├── .git.go ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE.txt ├── README.md ├── THANKS.md ├── arch ├── .gitignore └── arch.go ├── base64 ├── .gitignore ├── base64.go └── base64_test.go ├── basename ├── .gitignore ├── basename.go └── basename_test.go ├── build.bash ├── cal ├── .gitignore └── cal.go ├── cat ├── .gitignore ├── cat.go ├── cat_test.go ├── cat_unix.go ├── cat_windows.go └── test_files │ ├── coreutils_man_en.txt │ ├── dict_en.txt │ ├── file_list.txt │ ├── lang_ru.txt │ └── spaces_en.txt ├── chcon ├── .gitignore └── chcon.go ├── chgrp ├── .gitignore └── chgrp.go ├── chmod ├── .gitignore └── chmod.go ├── chown ├── .gitignore ├── README.md ├── checksum ├── chown ├── chown.go ├── chown_core.go ├── chown_types.go ├── patch.sh └── patch101310044_20001.tar.bz2 ├── chroot ├── .gitignore └── chroot.go ├── cksum ├── .gitignore └── cksum.go ├── comm ├── .gitignore └── comm.go ├── coreutils.go ├── cp ├── .gitignore ├── cp.go ├── foo.txt └── idk.go ├── csplit ├── .gitignore ├── boyermoore.go ├── csplit.go ├── mmap.go ├── read.go └── test.txt ├── cut ├── .gitignore └── cut.go ├── date ├── .gitignore └── date.go ├── dd ├── .gitignore └── dd.go ├── df ├── .gitignore └── df.go ├── dir ├── .gitignore └── dir.go ├── dircolors ├── .gitignore └── dircolors.go ├── dirname ├── .gitignore └── dirname.go ├── du ├── .gitignore └── du.go ├── echo ├── .gitignore └── echo.go ├── editlicensedates.bash ├── env ├── .gitignore └── env.go ├── expand ├── .gitignore └── expand.go ├── expr ├── .gitignore └── expr.go ├── factor ├── .gitignore └── factor.go ├── false ├── .gitignore └── false.go ├── fmt ├── .gitignore └── fmt.go ├── fold ├── .gitignore └── fold.go ├── groups ├── .gitignore └── groups.go ├── head ├── .gitignore └── head.go ├── hostid ├── .gitignore └── hostid.go ├── id ├── .gitignore └── id.go ├── install ├── .gitignore └── install.go ├── join ├── .gitignore └── join.go ├── link ├── .gitignore └── link.go ├── ln ├── .gitignore └── ln.go ├── logname ├── .gitignore └── logname.go ├── ls ├── .gitignore └── ls.go ├── md5sum ├── .gitignore ├── checksum_common │ ├── calc_sum.go │ ├── check_sum.go │ ├── checksum_test.go │ ├── output.go │ └── testdata │ │ ├── aad33efasdf.txt │ │ ├── checksum.md5 │ │ ├── checksum.sha1 │ │ ├── checksum.sha224 │ │ ├── checksum.sha256 │ │ ├── checksum.sha384 │ │ ├── checksum.sha512 │ │ ├── d333dasdf3.txt │ │ └── rgsdfsdfewerwf.txt └── md5sum.go ├── mkdir ├── .gitignore └── mkdir.go ├── mkfifo ├── .gitignore └── mkfifo.go ├── mknod ├── .gitignore └── mknod.go ├── mktemp ├── .gitignore └── mktemp.go ├── mv ├── .gitignore └── mv.go ├── nice ├── .gitignore └── nice.go ├── nl ├── .gitignore └── nl.go ├── nohup ├── .gitignore └── nohup.go ├── nproc ├── .gitignore └── nproc.go ├── numfmt ├── .gitignore └── numfmt.go ├── od ├── .gitignore └── od.go ├── paste ├── .gitignore └── paste.go ├── pathchk ├── .gitignore └── pathchk.go ├── pinky ├── .gitignore └── pinky.go ├── pr ├── .gitignore └── pr.go ├── printenv ├── .gitignore └── printenv.go ├── printf ├── .gitignore └── printf.go ├── ptx ├── .gitignore └── ptx.go ├── pwd ├── .gitignore └── pwd.go ├── readlink ├── .gitignore └── readlink.go ├── realpath ├── .gitignore └── realpath.go ├── rm ├── .gitignore ├── cmd.go ├── internal │ └── sys │ │ ├── sys_unix.go │ │ └── sys_windows.go └── rm.go ├── rmdir ├── .gitignore └── rmdir.go ├── runcon ├── .gitignore └── runcon.go ├── seq ├── .gitignore └── seq.go ├── sha1sum ├── .gitignore └── sha1sum.go ├── sha224sum ├── .gitignore └── sha224sum.go ├── sha256sum ├── .gitignore └── sha256sum.go ├── sha384sum ├── .gitignore └── sha384sum.go ├── sha512sum ├── .gitignore └── sha512sum.go ├── shred ├── .gitignore └── shred.go ├── shuf ├── .gitignore └── shuf.go ├── sleep ├── .gitignore └── sleep.go ├── sort ├── .gitignore └── sort.go ├── split ├── .gitignore └── split.go ├── stat ├── .gitignore └── stat.go ├── stdbuf ├── .gitignore └── stdbuf.go ├── stty ├── .gitignore └── stty.go ├── sum ├── .gitignore └── sum.go ├── sync ├── .gitignore ├── sync_linux.go └── sync_windows.go ├── tac ├── .gitignore └── tac.go ├── tail ├── .gitignore └── tail.go ├── tee ├── .gitignore └── tee.go ├── test ├── .gitignore └── test.go ├── timeout ├── .gitignore └── timeout.go ├── touch ├── .gitignore └── touch.go ├── tr ├── .gitignore └── tr.go ├── true ├── .gitignore └── true.go ├── truncate ├── .gitignore └── truncate.go ├── tsort ├── .gitignore ├── tsort.go └── tsort_test.go ├── tty ├── .gitignore └── tty.go ├── uname ├── .gitignore ├── README.md ├── generate.go ├── host_os.go ├── host_os_darwin.go ├── host_os_dragonfly.go ├── host_os_freebsd.go ├── host_os_linux.go ├── host_os_netbsd.go ├── host_os_openbsd.go ├── host_os_plan9.go ├── host_os_solaris.go ├── host_os_windows.go ├── ostypes.go ├── uname.go ├── uname_freebsd.go ├── uname_linux.go └── uname_windows.go ├── unexpand ├── .gitignore └── unexpand.go ├── uniq ├── .gitignore └── uniq.go ├── unlink ├── .gitignore └── unlink.go ├── uptime ├── .gitignore ├── uptime.go ├── uptime_freebsd.go └── uptime_linux.go ├── users ├── .gitignore └── users.go ├── vdir ├── .gitignore └── vdir.go ├── wc ├── _testdata │ ├── coreutils_man_en.txt │ ├── dict_en.txt │ ├── file_list.txt │ ├── lang_ru.txt │ └── spaces_en.txt ├── cmd.go ├── internal │ └── sys │ │ ├── fadv.go │ │ └── fadv_unix.go ├── wc.go └── wc_test.go ├── who ├── .gitignore └── who.go ├── whoami ├── .gitignore ├── whoami ├── whoami.go ├── whoami_test.go ├── whoami_unix.go └── whoami_windows.go ├── xxd ├── xxd.go └── xxd_test.go └── yes └── yes.go /.git.go: -------------------------------------------------------------------------------- 1 | package main -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | # Folders 6 | _obj 7 | _test 8 | # Architecture specific extensions/prefixes 9 | *.[568vq] 10 | [568vq].out 11 | *.cgo1.go 12 | *.cgo2.c 13 | _cgo_defun.c 14 | _cgo_gotypes.go 15 | _cgo_export.* 16 | _testmain.go 17 | *.exe 18 | *.test 19 | *.prof 20 | 21 | # Testing 22 | /testing/ 23 | 24 | # etc 25 | lst 26 | .c # because I test in C 27 | .out # same 28 | .tags 29 | 30 | # binary 31 | go-coreutils 32 | 33 | coreutils 34 | glibc 35 | .tags 36 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Goals: 4 | 5 | - Cross platform (on all platforms Go offically supports) 6 | - Fully implements GNU's coreutils (drop-in replacement) 7 | - Idiomatic Go 8 | - As fast as or faster than GNU's coreutils 9 | 10 | ## Tips 11 | 12 | - clone https://www.github.com/coreutils/coreutils and work side-by-side 13 | - get familiar with https://www.github.com/coreutils/gnulib 14 | - get familiar with https://www.github.com/EricLagergren/go-gnulib 15 | 16 | ## Licensing 17 | 18 | - All future changes will be licensed under GPLv3 or later. 19 | - If you edit a file append your name under the previous contributor(s). -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Go coreutils 2 | 3 | [![forthebadge](http://forthebadge.com/images/badges/made-with-crayons.svg)](http://forthebadge.com) 4 | [![forthebadge](http://forthebadge.com/images/badges/as-seen-on-tv.svg)](http://forthebadge.com) 5 | 6 | This is a port of GNU's coreutils (http://www.gnu.org/software/coreutils/) 7 | that aims to be a drop-in, cross-platform replacement. 8 | 9 | **It's currently under development.** 10 | 11 | Because it imports from `github.com/EricLagergren/go-gnulib`, and I'm constantly 12 | refactoring, parts could break from day-to-day. 13 | 14 | I'd recommend running `go get -u ...` before you file a bug report! 15 | 16 | *Pull requests are more than welcome.* 17 | 18 | Also, see https://www.github.com/EricLagergren/go-gnulib for a similar project that this project depends on. 19 | 20 | ### Completed: 21 | 22 | * 100% Completion 23 | * 15/100 24 | * Partial Completion 25 | * 2/100 26 | 27 | | Utility | Completeness | Cross Platform | Need Refactor| 28 | |:--------|:---------------|:--------------------|:-------------| 29 | | cat | 100% | Yes (Unix/Windows) | No | 30 | | chown | 0% (* see note #1) | No | Yes (-R) | 31 | | env | 100% | Yes (Unix/Windows) | No | 32 | | false | 100% | Yes (Unix/Windows) | No | 33 | | logname | 100% | No | No | 34 | | pwd | 100% | Yes (Unknown) | No | 35 | | sync | 100% | Yes (Unix/Windows) | No | 36 | | true | 100% | Yes (Unix/Windows) | No | 37 | | tsort | 100% | Yes (Unix/Windows) | No | 38 | | tty | 100% | Yes (Unix/Windows) | No | 39 | | uname | 100% | No | No | 40 | | uptime | 90% | Yes (Unix/Windows, no FreeBSD) | No | 41 | | users | 100% | No | No | 42 | | wc | 100% | Yes (Unix/Windows) | No | 43 | | whoami | 100% | Yes (Unix/Windows | No | 44 | | xxd | 100% | Yes (Unix/Windows) | No | 45 | | yes | 100% | Yes (Unix/Windows) | No | 46 | 47 | * chown note: Currently refactoring from the ground-up. 48 | 49 | **Side notes:** 50 | - Unix *should* include OS X unless otherwise specified. 51 | - Gofmt means it needs its styling changes (e.g. variable names, formatting, etc.) 52 | - Idiomatic means it needs to be changed to more idiomatic Go 53 | - Windows coverage will increase when I get a Windows laptop 54 | 55 | ### Information: 56 | 57 | #### Performance: 58 | 59 | Obviously there's some things Go can do better (parallelism and concurrency), 60 | but for the most part these tools should have nearly the same speed, 61 | with Go being slightly slower. 62 | 63 | ``` 64 | eric@archbox $ time ./wc_go -lwmc one_gigabyte_file.txt 65 | 32386258 146084896 1182425560 1183778772 one_gigabyte_file.txt 66 | 67 | real 0m25.206s 68 | user 0m24.900s 69 | sys 0m0.313s 70 | eric@archbox $ time wc_c -lwmc one_gigabyte_file.txt 71 | 32386258 146084896 1182425560 1183778772 one_gigabyte_file.txt 72 | 73 | real 0m22.841s 74 | user 0m22.570s 75 | sys 0m0.257s 76 | ``` 77 | 78 | #### Behavior: 79 | 80 | These utilities should be nearly identical to GNU's coreutils. 81 | 82 | Since parsing the output of shell commands isn't uncommon (even if 83 | it *is* bad behavior), most of the commands should have output that 84 | is nearly identical to the original GNU commands. 85 | 86 | Do note that sometimes the results could differ a little for select commands. 87 | 88 | For example, GNU's `wc` utility relies on the current locale to determine 89 | whether it should parse multi-byte characters or not. 90 | 91 | The Go version, on the other hand, uses the `unicode/utf8` package 92 | which natively detects multi-byte sequences. The trade-off is this: the 93 | Go version is technically more correct, while the C version is faster. 94 | 95 | Our implementation of `xxd` is actually much faster than the native `xxd` 96 | implementation found on most *nix machines -- try it out! 97 | 98 | ### REQUIRES: 99 | 100 | (Depends on platform and command...) 101 | - go get github.com/EricLagergren/ostypes 102 | - go get golang.org/x/sys/unix 103 | - go get github.com/EricLagergren/go-gnulib/ttyname 104 | - go get github.com/EricLagergren/go-gnulib/sysinfo 105 | - go get github.com/EricLagergren/go-gnulib/posix 106 | - go get github.com/EricLagergren/go-gnulib/general 107 | - go get github.com/EricLagergren/go-gnulib/login 108 | 109 | ### LICENSE: 110 | 111 | ``` 112 | Copyright (C) 2014-2016 Eric Lagergren 113 | 114 | This program is free software: you can redistribute it and/or modify 115 | it under the terms of the GNU General Public License as published by 116 | the Free Software Foundation, either version 3 of the License, or 117 | (at your option) any later version. 118 | 119 | This program is distributed in the hope that it will be useful, 120 | but WITHOUT ANY WARRANTY; without even the implied warranty of 121 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 122 | GNU General Public License for more details. 123 | 124 | You should have received a copy of the GNU General Public License 125 | along with this program. If not, see . 126 | ``` 127 | 128 | #### License subnotes: 129 | It (as a whole) is licensed under the GPLv3 because it's mostly a 130 | transliteration of GNU's coreutils, which are licensed under the GPLv3. 131 | 132 | However, certain parts have their own licenses (e.g., `xxd` is public domain). 133 | -------------------------------------------------------------------------------- /THANKS.md: -------------------------------------------------------------------------------- 1 | # Thanks 2 | 3 | Thanks to... 4 | 5 | - gonix contributors 6 | - vanhalt 7 | - iamthemuffinman 8 | - mattn -------------------------------------------------------------------------------- /arch/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/arch/.gitignore -------------------------------------------------------------------------------- /arch/arch.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /base64/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/base64/.gitignore -------------------------------------------------------------------------------- /base64/base64.go: -------------------------------------------------------------------------------- 1 | /* 2 | This program is free software: you can redistribute it and/or modify 3 | it under the terms of the GNU General Public License version 3 as 4 | published by the Free Software Foundation. 5 | 6 | This program is distributed in the hope that it will be useful, 7 | but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | GNU General Public License for more details. 10 | 11 | You should have received a copy of the GNU General Public License 12 | along with this program. If not, see . 13 | */ 14 | 15 | package main 16 | 17 | import ( 18 | "encoding/base64" 19 | "fmt" 20 | "io" 21 | "io/ioutil" 22 | "log" 23 | "os" 24 | "unicode" 25 | 26 | flag "github.com/ogier/pflag" 27 | ) 28 | 29 | const ( 30 | Help = ` 31 | Usage: base64 [OPTION]... [FILE] 32 | Base64 encode or decode FILE, or standard input, to standard output. 33 | 34 | Mandatory arguments to long options are mandatory for short options too. 35 | -d, --decode decode data 36 | -i, --ignore-garbage when decoding, ignore non-alphabet characters 37 | -w, --wrap=COLS wrap encoded lines after COLS character (default 76). 38 | Use 0 to disable line wrapping 39 | 40 | --help display this help and exit 41 | --version output version information and exit 42 | 43 | With no FILE, or when FILE is -, read standard input. 44 | 45 | The data are encoded as described for the base64 alphabet in RFC 3548. 46 | When decoding, the input may contain newlines in addition to the bytes of 47 | the formal base64 alphabet. Use --ignore-garbage to attempt to recover 48 | from any other non-alphabet bytes in the encoded stream. 49 | 50 | ` 51 | Version = ` 52 | base64 (Go coreutils) 0.1 53 | Copyright (C) 2015 Robert Deusser 54 | License GPLv3+: GNU GPL version 3 or later . 55 | This is free software: you are free to change and redistribute it. 56 | There is NO WARRANTY, to the extent permitted by law. 57 | 58 | ` 59 | ) 60 | 61 | var ( 62 | decode = flag.BoolP("decode", "d", false, "") 63 | ignore = flag.BoolP("ignore-garbage", "i", false, "") 64 | wrap = flag.IntP("wrap", "w", 76, "") 65 | version = flag.BoolP("version", "v", false, "") 66 | ) 67 | 68 | func base64Encode(src []byte) []byte { 69 | return []byte(base64.StdEncoding.EncodeToString(src)) 70 | } 71 | 72 | func base64Decode(src []byte) ([]byte, error) { 73 | return base64.StdEncoding.DecodeString(string(src)) 74 | } 75 | 76 | func readData(reader io.Reader) ([]byte, error) { 77 | return ioutil.ReadAll(reader) 78 | } 79 | 80 | func isAlpha(ch byte) bool { 81 | return unicode.IsLetter(rune(ch)) 82 | } 83 | 84 | func readAndHandle(reader io.Reader, decode *bool, ignore *bool, wrap *int) { 85 | src, err := readData(reader) 86 | if err != nil { 87 | log.Fatal(err) 88 | } 89 | var toHandle []byte 90 | if *ignore { 91 | //It seems that the effect of "base64 -i" in *nix 92 | //is not filter the non-alphabet charater. 93 | //This flag cannot work as the original *nix command flag. 94 | for i := 0; i < len(src); i++ { 95 | if isAlpha(src[i]) { 96 | toHandle = append(toHandle, src[i]) 97 | } 98 | } 99 | } else { 100 | toHandle = src 101 | } 102 | if *decode { 103 | decoded, err := base64Decode(toHandle) 104 | if err != nil { 105 | log.Fatal(err) 106 | } 107 | fmt.Printf("%s", string(decoded)) 108 | } else { 109 | encoded := base64Encode(toHandle) 110 | wrapPrint(encoded, *wrap) 111 | } 112 | } 113 | 114 | func wrapPrint(output []byte, wrap int) { 115 | if wrap == 0 { 116 | fmt.Printf("%s\n", string(output)) 117 | return 118 | } 119 | 120 | length := len(output) 121 | if length <= wrap { 122 | fmt.Printf("%s\n", string(output)) 123 | return 124 | } 125 | 126 | index, end := 0, 0 127 | for index < length { 128 | end += wrap 129 | if end > length { 130 | end = length 131 | } 132 | fmt.Printf("%s\n", string(output[index:end])) 133 | index += wrap 134 | } 135 | } 136 | 137 | func main() { 138 | flag.Usage = func() { 139 | fmt.Fprintf(os.Stderr, "%s", Help) 140 | os.Exit(1) 141 | } 142 | flag.Parse() 143 | 144 | switch { 145 | case *version: 146 | fmt.Fprintf(os.Stdout, "%s", Version) 147 | os.Exit(0) 148 | case *wrap < 0: 149 | log.Fatalf("invalid wrap size: %d", *wrap) 150 | default: 151 | if len(flag.Args()) == 0 { 152 | readAndHandle(os.Stdin, decode, ignore, wrap) 153 | } else { 154 | for i := 0; i < len(flag.Args()); i++ { 155 | file, err := os.Open(flag.Args()[i]) 156 | if err != nil { 157 | log.Fatal(err) 158 | } 159 | readAndHandle(file, decode, ignore, wrap) 160 | } 161 | } 162 | } 163 | 164 | } 165 | -------------------------------------------------------------------------------- /base64/base64_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "testing" 6 | ) 7 | 8 | func TestBase64Decode(t *testing.T) { 9 | 10 | cases := []struct { 11 | in, want string 12 | }{ 13 | {"aGVsbG8gd29ybGQK", "hello world\n"}, 14 | {"cGxlYXNlLCBkZWNvZGUgbWUK", "please, decode me\n"}, 15 | } 16 | 17 | for _, c := range cases { 18 | 19 | decodedBytes, err := base64Decode([]byte(c.in)) 20 | if err != nil { 21 | log.Fatal(err) 22 | } 23 | got := string(decodedBytes) 24 | 25 | if got != c.want { 26 | t.Errorf("base64 (%q) == %q, want %q", c.in, got, c.want) 27 | } 28 | } 29 | } 30 | 31 | func TestBase64Encode(t *testing.T) { 32 | cases := []struct { 33 | in, want string 34 | }{ 35 | {"hello world\n", "aGVsbG8gd29ybGQK"}, 36 | {"please, decode me\n", "cGxlYXNlLCBkZWNvZGUgbWUK"}, 37 | } 38 | 39 | for _, c := range cases { 40 | 41 | encodedBytes := base64Encode([]byte(c.in)) 42 | got := string(encodedBytes) 43 | 44 | if got != c.want { 45 | t.Errorf("base64 (%q) == %q, want %q", c.in, got, c.want) 46 | } 47 | } 48 | } 49 | 50 | func main() {} 51 | -------------------------------------------------------------------------------- /basename/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/basename/.gitignore -------------------------------------------------------------------------------- /basename/basename.go: -------------------------------------------------------------------------------- 1 | /* 2 | This program is free software: you can redistribute it and/or modify 3 | it under the terms of the GNU General Public License version 3 as 4 | published by the Free Software Foundation. 5 | 6 | This program is distributed in the hope that it will be useful, 7 | but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | GNU General Public License for more details. 10 | 11 | You should have received a copy of the GNU General Public License 12 | along with this program. If not, see . 13 | */ 14 | 15 | package main 16 | 17 | import ( 18 | "fmt" 19 | "os" 20 | "path/filepath" 21 | "strings" 22 | 23 | flag "github.com/ogier/pflag" 24 | ) 25 | 26 | const ( 27 | Help = ` 28 | Usage: basename NAME [SUFFIX] 29 | or: basename OPTION... NAME... 30 | Print NAME with any leading directory components removed. 31 | If specified, also remove a trailing SUFFIX. 32 | 33 | Mandatory arguments to long options are mandatory for short options too. 34 | -a, --multiple support multiple arguments and treat each as a NAME 35 | -s, --suffix=SUFFIX remove a trailing SUFFIX; implies -a 36 | -z, --zero end each output line with NUL, not newline 37 | --help display this help and exit 38 | --version output version information and exit 39 | 40 | Examples: 41 | basename /usr/bin/sort -> "sort" 42 | basename include/stdio.h .h -> "stdio" 43 | basename -s .h include/stdio.h -> "stdio" 44 | basename -a any/str1 any/str2 -> "str1" followed by "str2" 45 | 46 | ` 47 | Version = ` 48 | basename (Go coreutils) 0.1 49 | Copyright (C) 2015 Robert Deusser 50 | License GPLv3+: GNU GPL version 3 or later . 51 | This is free software: you are free to change and redistribute it. 52 | There is NO WARRANTY, to the extent permitted by law. 53 | 54 | ` 55 | ) 56 | 57 | var ( 58 | multiple = flag.BoolP("multiple", "a", false, "") 59 | suffix = flag.StringP("suffix", "s", "", "") 60 | zero = flag.BoolP("zero", "z", false, "") 61 | version = flag.BoolP("version", "v", false, "") 62 | ) 63 | 64 | func baseName(path, suffix string, null bool) string { 65 | dir := filepath.Base(path) 66 | 67 | if strings.HasSuffix(dir, suffix) { 68 | dir = dir[:len(dir)-len(suffix)] 69 | } 70 | 71 | if !null { 72 | dir += "\n" 73 | } 74 | 75 | return dir 76 | } 77 | 78 | func main() { 79 | flag.Usage = func() { 80 | fmt.Fprintf(os.Stderr, "%s", Help) 81 | os.Exit(1) 82 | } 83 | flag.Parse() 84 | 85 | switch { 86 | case *version: 87 | fmt.Fprintf(os.Stdout, "%s", Version) 88 | os.Exit(0) 89 | case *multiple: 90 | for _, v := range flag.Args() { 91 | dir := baseName(v, *suffix, *zero) 92 | fmt.Print(dir) 93 | } 94 | case *suffix != "": 95 | // Implies --multiple/-a 96 | for _, v := range flag.Args() { 97 | dir := baseName(v, *suffix, *zero) 98 | fmt.Print(dir) 99 | } 100 | default: 101 | dir := baseName(flag.Args()[0], *suffix, *zero) 102 | fmt.Print(dir) 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /basename/basename_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "log" 6 | "os/exec" 7 | "testing" 8 | ) 9 | 10 | func TestPerformBasename(t *testing.T) { 11 | 12 | cases := []struct { 13 | in []string 14 | want string 15 | }{ 16 | {[]string{"/usr/bin/sort", ""}, "sort\n"}, 17 | {[]string{"include/stdio.h", ""}, "stdio.h\n"}, 18 | {[]string{"include/stdio.h", ".h"}, "stdio\n"}, 19 | } 20 | 21 | for _, c := range cases { 22 | got := performBasename(c.in[0], c.in[1], false) 23 | 24 | if got != c.want { 25 | t.Errorf("basename (%q) == %q, want %q", c.in, got, c.want) 26 | } 27 | } 28 | } 29 | 30 | func TestBasename(t *testing.T) { 31 | 32 | cases := []struct { 33 | in []string 34 | want string 35 | }{ 36 | {[]string{"-a", "any/str1 any/str2"}, "str1\nstr2\n"}, 37 | {[]string{"-a", "any/str1 any/str2"}, "str1\nstr2\n"}, 38 | {[]string{"-a", "/a//b //a/b"}, "b\nb\n"}, 39 | {[]string{"-s", ".h", "include/stdio.h"}, "stdio\n"}, 40 | {[]string{"-s", ".h", "-a", "any/lib.h any/lib2.h"}, "lib\nlib2\n"}, 41 | {[]string{"-z", "any/str1"}, "str1"}, 42 | {[]string{"-z", "-a", "any/str1 any/str2"}, "str1str2"}, 43 | {[]string{"-z", "-s", ".h", "-a", "any/lib.h any/lib2.h"}, "liblib2"}, 44 | } 45 | 46 | for _, c := range cases { 47 | var out bytes.Buffer 48 | cmd := exec.Command("./basename", c.in...) 49 | cmd.Stdout = &out 50 | err := cmd.Run() 51 | if err != nil { 52 | log.Fatal(err) 53 | } 54 | 55 | got := out.String() 56 | if got != c.want { 57 | t.Errorf("basename (%q) == %q, want %q", c.in, got, c.want) 58 | } 59 | } 60 | 61 | } 62 | 63 | func main() {} 64 | -------------------------------------------------------------------------------- /build.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (c) 2015 Eric Lagergren 4 | # This is public domain. 5 | 6 | # No set -e because we expect some installs to fail. 7 | set -uo pipefail 8 | 9 | : > build.log 10 | 11 | for d in *; do 12 | if [ -d "${d}" ]; then 13 | 14 | cd "${d}" 15 | go generate >> ../build.log 2>&1 16 | go install -a -v -x -gcflags '-m' >> ../build.log 2>&1 17 | cd ../ 18 | 19 | fi 20 | done -------------------------------------------------------------------------------- /cal/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /cal/cal.go: -------------------------------------------------------------------------------- 1 | /* 2 | This program is free software: you can redistribute it and/or modify 3 | it under the terms of the GNU General Public License version 3 as 4 | published by the Free Software Foundation. 5 | 6 | This program is distributed in the hope that it will be useful, 7 | but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | GNU General Public License for more details. 10 | 11 | You should have received a copy of the GNU General Public License 12 | along with this program. If not, see . 13 | */ 14 | 15 | package main 16 | 17 | import "fmt" 18 | import flag "github.com/ogier/pflag" 19 | import "strconv" 20 | import "log" 21 | import "time" 22 | 23 | func leapyear(year int) int { 24 | //Return 1 if leapyear, 0 if not 25 | if year%4 == 0 && (year%100 != 0 || year%400 == 0) { 26 | return 1 27 | } 28 | return 0 29 | } 30 | 31 | func monthlen(month int, year int) int { 32 | //Return length of month in days 33 | switch month { 34 | case 1: 35 | return 31 36 | case 2: 37 | return 28 + leapyear(year) 38 | case 3: 39 | return 31 40 | case 4: 41 | return 30 42 | case 5: 43 | return 31 44 | case 6: 45 | return 30 46 | case 7: 47 | return 31 48 | case 8: 49 | return 31 50 | case 9: 51 | return 30 52 | case 10: 53 | return 31 54 | case 11: 55 | return 30 56 | case 12: 57 | return 31 58 | } 59 | return 0 60 | } 61 | 62 | func calendar(month int, year int) { 63 | weekday := int(time.Date(year, time.Month(month), 1, 0, 0, 0, 0, time.UTC).Weekday()) 64 | fmt.Printf("%s %d\n", time.Month(month).String(), year) 65 | fmt.Printf("Su Mo Tu We Th Fr Sa\n") 66 | for i := 0; i < weekday; i++ { 67 | fmt.Printf(" ") 68 | } 69 | for day := 1; day <= monthlen(month, year); day++ { 70 | if weekday == 6 { 71 | fmt.Printf("%2d\n", day) 72 | weekday = 0 73 | } else { 74 | fmt.Printf("%2d ", day) 75 | weekday++ 76 | } 77 | } 78 | if weekday != 6 { 79 | fmt.Printf("\n") 80 | } 81 | } 82 | 83 | func main() { 84 | flag.Parse() 85 | if len(flag.Args()) == 0 { 86 | year := int(time.Now().Year()) 87 | month := int(time.Now().Month()) 88 | calendar(month, year) 89 | } else if len(flag.Args()) == 1 { 90 | year, err := strconv.Atoi(flag.Arg(0)) 91 | if err != nil { 92 | log.Fatal(err) 93 | } 94 | for month := 1; month <= 12; month++ { 95 | calendar(month, year) 96 | fmt.Println() 97 | } 98 | } else if len(flag.Args()) == 2 { 99 | month, err := strconv.Atoi(flag.Arg(0)) 100 | if err != nil { 101 | log.Fatal(err) 102 | } 103 | year, err := strconv.Atoi(flag.Arg(1)) 104 | if err != nil { 105 | log.Fatal(err) 106 | } 107 | calendar(month, year) 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /cat/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/cat/.gitignore -------------------------------------------------------------------------------- /cat/cat_test.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | package main 4 | 5 | import ( 6 | "bufio" 7 | "bytes" 8 | "io" 9 | "os" 10 | "os/exec" 11 | "syscall" 12 | "testing" 13 | ) 14 | 15 | var flist = [...]string{ 16 | "test_files/lang_ru.txt", 17 | "test_files/dict_en.txt", 18 | "test_files/spaces_en.txt", 19 | "test_files/coreutils_man_en.txt", 20 | } 21 | 22 | var buf bytes.Buffer 23 | 24 | func TestCat(t *testing.T) { 25 | 26 | showNonPrinting = true 27 | *nonPrint = true 28 | *npEnds = true 29 | *npTabs = true 30 | 31 | for i, f := range flist { 32 | 33 | // set up our capture of stdout 34 | stdout := os.Stdout 35 | r, w, err := os.Pipe() 36 | if err != nil { 37 | t.Fatal(err) 38 | } 39 | os.Stdout = w 40 | 41 | file, err := os.Open(f) 42 | if err != nil { 43 | t.Error(err) 44 | } 45 | 46 | inStat, err := file.Stat() 47 | if err != nil { 48 | t.Error(err) 49 | } 50 | if inStat.IsDir() { 51 | t.Errorf("%s: is a directory\n", file.Name()) 52 | } 53 | 54 | inBsize := int(inStat.Sys().(*syscall.Stat_t).Blksize) 55 | size := 20 + inBsize*4 56 | outBuf := bufio.NewWriterSize(os.Stdout, size) 57 | inBuf := make([]byte, inBsize+1) 58 | 59 | cat(file, inBuf, outBuf) 60 | file.Close() 61 | 62 | // capture the stdout 63 | outC := make(chan string) 64 | go func() { 65 | var b bytes.Buffer 66 | _, err := io.Copy(&b, r) 67 | 68 | r.Close() 69 | if err != nil { 70 | t.Fatal(err) 71 | } 72 | outC <- b.String() 73 | }() 74 | 75 | // now get stdout of native cat 76 | cat := exec.Command("cat", "-A", flist[i]) 77 | 78 | b, err := cat.Output() 79 | if err != nil { 80 | t.Fatal(err) 81 | } 82 | buf.Write(b) 83 | 84 | // stop capturing of stdout 85 | w.Close() 86 | os.Stdout = stdout 87 | out := <-outC 88 | 89 | // check strings 90 | if out != buf.String() { 91 | t.Fatalf("Got:\n%s\n\nExpected:\n%s\n", out, buf.String()) 92 | } 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /cat/cat_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014-2016 Eric Lagergren 2 | // Use of this source code is governed by the GPL v3 or later. 3 | 4 | package main 5 | 6 | import ( 7 | "bufio" 8 | "log" 9 | "os" 10 | 11 | "github.com/EricLagergren/go-coreutils/internal/flag" 12 | 13 | "golang.org/x/sys/unix" 14 | ) 15 | 16 | func bsize(info os.FileInfo) int { 17 | stat, ok := info.Sys().(*unix.Stat_t) 18 | if !ok { 19 | log.Fatalln("cat: (bug) inf.Sys().(*unix.Stat_t) is false") 20 | } 21 | // (Taken from ioblksize.h) 22 | // bufSize is determined by: 23 | // 24 | // for i in $(seq 0 10); do 25 | // bs=$((1024*2**$i)) 26 | // printf "%7s=" $bs 27 | // timeout --foreground -sINT 2 \ 28 | // dd bs=$bs if=/dev/zero of=/dev/null 2>&1 \ 29 | // | sed -n 's/.* \([0-9.]* [GM]B\/s\)/\1/p' 30 | // done 31 | const bufSize = 128 * 1024 32 | return max(bufSize, int(stat.Blksize)) 33 | } 34 | 35 | func main() { 36 | var ok int // return status 37 | 38 | outStat, err := os.Stdout.Stat() 39 | if err != nil { 40 | fatal.Fatalln(err) 41 | } 42 | outReg := outStat.Mode().IsRegular() 43 | outBsize := bsize(outStat) 44 | 45 | // catch (./cat) < /etc/group 46 | args := flag.Args() 47 | if flag.NArg() == 0 { 48 | args = []string{"-"} 49 | } 50 | 51 | var file *os.File 52 | for _, arg := range args { 53 | file = os.Stdin 54 | if arg != "-" { 55 | file, err = os.Open(arg) 56 | if err != nil { 57 | fatal.Fatalln(err) 58 | } 59 | } 60 | 61 | inStat, err := file.Stat() 62 | if err != nil { 63 | fatal.Fatalln(err) 64 | } 65 | if inStat.IsDir() { 66 | fatal.Printf("%s: is a directory\n", file.Name()) 67 | } 68 | inBsize := bsize(inStat) 69 | 70 | // prefetch! prefetch! prefetch! 71 | unix.Fadvise(int(file.Fd()), 0, 0, unix.FADV_SEQUENTIAL) 72 | 73 | // Make sure we're not catting a file to itself, 74 | // provided it's a regular file. Catting a non-reg 75 | // file to itself is cool. 76 | // e.g. cat file > file 77 | if outReg && os.SameFile(outStat, inStat) { 78 | if n, _ := file.Seek(0, os.SEEK_CUR); n < inStat.Size() { 79 | fatal.Fatalf("%s: input file is output file\n", file.Name()) 80 | } 81 | } 82 | 83 | pageSize := os.Getpagesize() 84 | if simple { 85 | // Select larger block size 86 | size := max(inBsize, outBsize) 87 | outBuf := bufio.NewWriterSize(os.Stdout, size+pageSize-1) 88 | ok ^= simpleCat(file, outBuf) 89 | 90 | // Flush because we don't have a chance to in 91 | // simpleCat() because we use io.Copy() 92 | outBuf.Flush() 93 | } else { 94 | // If you want to know why, exactly, I chose 95 | // outBsize -1 + inBsize*4 + 20, read GNU's cat 96 | // source code. The tl;dr is the 20 is the counter 97 | // buffer, inBsize*4 is from potentially prepending 98 | // the control characters (M-^), and outBsize is 99 | // due to new tests for newlines. 100 | size := outBsize - 1 + inBsize*4 + 20 101 | outBuf := bufio.NewWriterSize(os.Stdout, size) 102 | inBuf := make([]byte, inBsize+pageSize-1) 103 | ok ^= cat(file, inBuf, outBuf) 104 | } 105 | 106 | file.Close() 107 | } 108 | 109 | os.Exit(ok) 110 | } 111 | -------------------------------------------------------------------------------- /cat/cat_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014-2016 Eric Lagergren 2 | // Use of this source code is governed by the GPL v3 or later. 3 | 4 | package main 5 | 6 | import ( 7 | "bufio" 8 | "os" 9 | "syscall" 10 | 11 | k32 "github.com/EricLagergren/go-gnulib/windows" 12 | flag "github.com/ogier/pflag" 13 | ) 14 | 15 | func main() { 16 | var ok int // return status 17 | 18 | outHandle := syscall.Handle(os.Stdout.Fd()) 19 | outType, err := syscall.GetFileType(outHandle) 20 | if err != nil { 21 | fatal.Fatalln(err) 22 | } 23 | outBsize := 4096 24 | 25 | // catch (./cat) < /etc/group 26 | var args []string 27 | if flag.NArg() == 0 { 28 | args = []string{"-"} 29 | } else { 30 | args = flag.Args() 31 | } 32 | 33 | // the main loop 34 | var file *os.File 35 | for _, arg := range args { 36 | var inStat os.FileInfo 37 | 38 | if arg == "-" { 39 | file = os.Stdin 40 | } else { 41 | file, err = os.Open(arg) 42 | if err != nil { 43 | fatal.Fatalln(err) 44 | } 45 | 46 | inStat, err = file.Stat() 47 | if err != nil { 48 | fatal.Fatalln(err) 49 | } 50 | if inStat.IsDir() { 51 | fatal.Printf("%s: Is a directory\n", file.Name()) 52 | } 53 | } 54 | 55 | inHandle := syscall.Handle(file.Fd()) 56 | inBsize := 4096 57 | 58 | // See http://stackoverflow.com/q/29360969/2967113 59 | // for why this differs from the Unix versions. 60 | // 61 | // Make sure we're not catting a file to itself, 62 | // provided it's a regular file. Catting a non-reg 63 | // file to itself is cool, e.g. cat file > file 64 | if outType == syscall.FILE_TYPE_DISK { 65 | 66 | inPath := make([]byte, syscall.MAX_PATH) 67 | outPath := make([]byte, syscall.MAX_PATH) 68 | 69 | err = k32.GetFinalPathNameByHandleA(inHandle, inPath, 0) 70 | if err != nil { 71 | fatal.Fatalln(err) 72 | } 73 | 74 | err = k32.GetFinalPathNameByHandleA(outHandle, outPath, 0) 75 | if err != nil { 76 | fatal.Fatalln(err) 77 | } 78 | 79 | if string(inPath) == string(outPath) { 80 | if n, _ := file.Seek(0, os.SEEK_CUR); n < inStat.Size() { 81 | fatal.Fatalf("%s: input file is output file\n", file.Name()) 82 | } 83 | } 84 | } 85 | 86 | if simple { 87 | outBuf := bufio.NewWriterSize(os.Stdout, 4096) 88 | ok ^= simpleCat(file, outBuf) 89 | 90 | // Flush because we don't have a chance to in 91 | // simpleCat() because we use io.Copy() 92 | outBuf.Flush() 93 | } else { 94 | // If you want to know why, exactly, I chose 95 | // outBsize -1 + inBsize*4 + 20, read GNU's cat 96 | // source code. The tl;dr is the 20 is the counter 97 | // buffer, inBsize*4 is from potentially prepending 98 | // the control characters (M-^), and outBsize is 99 | // due to new tests for newlines. 100 | size := outBsize - 1 + inBsize*4 + 20 101 | outBuf := bufio.NewWriterSize(os.Stdout, size) 102 | inBuf := make([]byte, inBsize+1) 103 | ok ^= cat(file, inBuf, outBuf) 104 | } 105 | 106 | file.Close() 107 | } 108 | 109 | os.Exit(ok) 110 | } 111 | -------------------------------------------------------------------------------- /cat/test_files/coreutils_man_en.txt: -------------------------------------------------------------------------------- 1 | Next: sum invocation, Up: Summarizing files 2 | 3 | 6.1 wc: Print newline, word, and byte counts 4 | 5 | wc counts the number of bytes, characters, whitespace-separated words, and newlines in each given file, or standard input if none are given or for a file of ‘-’. Synopsis: 6 | 7 | wc [option]... [file]... 8 | wc prints one line of counts for each file, and if the file was given as an argument, it prints the file name following the counts. If more than one file is given, wc prints a final line containing the cumulative counts, with the file name total. The counts are printed in this order: newlines, words, characters, bytes, maximum line length. Each count is printed right-justified in a field with at least one space between fields so that the numbers and file names normally line up nicely in columns. The width of the count fields varies depending on the inputs, so you should not depend on a particular field width. However, as a GNU extension, if only one count is printed, it is guaranteed to be printed without leading spaces. 9 | 10 | By default, wc prints three counts: the newline, words, and byte counts. Options can specify that only certain counts be printed. Options do not undo others previously given, so 11 | 12 | wc --bytes --words 13 | prints both the byte counts and the word counts. 14 | 15 | With the --max-line-length option, wc prints the length of the longest line per file, and if there is more than one file it prints the maximum (not the sum) of those lengths. The line lengths here are measured in screen columns, according to the current locale and assuming tab positions in every 8th column. 16 | 17 | The program accepts the following options. Also see Common options. 18 | 19 | ‘-c’ 20 | ‘--bytes’ 21 | Print only the byte counts. 22 | ‘-m’ 23 | ‘--chars’ 24 | Print only the character counts. 25 | ‘-w’ 26 | ‘--words’ 27 | Print only the word counts. 28 | ‘-l’ 29 | ‘--lines’ 30 | Print only the newline counts. 31 | ‘-L’ 32 | ‘--max-line-length’ 33 | Print only the maximum line lengths. 34 | ‘--files0-from=file’ 35 | Disallow processing files named on the command line, and instead process those named in file file; each name being terminated by a zero byte (ASCII NUL). This is useful when the list of file names is so long that it may exceed a command line length limitation. In such cases, running wc via xargs is undesirable because it splits the list into pieces and makes wc print a total for each sublist rather than for the entire list. One way to produce a list of ASCII NUL terminated file names is with GNU find, using its -print0 predicate. If file is ‘-’ then the ASCII NUL terminated file names are read from standard input. 36 | For example, to find the length of the longest line in any .c or .h file in the current hierarchy, do this: 37 | 38 | find . -name '*.[ch]' -print0 | 39 | wc -L --files0-from=- | tail -n1 40 | An exit status of zero indicates success, and a nonzero value indicates failure. -------------------------------------------------------------------------------- /cat/test_files/file_list.txt: -------------------------------------------------------------------------------- 1 | ./test_files/file_list.txt./test_files/spaces_en.txt./test_files/dict_en.txt./test_files/lang_ru.txt./test_files/coreutils_man_en.txt -------------------------------------------------------------------------------- /cat/test_files/spaces_en.txt: -------------------------------------------------------------------------------- 1 | Hello, world! 2 | This is a test file to see if1 my wc utilit y 3 | 4 | is 5 | able 6 | 7 | to det 8 | ermine the correct counts for different fi 9 | les. 10 | -------------------------------------------------------------------------------- /chcon/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/chcon/.gitignore -------------------------------------------------------------------------------- /chcon/chcon.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /chgrp/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/chgrp/.gitignore -------------------------------------------------------------------------------- /chgrp/chgrp.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /chmod/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/chmod/.gitignore -------------------------------------------------------------------------------- /chmod/chmod.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /chown/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/chown/.gitignore -------------------------------------------------------------------------------- /chown/README.md: -------------------------------------------------------------------------------- 1 | **See https://codereview.appspot.com/101310044/ for more information about why 2 | we need to install a patch** 3 | 4 | ### IMPORTANT NOTES: 5 | 6 | - (1) `-R` could get stuck on looped symlinks (e.g. foo -> bar -> foo -> bar) 7 | 8 | ### PATCH NOTES: 9 | - (1) fixed `--from=` on 03 Dec, 2014 -------------------------------------------------------------------------------- /chown/checksum: -------------------------------------------------------------------------------- 1 | 8cb8c7de1776a5badf4f0070eb009363 patch101310044_20001.tar.bz2 -------------------------------------------------------------------------------- /chown/chown: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/chown/chown -------------------------------------------------------------------------------- /chown/chown.go: -------------------------------------------------------------------------------- 1 | /* 2 | Go chown -- change ownership of a file 3 | 4 | Copyright (c) 2014-2015 Eric Lagergren 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | /* 21 | Written by Eric Lagergren 22 | */ 23 | 24 | // BUG(eric): -R flag could get stuck in an infinite loop 25 | 26 | package main 27 | 28 | import ( 29 | "fmt" 30 | "os" 31 | 32 | flag "github.com/EricLagergren/pflag" 33 | ) 34 | 35 | const ( 36 | Help = "help" 37 | Version = "version" 38 | ) 39 | 40 | var ( 41 | recursive = flag.BoolP("recursive", "R", false, "") 42 | changes = flag.BoolP("changes", "c", false, "") 43 | dereference = flag.Bool("dereference", false, "") 44 | from = flag.Bool("from", false, "") 45 | noDereference = flag.BoolP("no-dereference", "h", false, "") 46 | noPreserveRoot = flag.Bool("no-preserve-root", false, "") 47 | quiet = flag.Bool("quiet", false, "") 48 | silent = flag.Bool("silent", false, "") 49 | reference = flag.Bool("reference", false, "") 50 | verbose = flag.BoolP("verbose", "v", false, "") 51 | 52 | version = flag.Bool("version", false, "") 53 | ) 54 | 55 | func main() { 56 | flag.Usage = func() { 57 | fmt.Fprintf(os.Stderr, "%s", Help) 58 | os.Exit(1) 59 | } 60 | flag.Parse() 61 | 62 | if *version { 63 | fmt.Printf("%s\n", Version) 64 | os.Exit(0) 65 | } 66 | 67 | // 1 if --dereference, 0 if --no-dereference, -1 if neither 68 | // has been specified. 69 | // deref := -1 70 | // bitFlags := 12 // todo 71 | } 72 | -------------------------------------------------------------------------------- /chown/chown_core.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "syscall" 7 | // "strconv" 8 | ) 9 | 10 | func newChownOption() *ChownOption { 11 | // Rest fall back to their zero-value. 12 | return &ChownOption{ 13 | verbosity: VOff, 14 | affectSymlinkReferent: true, 15 | } 16 | } 17 | 18 | // func gidToName(gid uint32) (string, error) { 19 | // id, err := user.LookupGroupId(strconv.FormatUint(uint64(gid), 10)) 20 | // if err != nil { 21 | // return "", err 22 | // } 23 | // return id.Name, nil 24 | // } 25 | 26 | // func uidToName(uid uint32) (string, error) { 27 | // id, err := user.LookupId(strconv.FormatUint(uint64(uid), 10)) 28 | // if err != nil { 29 | // return "", err 30 | // } 31 | // return id.Name, nil 32 | // } 33 | 34 | func UserGroupString(user, group string) string { 35 | var spec string 36 | if user != "" { 37 | if group != "" { 38 | spec = fmt.Sprintf("%s:%s", user, group) 39 | } else { 40 | spec = user 41 | } 42 | } else if group != "" { 43 | spec = group 44 | } 45 | return spec 46 | } 47 | 48 | func DescribeChange(file string, changed ChangeStatus, oldUser, oldGroup, user, group string) { 49 | 50 | if changed == CHNotApplied { 51 | fmt.Printf("neither symbolic link %q nor referent has been changed\n", file) 52 | return 53 | } 54 | 55 | spec := UserGroupString(user, group) 56 | var oldSpec string 57 | if user != "" { 58 | if group != "" { 59 | oldSpec = UserGroupString(oldUser, oldGroup) 60 | } else { 61 | oldSpec = UserGroupString(oldUser, "") 62 | } 63 | } else if group != "" { 64 | oldSpec = UserGroupString("", oldGroup) 65 | } else { 66 | oldSpec = UserGroupString("", "") 67 | } 68 | 69 | var format string 70 | switch changed { 71 | case CHSucceeded: 72 | if user != "" { 73 | format = "changed ownership of %q from %s to %s\n" 74 | } else if group != "" { 75 | format = "changed group of %q from %s to %s\n" 76 | } else { 77 | format = "no change to ownership of %s\n" 78 | } 79 | case CHFailed: 80 | if oldSpec != "" { 81 | if user != "" { 82 | format = "failed to change ownership of %q from %s to %s\n" 83 | } else if group != "" { 84 | format = "failed to change group of %q from %s to %s\n" 85 | } else { 86 | format = "failed to change ownership of %q\n" 87 | } 88 | } 89 | case CHNoChangeRequested: 90 | if user != "" { 91 | format = "ownership of %q retained as %s\n" 92 | } else if group != "" { 93 | format = "group of %q retained as %s\n" 94 | } else { 95 | format = "ownership of %q retained\n" 96 | } 97 | default: 98 | os.Exit(1) 99 | } 100 | 101 | fmt.Printf(format, file, oldSpec, spec) 102 | } 103 | 104 | func RestrictedChown(cwdFd int, file string, origStat os.FileInfo, uid, gid, reqUid, reqGid int) RCHStatus { 105 | 106 | status := RCOK 107 | openflags := syscall.O_NONBLOCK | syscall.O_NOCTTY 108 | 109 | if reqUid == -1 && reqGid == 1 { 110 | return RCDoOrdinaryChown 111 | } 112 | 113 | if !origStat.Mode().IsRegular() { 114 | if !origStat.Mode().IsDir() { 115 | return RCDoOrdinaryChown 116 | } 117 | openflags |= syscall.O_DIRECTORY 118 | } 119 | 120 | fd, err := syscall.Openat(cwdFd, file, syscall.O_RDONLY|openflags, 0) 121 | 122 | if !(0 <= fd || 123 | err == syscall.EACCES && 124 | origStat.Mode().IsRegular()) { 125 | 126 | if fd, err = syscall.Openat(cwdFd, file, syscall.O_WRONLY|openflags, 0); 0 > fd { 127 | 128 | if err == syscall.EACCES { 129 | return RCDoOrdinaryChown 130 | } 131 | return RCError 132 | } 133 | } 134 | 135 | var stat syscall.Stat_t 136 | if err := syscall.Fstat(fd, &stat); err != nil { 137 | status = RCError 138 | } else if !sameFile(origStat.Sys().(*syscall.Stat_t), &stat) { 139 | status = RCInodeChanged 140 | } else if reqUid == -1 || uint32(reqUid) == stat.Uid && 141 | (reqGid == -1 || uint32(reqGid) == stat.Gid) { 142 | if syscall.Fchown(fd, uid, gid) == nil { 143 | if syscall.Close(fd) == nil { 144 | return RCOK 145 | } 146 | return RCError 147 | } else { 148 | status = RCError 149 | } 150 | } 151 | 152 | return status 153 | } 154 | 155 | // Basically borrowed from os/stat_linux.go but there's no 156 | // other way to do it. 157 | func sameFile(st1, st2 *syscall.Stat_t) bool { 158 | return st1.Dev == st2.Dev && st1.Ino == st2.Ino 159 | } 160 | 161 | func ChangeFileOwner(uid, gid, reqUid, reqGid uint32, chopt ChownOption) bool { 162 | 163 | } 164 | -------------------------------------------------------------------------------- /chown/chown_types.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type ChangeStatus int 4 | 5 | const ( 6 | _ = iota 7 | 8 | CHNotApplied ChangeStatus = iota 9 | CHSucceeded 10 | CHFailed 11 | CHNoChangeRequested 12 | ) 13 | 14 | type Verbosity int 15 | 16 | const ( 17 | VHigh Verbosity = iota 18 | VChangesOnly 19 | VOff 20 | ) 21 | 22 | type ChownOption struct { 23 | verbosity Verbosity 24 | recurse bool 25 | // rootDevIno *devIno 26 | affectSymlinkReferent bool 27 | forceSilent bool 28 | userName string 29 | groupName string 30 | } 31 | 32 | type RCHStatus int 33 | 34 | const ( 35 | _ = iota 36 | _ = iota 37 | 38 | RCOK RCHStatus = iota 39 | RCExcluded 40 | RCInodeChanged 41 | RCDoOrdinaryChown 42 | RCError 43 | ) 44 | -------------------------------------------------------------------------------- /chown/patch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euf -o pipefail 3 | 4 | 5 | ORIG=$PWD 6 | 7 | # You don't need wget the tarball unless you don't trust mine... 8 | # MD5: 8cb8c7de1776a5badf4f0070eb009363 patch101310044_20001.tar.bz2 9 | 10 | #PATCH=https://codereview.appspot.com/tarball/101310044/20001 11 | FNAME=patch101310044_20001.tar.bz2 12 | #wget -O $FNAME $PATCH 13 | 14 | # If this fails then either the downloaded tarball was downloaded incorrectly 15 | # or something else weird happened. In any case, go to 16 | # https://codereview.appspot.com/101310044/ and find the correct patch, 17 | # download the tarball, and place it inside this directory under the name 18 | # patch101310044_20001.tar.bz2 and then run this script 19 | # Or just do it yourself 20 | md5sum -c checksum 21 | if [[ $? != 0 ]]; then 22 | echo "checksum did not match." 23 | exit 1 24 | fi 25 | 26 | tar -xjf $FNAME 27 | 28 | if [ ! $GOROOT ]; then 29 | GOROOT="$(dirname "$(which go)")" 30 | fi 31 | 32 | cd $GOROOT && cd ../ 33 | cd src/pkg/os/ 34 | rm --preserve-root -r a/ 35 | cp -r $ORIG/b/src/pkg/os/user/* user/ 36 | if [[ $? != 0 ]]; then 37 | if [[ $EUID -ne 0 ]]; then 38 | echo "If 'permission denied', then this script must be run as root" 1>&2 39 | exit 1 40 | fi 41 | fi 42 | cd ../../ 43 | ./all.bash 44 | if [[ $? != 0 ]]; then 45 | if [[ $EUID -ne 0 ]]; then 46 | echo "If 'permission denied', then this script must be run as root" 1>&2 47 | exit 1 48 | fi 49 | fi 50 | cd $ORIG 51 | rm --preserve-root -r b/ 52 | 53 | exit 0 54 | -------------------------------------------------------------------------------- /chown/patch101310044_20001.tar.bz2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/chown/patch101310044_20001.tar.bz2 -------------------------------------------------------------------------------- /chroot/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/chroot/.gitignore -------------------------------------------------------------------------------- /chroot/chroot.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /cksum/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/cksum/.gitignore -------------------------------------------------------------------------------- /cksum/cksum.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /comm/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/comm/.gitignore -------------------------------------------------------------------------------- /comm/comm.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /coreutils.go: -------------------------------------------------------------------------------- 1 | package coreutils 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "io" 7 | "sync" 8 | ) 9 | 10 | var cmdsMu sync.Mutex 11 | var cmds = make(map[string]Runnable) 12 | 13 | func Register(name string, r Runnable) { 14 | cmdsMu.Lock() 15 | defer cmdsMu.Unlock() 16 | if _, ok := cmds[name]; ok { 17 | panic("Register called with identical name: " + name) 18 | } 19 | cmds[name] = r 20 | } 21 | 22 | type Runnable func(ctx Context, args ...string) error 23 | 24 | type Context struct { 25 | context.Context 26 | Dir string 27 | GetEnv func(string) string 28 | Stdin io.Reader 29 | Stdout io.Writer 30 | Stderr io.Writer 31 | } 32 | 33 | func Run(ctx Context, name string, args ...string) error { 34 | cmdsMu.Lock() 35 | fn := cmds[name] 36 | cmdsMu.Unlock() 37 | if fn == nil { 38 | return errors.New("invalid function ...") 39 | } 40 | return fn(ctx, args...) 41 | } 42 | -------------------------------------------------------------------------------- /cp/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/cp/.gitignore -------------------------------------------------------------------------------- /cp/foo.txt: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "log" 7 | "os" 8 | "syscall" 9 | ) 10 | 11 | type Options struct { 12 | AsRegular bool 13 | Dereference bool // check type 14 | UnlinkBefore bool 15 | UnlinkAfterFailed bool 16 | HardLink bool 17 | Interactive bool 18 | MoveMode bool 19 | OneFS bool 20 | RefLinkMode bool // check type 21 | 22 | PreserveOwnership bool 23 | PreserveLinks bool 24 | PreserveMode bool 25 | PreserveTimestamps bool 26 | ExplicitNoPreserve bool 27 | PreserveSecurityContex bool // -a or --preserve=context 28 | RequirePreserveContext bool // --preserve=contex 29 | SetSecurityContext bool // -Z, set sys default contex 30 | PreserveXattr bool 31 | ReduceDiagnostics bool 32 | RequirePreserveXattr bool 33 | 34 | DataCopyRequired bool 35 | RequirePreserve bool 36 | Recursive bool 37 | SparseMode bool // check type 38 | SymbolicLink bool 39 | SetMode bool 40 | Mode int 41 | 42 | Update bool 43 | Verbose bool 44 | } 45 | 46 | func newOptions() *Options { 47 | return &Options{ 48 | AsRegular: true, 49 | Dereference: true, // check type 50 | //HardLink: ? //check type 51 | //Interactive: ? //check type 52 | //RefLinkMode: ? //checktype 53 | } 54 | } 55 | 56 | func isDir(file string) (bool, *os.FileInfo) { 57 | info, err := os.Stat(file) 58 | if err != nil { 59 | if err.(*os.PathError).Err != syscall.ENOENT { 60 | log.Fatalf("%s failed to access %s", err, file) 61 | } 62 | return false, nil 63 | } 64 | return info.Mode().IsDir(), &info 65 | } 66 | 67 | func cp(n int, file []string, dir string, options *Options) { 68 | if n <= 0 { 69 | log.Fatalln("missing file operand") 70 | } 71 | 72 | if noDir { 73 | 74 | } 75 | } 76 | 77 | func main() { 78 | } 79 | -------------------------------------------------------------------------------- /cp/idk.go: -------------------------------------------------------------------------------- 1 | package main 2 | -------------------------------------------------------------------------------- /csplit/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/csplit/.gitignore -------------------------------------------------------------------------------- /csplit/boyermoore.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | var BuffSize = 7 4 | 5 | func main() { 6 | pattern := "eric" 7 | test := "america" 8 | } 9 | 10 | func preBad(x string, m int, badChar []int) { 11 | for i := 0; i < BuffSize; i++ { 12 | badChar[i] = m 13 | } 14 | 15 | for i := 0; i < m-1; i++ { 16 | badChar[x[i]] = m - i - 1 17 | } 18 | } 19 | 20 | func suffix(x string, m int, suff []int) { 21 | var f int 22 | 23 | suff[m-1] = m 24 | g := m - 1 25 | 26 | for i := m - 2; i >= 0; i-- { 27 | if i > g && suff[i+m-1-f] < i-g { 28 | suff[i] = suff[i+m-1-f] 29 | } else { 30 | if i > g { 31 | g = i 32 | } 33 | f = i 34 | for g >= 0 && x[g] == x[g+m-1-f] { 35 | g-- 36 | } 37 | suff[i] = f - g 38 | } 39 | } 40 | } 41 | 42 | func preGood(x string, m int, goodChar []int) { 43 | suff := make([]int, BuffSize) 44 | suffix(x, m, suff) 45 | } 46 | -------------------------------------------------------------------------------- /csplit/csplit.go: -------------------------------------------------------------------------------- 1 | package main 2 | -------------------------------------------------------------------------------- /csplit/mmap.go: -------------------------------------------------------------------------------- 1 | package main 2 | -------------------------------------------------------------------------------- /csplit/read.go: -------------------------------------------------------------------------------- 1 | package main 2 | -------------------------------------------------------------------------------- /csplit/test.txt: -------------------------------------------------------------------------------- 1 | I. HELLO 2 | II. THIS 3 | III. IS 4 | IV. A 5 | V. TEST -------------------------------------------------------------------------------- /cut/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/cut/.gitignore -------------------------------------------------------------------------------- /cut/cut.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /date/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/date/.gitignore -------------------------------------------------------------------------------- /date/date.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /dd/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/dd/.gitignore -------------------------------------------------------------------------------- /dd/dd.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /df/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/df/.gitignore -------------------------------------------------------------------------------- /df/df.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /dir/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/dir/.gitignore -------------------------------------------------------------------------------- /dir/dir.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /dircolors/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/dircolors/.gitignore -------------------------------------------------------------------------------- /dircolors/dircolors.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /dirname/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/dirname/.gitignore -------------------------------------------------------------------------------- /dirname/dirname.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /du/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/du/.gitignore -------------------------------------------------------------------------------- /du/du.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /echo/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/echo/.gitignore -------------------------------------------------------------------------------- /echo/echo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /editlicensedates.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (c) 2015 Eric Lagergren 4 | # This is public domain. 5 | 6 | set -euo pipefail 7 | 8 | shopt -s globstar nullglob extglob 9 | for f in **/*.@(go); do 10 | if [[ -f $f ]]; then 11 | sed -i 's/Copyright (C) 2014 /Copyright (c) 2014-2015 /g' "$f" 12 | fi 13 | done -------------------------------------------------------------------------------- /env/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/env/.gitignore -------------------------------------------------------------------------------- /env/env.go: -------------------------------------------------------------------------------- 1 | /* 2 | Go env - run a program in a modified environment 3 | Copyright (C) 1986-2015 Eric Lagergren 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "fmt" 23 | "log" 24 | "os" 25 | "os/exec" 26 | "strings" 27 | 28 | flag "github.com/ogier/pflag" 29 | ) 30 | 31 | const ( 32 | help = ` 33 | Usage: env [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...] 34 | Set each NAME to VALUE in the environment and run COMMAND. 35 | 36 | Mandatory arguments to long options are mandatory for short options too. 37 | -i, --ignore-environment start with an empty environment 38 | -0, --null end each output line with NUL, not newline 39 | -u, --unset=NAME remove variable from the environment 40 | -s, --set=NAME set variable in the environment 41 | --help display this help and exit 42 | --version output version information and exit 43 | 44 | A mere - implies -i. If no COMMAND, print the resulting environment. 45 | 46 | Report wc bugs to ericscottlagergren@gmail.com 47 | Go coreutils home page: 48 | ` 49 | version = `env (Go coreutils) 1.0 50 | Copyright (C) 2015 Eric Lagergren 51 | License GPLv3+: GNU GPL version 3 or later . 52 | This is free software: you are free to change and redistribute it. 53 | There is NO WARRANTY, to the extent permitted by law. 54 | ` 55 | ) 56 | 57 | var ( 58 | unset string 59 | set string 60 | nullEol bool 61 | ignore bool 62 | 63 | // fatal = log.New(os.Stderr, "", log.Lshortfile) 64 | fatal = log.New(os.Stderr, "", 0) 65 | 66 | env = os.Environ() 67 | ) 68 | 69 | // Run a command, waiting for it to finish. Will first run CMD's path; 70 | // failing that, will lookup the path and attempt to do the same. 71 | func execvp(cmd exec.Cmd) error { 72 | if err := cmd.Start(); err == nil { 73 | 74 | // Wait for command to finish 75 | return cmd.Wait() 76 | 77 | } 78 | 79 | // Didn't work? Search for the executable's path 80 | path, err := exec.LookPath(cmd.Path) 81 | if err != nil { 82 | return err 83 | } 84 | 85 | // Reset our path 86 | cmd.Path = path 87 | 88 | // Try again with the executable found in $PATH 89 | if err = cmd.Start(); err != nil { 90 | return err 91 | } 92 | return cmd.Wait() 93 | } 94 | 95 | func parseFlags(argv []string) (args []string) { 96 | for i := 1; i < len(argv); i++ { 97 | switch v := argv[i]; v { 98 | case "-i", "--ignore-environment": 99 | ignore = true 100 | case "-0", "--null": 101 | nullEol = true 102 | case "-u", "--unset": 103 | i++ 104 | unset = argv[i] 105 | case "-s", "--set": 106 | i++ 107 | set = argv[i] 108 | case "--help": 109 | fmt.Fprintf(os.Stderr, "%s", help) 110 | os.Exit(1) 111 | case "--version": 112 | fmt.Printf("%s", version) 113 | os.Exit(0) 114 | default: 115 | args = append(args, v) 116 | } 117 | } 118 | return args 119 | } 120 | 121 | func main() { 122 | args := parseFlags(os.Args) 123 | 124 | if unset != "" { 125 | os.Unsetenv(unset) 126 | } 127 | 128 | cmd := exec.Cmd{Env: env} 129 | 130 | // Check for "-" as an argument, because it means the same as "-i" 131 | if flag.Arg(0) == "-" { 132 | cmd.Env = []string{} 133 | } 134 | 135 | for i, arg := range args { 136 | if strings.Index(arg, "=") > 0 { 137 | cmd.Env = append(cmd.Env, arg) 138 | } else if arg != "-" { 139 | if nullEol { 140 | fatal.Fatalln("cannot specify --null (-0) with command") 141 | } 142 | 143 | cmd.Path = arg 144 | 145 | cmd.Args = append(cmd.Args, args[i:]...) 146 | cmd.Stdin = os.Stdin 147 | cmd.Stdout = os.Stdout 148 | cmd.Stderr = os.Stderr 149 | 150 | if err := execvp(cmd); err != nil { 151 | fatal.Fatalln(err) 152 | } 153 | return 154 | } 155 | } 156 | 157 | eol := '\n' 158 | if nullEol { 159 | eol = '\x00' 160 | } 161 | 162 | for _, e := range env { 163 | fmt.Printf("%s%c", e, eol) 164 | } 165 | 166 | return 167 | } 168 | -------------------------------------------------------------------------------- /expand/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/expand/.gitignore -------------------------------------------------------------------------------- /expand/expand.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /expr/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/expr/.gitignore -------------------------------------------------------------------------------- /expr/expr.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /factor/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/factor/.gitignore -------------------------------------------------------------------------------- /factor/factor.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /false/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/false/.gitignore -------------------------------------------------------------------------------- /false/false.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | const ( 9 | Help = `Usage: /usr/bin/false [ignored command line arguments] 10 | or: /usr/bin/false OPTION 11 | Exit with a status code indicating success. 12 | 13 | --help display this help and exit 14 | --version output version information and exit 15 | 16 | NOTE: your shell may have its own version of false, which usually supersedes 17 | the version described here. Please refer to your shell's documentation 18 | for details about the options it supports. 19 | ` 20 | Version = `false (Go coreutils) 1.0 21 | Copyright (C) 2015 Eric Lagergren 22 | License GPLv3+: GNU GPL version 3 or later . 23 | This is free software: you are free to change and redistribute it. 24 | There is NO WARRANTY, to the extent permitted by law. 25 | ` 26 | ) 27 | 28 | func main() { 29 | if len(os.Args) == 2 { 30 | if os.Args[1] == "--help" { 31 | fmt.Printf("%s", Help) 32 | } 33 | 34 | if os.Args[1] == "--version" { 35 | fmt.Printf("%s", Version) 36 | } 37 | } 38 | os.Exit(1) 39 | } 40 | -------------------------------------------------------------------------------- /fmt/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/fmt/.gitignore -------------------------------------------------------------------------------- /fmt/fmt.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /fold/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/fold/.gitignore -------------------------------------------------------------------------------- /fold/fold.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /groups/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/groups/.gitignore -------------------------------------------------------------------------------- /groups/groups.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /head/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/head/.gitignore -------------------------------------------------------------------------------- /head/head.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /hostid/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/hostid/.gitignore -------------------------------------------------------------------------------- /hostid/hostid.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /id/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/id/.gitignore -------------------------------------------------------------------------------- /id/id.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /install/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/install/.gitignore -------------------------------------------------------------------------------- /install/install.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /join/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/join/.gitignore -------------------------------------------------------------------------------- /join/join.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /link/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/link/.gitignore -------------------------------------------------------------------------------- /link/link.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /ln/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/ln/.gitignore -------------------------------------------------------------------------------- /ln/ln.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /logname/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/logname/.gitignore -------------------------------------------------------------------------------- /logname/logname.go: -------------------------------------------------------------------------------- 1 | /* 2 | Go logname -- print user's login name 3 | 4 | Copyright (C) 2015 Eric Lagergren 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | /* Written by Eric Lagergren */ 21 | 22 | package main 23 | 24 | import ( 25 | "fmt" 26 | "log" 27 | "os" 28 | 29 | "github.com/EricLagergren/go-gnulib/login" 30 | 31 | flag "github.com/ogier/pflag" 32 | ) 33 | 34 | const ( 35 | HELP = `Usage: logname [OPTION]... 36 | Print the name of the current user. 37 | 38 | --help display this help and exit 39 | --version output version information and exit 40 | 41 | Report logname bugs to ericscottlagergren@gmail.com 42 | Go coreutils home page: 43 | ` 44 | 45 | VERSION = `logname (Go coreutils) 1.0 46 | Copyright (C) 2015 Eric Lagergren 47 | License GPLv3+: GNU GPL version 3 or later . 48 | This is free software: you are free to change and redistribute it. 49 | There is NO WARRANTY, to the extent permitted by law. 50 | 51 | Written by Eric Lagergren 52 | ` 53 | ) 54 | 55 | var ( 56 | version = flag.BoolP("version", "v", false, "print program version") 57 | 58 | fatal = log.New(os.Stderr, "", 0) 59 | //fatal = log.New(os.Stderr, "", log.Lshortfile) 60 | ) 61 | 62 | func main() { 63 | flag.Usage = func() { 64 | fmt.Fprintf(os.Stderr, "%s", HELP) 65 | os.Exit(0) 66 | } 67 | flag.Parse() 68 | 69 | if *version { 70 | fmt.Fprintf(os.Stderr, "%s", VERSION) 71 | os.Exit(0) 72 | } 73 | 74 | name, err := login.GetLogin() 75 | if err != nil { 76 | // POSIX prohibits using a fallback 77 | fatal.Fatalln("no login name") 78 | } 79 | 80 | fmt.Println(name) 81 | } 82 | -------------------------------------------------------------------------------- /ls/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/ls/.gitignore -------------------------------------------------------------------------------- /ls/ls.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /md5sum/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/md5sum/.gitignore -------------------------------------------------------------------------------- /md5sum/checksum_common/calc_sum.go: -------------------------------------------------------------------------------- 1 | /* 2 | go checksum common 3 | 4 | Copyright (c) 2014-2015 Dingjun Fang 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License version 3 as 8 | published by the Free Software Foundation. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | package checksum_common 20 | 21 | import ( 22 | "crypto/md5" 23 | "crypto/sha1" 24 | "crypto/sha256" 25 | "crypto/sha512" 26 | "fmt" 27 | //flag "github.com/ogier/pflag" 28 | "hash" 29 | "io" 30 | "os" 31 | "path/filepath" 32 | ) 33 | 34 | /* 35 | read from os.File and return the whole file's checksum 36 | */ 37 | func calc_checksum(fp io.Reader, t string) string { 38 | var m hash.Hash 39 | switch t { 40 | case "md5": 41 | m = md5.New() 42 | case "sha1": 43 | m = sha1.New() 44 | case "sha512": 45 | m = sha512.New() 46 | case "sha256": 47 | m = sha256.New() 48 | case "sha224": 49 | m = sha256.New224() 50 | case "sha384": 51 | m = sha512.New384() 52 | default: 53 | output_e("unknown type: %s\n", t) 54 | return "" 55 | } 56 | 57 | /* issue: 58 | if fp is os.Stdin, there is no way to trigger EOF 59 | */ 60 | _, err := io.Copy(m, fp) 61 | 62 | if err != nil { 63 | output_e("%ssum: %s\n", t, err.Error()) 64 | return "" 65 | } 66 | 67 | return fmt.Sprintf("%x", m.Sum(nil)) 68 | } 69 | 70 | /* 71 | generate the checksum for all of files from cmdline 72 | */ 73 | func gen_checksum(files []string, t string) bool { 74 | 75 | has_error := false 76 | 77 | for i := 0; i < len(files); i++ { 78 | fn := files[i] 79 | 80 | /* stdin */ 81 | if fn == "-" { 82 | sum := calc_checksum(os.Stdin, t) 83 | if sum != "" { 84 | fmt.Fprintf(os.Stdout, "%s *%s\n", sum, fn) 85 | } else { 86 | has_error = true 87 | } 88 | continue 89 | } 90 | 91 | /* file */ 92 | 93 | /* extends file lists when filename contains '*' */ 94 | filenames, _ := filepath.Glob(fn) 95 | if filenames == nil { 96 | filenames = append(filenames, fn) 97 | } 98 | 99 | for _, f := range filenames { 100 | file, err := os.Open(f) 101 | if err != nil { 102 | has_error = true 103 | fmt.Fprintf(os.Stderr, "%ssum: %s\n", t, err.Error()) 104 | continue 105 | } 106 | sum := calc_checksum(file, t) 107 | file.Close() 108 | if sum != "" { 109 | fmt.Fprintf(os.Stdout, "%s *%s\n", sum, f) 110 | } else { 111 | has_error = true 112 | } 113 | } 114 | } 115 | 116 | return !has_error 117 | } 118 | 119 | /* 120 | generate the checksum for given file list. 121 | 122 | files: the file name lists to generate checksum 123 | 124 | t: the type of checksum, md5 or sha1... 125 | 126 | return false if there are some errors. 127 | 128 | return true if there is no error. 129 | */ 130 | func GenerateChecksum(files []string, t string) bool { 131 | return gen_checksum(files, t) 132 | } 133 | -------------------------------------------------------------------------------- /md5sum/checksum_common/check_sum.go: -------------------------------------------------------------------------------- 1 | /* 2 | go checksum common 3 | 4 | Copyright (c) 2014-2015 Dingjun Fang 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License version 3 as 8 | published by the Free Software Foundation. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | /* 20 | the core checksum implements of md5, sha1, sha224, sha256, sha384, sha512. 21 | */ 22 | package checksum_common 23 | 24 | import ( 25 | "bufio" 26 | //flag "github.com/ogier/pflag" 27 | "io" 28 | "os" 29 | "path/filepath" 30 | "strings" 31 | ) 32 | 33 | /* 34 | check the checksum for all of files 35 | */ 36 | func check_checksum(files []string, t string) bool { 37 | 38 | has_err := false 39 | 40 | for i := 0; i < len(files); i++ { 41 | 42 | /* stdin */ 43 | if files[i] == "-" { 44 | if b := check_checksum_f(os.Stdin, t); !b { 45 | has_err = true 46 | } 47 | continue 48 | } 49 | 50 | /* file */ 51 | file, err := os.Open(files[i]) 52 | if err != nil { 53 | output_e("%ssum: %s\n", t, err.Error()) 54 | has_err = true 55 | continue 56 | } 57 | if b := check_checksum_f(file, t); !b { 58 | has_err = true 59 | } 60 | file.Close() 61 | } 62 | 63 | return !has_err 64 | } 65 | 66 | /* 67 | process single checksum list file 68 | */ 69 | func check_checksum_f(fp io.Reader, t string) bool { 70 | has_err := false 71 | reader := bufio.NewReader(fp) 72 | 73 | /* total file */ 74 | total := 0 75 | 76 | /* failed number */ 77 | failed := 0 78 | 79 | /* error number */ 80 | errored := 0 81 | 82 | /* line number */ 83 | line_num := 0 84 | 85 | for { 86 | line_num += 1 87 | l, _, err := reader.ReadLine() 88 | if err != nil { 89 | if err != io.EOF { 90 | has_err = true 91 | output_e("%ssum: %s\n", t, err.Error()) 92 | } 93 | break 94 | } 95 | 96 | ll := strings.TrimSpace(string(l)) 97 | 98 | if ll == "" { 99 | continue 100 | } 101 | 102 | /* strip the '\' at beginning */ 103 | if ll[0] == '\\' { 104 | ll = ll[1:] 105 | } 106 | 107 | fields := strings.Fields(ll) 108 | 109 | if len(fields) != 2 { 110 | if show_warn { 111 | output_e("%ssum: line: %d: improperly formatted %s checksum line\n", 112 | t, line_num, strings.ToUpper(t)) 113 | } 114 | continue 115 | } 116 | 117 | sum, fn := fields[0], fields[1] 118 | 119 | /* strip the '*' from filename */ 120 | if fn[0] == '*' { 121 | fn = fn[1:] 122 | } 123 | 124 | fn = filepath.Clean(fn) 125 | 126 | file, err := os.Open(fn) 127 | if err != nil { 128 | output_e("%ssum: %s\n", t, err.Error()) 129 | has_err = true 130 | errored += 1 131 | continue 132 | } 133 | 134 | sum1 := calc_checksum(file, t) 135 | file.Close() 136 | 137 | total += 1 138 | 139 | if sum1 != "" { 140 | if sum1 != sum { // failed 141 | failed += 1 142 | output_e("%s: FAILED\n", fn) 143 | has_err = true 144 | } else { // success 145 | output_n("%s: OK\n", fn) 146 | } 147 | } else { // error 148 | errored += 1 149 | has_err = true 150 | } 151 | } 152 | 153 | if failed > 0 && show_warn { 154 | output_e("%ssum: WARNING: %d of %d computed checksums did NOT match\n", 155 | t, failed, total) 156 | } 157 | 158 | if errored > 0 && show_warn { 159 | output_e("%ssum: WARNING: %d of %d listed files could not be read\n", 160 | t, errored, total) 161 | } 162 | 163 | return !has_err 164 | } 165 | 166 | /* 167 | read the file contains the checksum and check it 168 | 169 | files: file name lists which contains the checksums. 170 | 171 | t: the type of checksum, md5 or sha1... 172 | 173 | return true if everything is ok 174 | 175 | return false if there are some errors. 176 | */ 177 | func CompareChecksum(files []string, t string, output_message, output_warn bool) bool { 178 | no_output = !output_message 179 | show_warn = output_warn 180 | return check_checksum(files, t) 181 | } 182 | -------------------------------------------------------------------------------- /md5sum/checksum_common/checksum_test.go: -------------------------------------------------------------------------------- 1 | package checksum_common 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "os" 8 | "testing" 9 | ) 10 | 11 | func TestCalc_checksum(t *testing.T) { 12 | cases := []struct { 13 | in, want, t string 14 | }{ 15 | /* md5 */ 16 | {"hello, world", "e4d7f1b4ed2e42d15898f4b27b019da4", "md5"}, 17 | {"ad3344412123123fasdfasdf", "353a3336352ae74136ef5b37e4091c4c", "md5"}, 18 | {"333dddf213sfasdfasdfasfd\n", "106f56f032f7d29af6af98eeb24d5d2c", "md5"}, 19 | 20 | /* sha1 */ 21 | {"hello, world", "b7e23ec29af22b0b4e41da31e868d57226121c84", "sha1"}, 22 | {"ad3344412123123fasdfasdf", "76758123ef52b09899546142393c32db7f53a022", "sha1"}, 23 | {"333dddf213sfasdfasdfasfd\n", "0d966748d89029d547f3e36e63af9839f3b9ce6b", "sha1"}, 24 | 25 | /* sha224 */ 26 | {"hello, world", "6e1a93e32fb44081a401f3db3ef2e6e108b7bbeeb5705afdaf01fb27", "sha224"}, 27 | {"ad3344412123123fasdfasdf", "372b81303da6fd1418041af497d53b9434891b9c93954e929d4ee7a3", "sha224"}, 28 | {"333dddf213sfasdfasdfasfd\n", "cc92bf4cc34f856bfedc056f943afc68121f74620ca158f42920765f", "sha224"}, 29 | 30 | /* sh256 */ 31 | {"hello, world", "09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b", "sha256"}, 32 | {"ad3344412123123fasdfasdf", "a1962c3391c5580497624394b3b156637ec0e33d6705938c505b4a20e7e73fce", "sha256"}, 33 | {"333dddf213sfasdfasdfasfd\n", "19bacc61eb1896d9865d77f62c19a325b704a7a23ef43e2cb46d9b406c01ab28", "sha256"}, 34 | 35 | /* sha384 */ 36 | {"hello, world", "1fcdb6059ce05172a26bbe2a3ccc88ed5a8cd5fc53edfd9053304d429296a6da23b1cd9e5c9ed3bb34f00418a70cdb7e", "sha384"}, 37 | {"ad3344412123123fasdfasdf", "494dd728eeccfa6cc27815538ab432c4dbb19d0f7157654fb3fc945fd2f6535535d4af8dbefbefbd51d608b4423c9508", "sha384"}, 38 | {"333dddf213sfasdfasdfasfd\n", "8823b5ac0abaa00b665525e74072f233a6a8f0291cf6974d04ab548acbb11e860f13b156a787987cd9cd799306d4b138", "sha384"}, 39 | 40 | /* sha512 */ 41 | {"hello, world", "8710339dcb6814d0d9d2290ef422285c9322b7163951f9a0ca8f883d3305286f44139aa374848e4174f5aada663027e4548637b6d19894aec4fb6c46a139fbf9", "sha512"}, 42 | {"ad3344412123123fasdfasdf", "e08719391e0e3592db97bf24084ea5230f645da3cb5747aa10e504feafc53426348a61ea9b392be255ac89c28a2ed9092d433b377292827a65a897a2a7687a07", "sha512"}, 43 | {"333dddf213sfasdfasdfasfd\n", "c7fb59d56d18f86c6838a3a504dcc939e11eec832338f5ef998f222f7cd66527536499dcfac5b8649381adf7665e0557e3574febca7d605a0798b8f737d05f54", "sha512"}, 44 | } 45 | 46 | for _, v := range cases { 47 | buf := bytes.NewBufferString(v.in) 48 | sum := calc_checksum(buf, v.t) 49 | if sum != v.want { 50 | t.Errorf("%ssum (%#v) == %#v, want %#v", v.t, v.in, sum, v.want) 51 | } else { 52 | t.Logf("%ssum (%#v), expect %#v, got %#v\n", v.t, v.in, v.want, sum) 53 | } 54 | } 55 | } 56 | 57 | func TestCheck_checksum(t *testing.T) { 58 | 59 | old_stdout := os.Stdout 60 | 61 | /* capture output */ 62 | r, w, _ := os.Pipe() 63 | os.Stdout = w 64 | 65 | outC := make(chan string) 66 | 67 | defer func() { 68 | w.Close() 69 | os.Stdout = old_stdout 70 | output := <-outC 71 | t.Logf("%s\n", output) 72 | }() 73 | 74 | go func() { 75 | var buf bytes.Buffer 76 | io.Copy(&buf, r) 77 | outC <- buf.String() 78 | }() 79 | 80 | sum_methods := []string{"md5", "sha1", "sha224", "sha256", "sha384", "sha512"} 81 | for _, m := range sum_methods { 82 | fn := fmt.Sprintf("testdata/checksum.%s", m) 83 | sum_f_lists := []string{fn} 84 | if r := CompareChecksum(sum_f_lists, m, true, true); !r { 85 | t.Fail() 86 | } else { 87 | t.Logf("check %s for %s: success\n", fn, m) 88 | } 89 | } 90 | } 91 | 92 | func TestGenChecksum(t *testing.T) { 93 | 94 | old_stdout := os.Stdout 95 | 96 | /* capture output */ 97 | r, w, _ := os.Pipe() 98 | os.Stdout = w 99 | 100 | outC := make(chan string) 101 | 102 | defer func() { 103 | w.Close() 104 | os.Stdout = old_stdout 105 | output := <-outC 106 | t.Logf("\n%s\n", output) 107 | }() 108 | 109 | go func() { 110 | var buf bytes.Buffer 111 | io.Copy(&buf, r) 112 | outC <- buf.String() 113 | }() 114 | 115 | sum_methods := []string{"md5", "sha1", "sha224", "sha256", "sha384", "sha512"} 116 | for _, m := range sum_methods { 117 | flists := []string{"testdata/*.txt"} 118 | if r := GenerateChecksum(flists, m); !r { 119 | t.Fail() 120 | } else { 121 | t.Logf("generate %sum: success\n", m) 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /md5sum/checksum_common/output.go: -------------------------------------------------------------------------------- 1 | /* 2 | go checksum common 3 | 4 | Copyright (c) 2014-2015 Dingjun Fang 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License version 3 as 8 | published by the Free Software Foundation. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | package checksum_common 20 | 21 | import ( 22 | "fmt" 23 | "os" 24 | ) 25 | 26 | var no_output bool = false 27 | var show_warn bool = true 28 | 29 | /* 30 | output to stdout 31 | */ 32 | func output_n(s string, s1 ...interface{}) { 33 | if no_output != true { 34 | fmt.Fprintf(os.Stdout, s, s1...) 35 | } 36 | } 37 | 38 | /* 39 | output to stderr 40 | */ 41 | func output_e(s string, s1 ...interface{}) { 42 | if no_output != true { 43 | fmt.Fprintf(os.Stderr, s, s1...) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /md5sum/checksum_common/testdata/aad33efasdf.txt: -------------------------------------------------------------------------------- 1 | ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd 2 | ffffffffffffffffffffffffffffffffffffffffffffffffffffff 3 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 4 | ddddddddddddddddddddddddd 5 | f3444444444444444444444444444444444444444444444444 6 | 5555555555555555555555555555555555 7 | 3333333333333333333333 8 | 3333333333333333333333 -------------------------------------------------------------------------------- /md5sum/checksum_common/testdata/checksum.md5: -------------------------------------------------------------------------------- 1 | 87baa79eee939e85645b0985683f2d17 *testdata/aad33efasdf.txt 2 | 05d52ce6dc54a594790686d383b4f766 *testdata/d333dasdf3.txt 3 | 6e83af947fa5d0ff4838d91fdc1c5819 *testdata/rgsdfsdfewerwf.txt 4 | -------------------------------------------------------------------------------- /md5sum/checksum_common/testdata/checksum.sha1: -------------------------------------------------------------------------------- 1 | 10aa2454094c9b4c6f92dfbfe643a6176cf1f534 *testdata/aad33efasdf.txt 2 | bb4671ffb2e316634ee5ed38ca2d5c8afea48425 *testdata/d333dasdf3.txt 3 | eaf81c56f2d7ebb66064e38e4237e2158001c6a4 *testdata/rgsdfsdfewerwf.txt 4 | -------------------------------------------------------------------------------- /md5sum/checksum_common/testdata/checksum.sha224: -------------------------------------------------------------------------------- 1 | 3f6f5dafef1c3b250ef71b3f3e133738a4cb4b8f54bf860396a48bcc *testdata/aad33efasdf.txt 2 | ccbcc955e155fd479a06aa91c713b9868105afa34a4eec5ef1eae49d *testdata/d333dasdf3.txt 3 | f001b48669e9ef021d7ae54969bf1a4b4ddae49f701a6bb5ccc3a210 *testdata/rgsdfsdfewerwf.txt 4 | -------------------------------------------------------------------------------- /md5sum/checksum_common/testdata/checksum.sha256: -------------------------------------------------------------------------------- 1 | c45212cc8468c69ec29c8283810182005109db11d5795f3cf7576321072223c5 *testdata/aad33efasdf.txt 2 | c03431fd8606f6afbc3d780e62847e723c918a5292ae96b5f9fbc3ae96f792c6 *testdata/d333dasdf3.txt 3 | cc64281c6e6e4c0a0c57ef2b3a38299c47114ca014334e09a76281fd82a8845d *testdata/rgsdfsdfewerwf.txt 4 | -------------------------------------------------------------------------------- /md5sum/checksum_common/testdata/checksum.sha384: -------------------------------------------------------------------------------- 1 | f3cfa1ea2a5b98630b141448ad420e7e49ec01113ec67bf9ea2d945dda8090b109ec16c90eb064ce7efd754778571ce8 *testdata/aad33efasdf.txt 2 | 23652f1dacba1e2fe3ff79b3df02e3f5d53af71a5e5c7a91f5d4873975161955dc8eda34818a57d719b29b8844f4e8f4 *testdata/d333dasdf3.txt 3 | 1146cc8e078a65c3c96c6551d78b68224a4cd25352dc8215294b8b7a390b8d5b5b46174ca44ea800fbff10aede5781cf *testdata/rgsdfsdfewerwf.txt 4 | -------------------------------------------------------------------------------- /md5sum/checksum_common/testdata/checksum.sha512: -------------------------------------------------------------------------------- 1 | 1987cb5f81681165781df2e8a74417e7c78d63aebfd9fb959970d8455aad151af5683a049bcb54732a3143f5c6ce34d5d092de7d6b07ad0a661d955e0c7cebb4 *testdata/aad33efasdf.txt 2 | ad85f6622035b001fdce7cee100e2ae5aefb26dd4d86291355cd2403e872f7ca37771ea41304eb10e4ab8cb38f0b0fe39e5cbe8b816da40f73e010462008564f *testdata/d333dasdf3.txt 3 | 9d469a012e241672e2f7bcdf3a64d6d782e554fa2daf1e9a3b875d4c42243b824ed6e7b25d4b271ef6e34a5cb33ebb14b9dccfb2fb1379ba77cc873dcda91c20 *testdata/rgsdfsdfewerwf.txt 4 | -------------------------------------------------------------------------------- /md5sum/checksum_common/testdata/d333dasdf3.txt: -------------------------------------------------------------------------------- 1 | aaaaaaaaaaaaaaaaaaaaaaaaaaa 2 | ffffffffffffffffffffffff 3 | aaaaaaaaaaaaaaaaaaa 4 | ffffffffffffffffffffff 5 | ffffffffffffffffff 6 | aaaaaaaaa 7 | ;;;;;;;;;;;;;;;;;;;........3333333333333333fg 8 | asddddddddddddddddddd -------------------------------------------------------------------------------- /md5sum/checksum_common/testdata/rgsdfsdfewerwf.txt: -------------------------------------------------------------------------------- 1 | teasdf 2 | asdfffffffffffffffffffffffffffffffffffffffff 3 | asfda 4 | sdfa 5 | sdfa 6 | asdf 7 | asfaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 8 | das 9 | dfasfd 10 | -------------------------------------------------------------------------------- /md5sum/md5sum.go: -------------------------------------------------------------------------------- 1 | /* 2 | go md5sum 3 | 4 | Copyright (c) 2014-2015 Dingjun Fang 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License version 3 as 8 | published by the Free Software Foundation. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | /* 20 | 21 | Md5sum util implement by go. 22 | 23 | Usage: md5sum [OPTION]... [FILE]... 24 | 25 | Print or check MD5 (128-bit) checksums. 26 | 27 | With no FILE, or when FILE is -, read standard input. 28 | 29 | -b, --binary read in binary mode(default) 30 | -c, --check read MD5 sums from the FILEs and check them 31 | -t, --text read in text mode 32 | Note: there is no difference between text and binary mode option. 33 | 34 | The following three options are useful only when verifying checksums: 35 | --quiet don't print OK for each successfully verified file 36 | --status don't output anything, status code shows success 37 | -w, --warn warn about improperly formated checksum lines 38 | 39 | --help show help and exit 40 | --version show version and exit 41 | 42 | The sums are computed as described in RFC 1321. When checking, the input 43 | should be a former output of this program. The default mode is to print 44 | a line with checksum, a character indicating type ('*' for binary, ' ' for 45 | text), and name for each FILE. 46 | */ 47 | package main 48 | 49 | import ( 50 | "fmt" 51 | cc "github.com/fangdingjun/go-coreutils/md5sum/checksum_common" 52 | flag "github.com/ogier/pflag" 53 | "os" 54 | ) 55 | 56 | const ( 57 | Help = `Usage: md5sum [OPTION]... [FILE]... 58 | Print or check MD5 (128-bit) checksums. 59 | With no FILE, or when FILE is -, read standard input. 60 | 61 | -b, --binary read in binary mode(default) 62 | -c, --check read MD5 sums from the FILEs and check them 63 | -t, --text read in text mode 64 | Note: there is no difference between text and binary mode option. 65 | 66 | The following three options are useful only when verifying checksums: 67 | --quiet don't print OK for each successfully verified file 68 | --status don't output anything, status code shows success 69 | -w, --warn warn about improperly formated checksum lines 70 | 71 | --help show help and exit 72 | --version show version and exit 73 | 74 | The sums are computed as described in RFC 1321. When checking, the input 75 | should be a former output of this program. The default mode is to print 76 | a line with checksum, a character indicating type ('*' for binary, ' ' for 77 | text), and name for each FILE. 78 | ` 79 | Version = `md5sum (Go coreutils) 0.1 80 | Copyright (C) 2015 Dingjun Fang 81 | License GPLv3+: GNU GPL version 3 or later . 82 | This is free software: you are free to change and redistribute it. 83 | There is NO WARRANTY, to the extent permitted by law. 84 | ` 85 | ) 86 | 87 | var ( 88 | check_sum = flag.BoolP("check", "c", false, "") 89 | no_output = flag.BoolP("quiet", "q", false, "") 90 | no_output_s = flag.BoolP("status", "", false, "") 91 | show_warn = flag.BoolP("warn", "w", true, "") 92 | show_version = flag.BoolP("version", "v", false, "") 93 | text_mode = flag.BoolP("text", "t", false, "") 94 | binary_mode = flag.BoolP("binary", "b", false, "") 95 | ) 96 | 97 | func main() { 98 | flag.Usage = func() { 99 | fmt.Fprintf(os.Stderr, "%s", Help) 100 | os.Exit(1) 101 | } 102 | 103 | flag.Parse() 104 | 105 | /* trust --status and --quiet as the same */ 106 | if *no_output_s == true { 107 | *no_output = true 108 | } 109 | 110 | has_error := false 111 | 112 | file_lists := flag.Args() 113 | if len(file_lists) == 0 { 114 | file_lists = append(file_lists, "-") 115 | } 116 | 117 | switch { 118 | case *show_version: 119 | fmt.Fprintf(os.Stdout, "%s", Version) 120 | os.Exit(0) 121 | case *check_sum: 122 | if r := cc.CompareChecksum(file_lists, "md5", 123 | !(*no_output), *show_warn); !r { 124 | has_error = true 125 | } 126 | default: 127 | if r := cc.GenerateChecksum(file_lists, "md5"); !r { 128 | has_error = true 129 | } 130 | } 131 | 132 | if has_error { 133 | os.Exit(1) 134 | } 135 | 136 | os.Exit(0) 137 | } 138 | -------------------------------------------------------------------------------- /mkdir/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/mkdir/.gitignore -------------------------------------------------------------------------------- /mkdir/mkdir.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /mkfifo/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/mkfifo/.gitignore -------------------------------------------------------------------------------- /mkfifo/mkfifo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /mknod/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/mknod/.gitignore -------------------------------------------------------------------------------- /mknod/mknod.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /mktemp/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/mktemp/.gitignore -------------------------------------------------------------------------------- /mktemp/mktemp.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /mv/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/mv/.gitignore -------------------------------------------------------------------------------- /mv/mv.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /nice/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/nice/.gitignore -------------------------------------------------------------------------------- /nice/nice.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /nl/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/nl/.gitignore -------------------------------------------------------------------------------- /nl/nl.go: -------------------------------------------------------------------------------- 1 | /* 2 | This program is free software: you can redistribute it and/or modify 3 | it under the terms of the GNU General Public License version 3 as 4 | published by the Free Software Foundation. 5 | 6 | This program is distributed in the hope that it will be useful, 7 | but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | GNU General Public License for more details. 10 | 11 | You should have received a copy of the GNU General Public License 12 | along with this program. If not, see . 13 | */ 14 | 15 | package main 16 | 17 | import "os" 18 | import "fmt" 19 | import "io/ioutil" 20 | import "strings" 21 | import flag "github.com/ogier/pflag" 22 | 23 | func main() { 24 | bFlag := flag.StringP("body-numbering", "b", "t", "style") 25 | flag.Parse() 26 | if len(flag.Args()) == 0 { 27 | bytes, _ := ioutil.ReadAll(os.Stdin) 28 | lines := strings.Split(string(bytes), "\n") 29 | linecount := 0 30 | for i := 0; i < len(lines)-1; i++ { 31 | if *bFlag == "t" { 32 | if len(strings.TrimSpace(lines[i])) > 0 { 33 | linecount++ 34 | fmt.Printf("%6d %s\n", linecount, lines[i]) 35 | } else { 36 | fmt.Println(lines[i]) 37 | } 38 | } else { 39 | linecount++ 40 | fmt.Printf("%6d %s\n", linecount, lines[i]) 41 | } 42 | } 43 | } else if len(flag.Args()) > 0 { 44 | linecount := 0 45 | for j := 0; j < len(flag.Args()); j++ { 46 | bytes, _ := ioutil.ReadFile(flag.Arg(j)) 47 | lines := strings.Split(string(bytes), "\n") 48 | for i := 0; i < len(lines)-1; i++ { 49 | if *bFlag == "t" { 50 | if len(strings.TrimSpace(lines[i])) > 0 { 51 | linecount++ 52 | fmt.Printf("%6d %s\n", linecount, lines[i]) 53 | } else { 54 | fmt.Println(lines[i]) 55 | } 56 | } else { 57 | linecount++ 58 | fmt.Printf("%6d %s\n", linecount, lines[i]) 59 | } 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /nohup/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/nohup/.gitignore -------------------------------------------------------------------------------- /nohup/nohup.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /nproc/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/nproc/.gitignore -------------------------------------------------------------------------------- /nproc/nproc.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /numfmt/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/numfmt/.gitignore -------------------------------------------------------------------------------- /numfmt/numfmt.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /od/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/od/.gitignore -------------------------------------------------------------------------------- /od/od.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /paste/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/paste/.gitignore -------------------------------------------------------------------------------- /paste/paste.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /pathchk/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/pathchk/.gitignore -------------------------------------------------------------------------------- /pathchk/pathchk.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /pinky/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/pinky/.gitignore -------------------------------------------------------------------------------- /pinky/pinky.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /pr/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/pr/.gitignore -------------------------------------------------------------------------------- /pr/pr.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /printenv/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/printenv/.gitignore -------------------------------------------------------------------------------- /printenv/printenv.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /printf/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/printf/.gitignore -------------------------------------------------------------------------------- /printf/printf.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /ptx/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/ptx/.gitignore -------------------------------------------------------------------------------- /ptx/ptx.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /pwd/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/pwd/.gitignore -------------------------------------------------------------------------------- /readlink/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/readlink/.gitignore -------------------------------------------------------------------------------- /readlink/readlink.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /realpath/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/realpath/.gitignore -------------------------------------------------------------------------------- /realpath/realpath.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /rm/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/rm/.gitignore -------------------------------------------------------------------------------- /rm/cmd.go: -------------------------------------------------------------------------------- 1 | package rm 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "io" 7 | 8 | coreutils "github.com/ericlagergren/go-coreutils" 9 | flag "github.com/spf13/pflag" 10 | ) 11 | 12 | func init() { 13 | coreutils.Register("rm", run) 14 | } 15 | 16 | // Sentinal flags for default values or flags with single-character options and 17 | // without multi-character options. (e.g., if we want -i but not --i.) 18 | const ( 19 | uniNonChar = 0xFDD0 20 | interDefault = string(uniNonChar + 1) 21 | bad1 = string(uniNonChar + 2) 22 | bad2 = string(uniNonChar + 3) 23 | bad3 = string(uniNonChar + 4) 24 | ) 25 | 26 | func newCommand() *cmd { 27 | var c cmd 28 | c.f.BoolVarP(&c.force, "force", "f", false, "ignore non-existent files and arguments; never prompt prior to removal") 29 | c.f.BoolVarP(&c.moreInter, bad1, "i", false, "prompt before each removal") 30 | c.f.BoolVarP(&c.lessInter, bad2, "I", false, "prompt (once) prior to removing more than three files or when removing recursively") 31 | c.f.StringVar(&c.interactive, "interactive", interDefault, "prompt: 'never', 'once' (-i), 'always' (-I)") 32 | c.f.BoolVar(&c.oneFileSystem, "one-file-system", false, "when recursing, skip directories that are on a different filesystem") 33 | c.f.BoolVar(&c.preserveRoot, "preserve-root", true, "do not remove '/'") 34 | c.f.BoolVar(&c.noPreserveRoot, "no-preserve-root", false, "do not special-case '/'") 35 | c.f.BoolVarP(&c.recursive, "recursive", "r", false, "remove directories and their contents recursively") 36 | c.f.BoolVarP(&c.recursive, bad3, "R", false, "remove directories and their contents recursively") 37 | c.f.BoolVarP(&c.rmdir, "dir", "d", false, "remove empty directories") 38 | c.f.BoolVarP(&c.verbose, "verbose", "v", false, "explain what's occurring") 39 | c.f.BoolVar(&c.version, "version", false, "print version information and exit") 40 | return &c 41 | } 42 | 43 | type cmd struct { 44 | f flag.FlagSet 45 | force bool 46 | moreInter, lessInter bool 47 | interactive string 48 | preserveRoot bool 49 | noPreserveRoot bool 50 | oneFileSystem bool 51 | recursive bool 52 | rmdir bool 53 | verbose bool 54 | version bool 55 | } 56 | 57 | func run(ctx coreutils.Context, args ...string) error { 58 | c := newCommand() 59 | if err := c.f.Parse(args); err != nil { 60 | return err 61 | } 62 | 63 | if c.version { 64 | fmt.Fprintf(ctx.Stdout, "rm (go-coreutils) 1.0") 65 | return nil 66 | } 67 | 68 | var opts RemoveOption 69 | if c.noPreserveRoot && !c.preserveRoot { 70 | opts |= NoPreserveRoot 71 | } 72 | if c.force { 73 | opts |= Force 74 | } 75 | if c.recursive { 76 | opts |= Recursive 77 | } 78 | if c.rmdir { 79 | opts |= RemoveEmpty 80 | } 81 | if c.oneFileSystem { 82 | opts |= OneFileSystem 83 | } 84 | if c.verbose { 85 | opts |= Verbose 86 | } 87 | switch c.interactive { 88 | case interDefault: 89 | if c.moreInter { 90 | opts |= PromptAlways 91 | c.lessInter = false 92 | } 93 | case "never", "no", "none": 94 | opts &= PromptAlways 95 | case "once": 96 | c.lessInter = true 97 | opts &= IgnoreMissing 98 | case "always", "yes", "": 99 | opts |= PromptAlways 100 | opts &= IgnoreMissing 101 | default: 102 | return errors.New("unknown interactive option: " + c.interactive) 103 | } 104 | 105 | if c.lessInter && (opts&Recursive != 0 || c.f.NArg() >= 3) { 106 | n := c.f.NArg() 107 | arg := "arguments" 108 | adj := "" 109 | if opts&Recursive != 0 { 110 | adj = " recursively " 111 | if n == 1 { 112 | arg = "argument" 113 | } 114 | } 115 | fmt.Fprintf(ctx.Stderr, "rm: remove %d %s%s? ", n, arg, adj) 116 | switch yes, err := getYesNo(ctx.Stdin); { 117 | case err != nil: 118 | return err 119 | case !yes: 120 | return nil 121 | } 122 | } 123 | 124 | r := NewRemover(opts) 125 | 126 | if r.opts&PromptAlways != 0 { 127 | r.Prompt = func(name string, opts PromptOption) bool { 128 | 129 | wp := " " 130 | if opts&WriteProtected != 0 { 131 | wp = " write-protected " 132 | } 133 | 134 | msg := "rm: remove%s%s %q? " 135 | typ := "file" 136 | if opts&(Descend|Directory) != 0 { 137 | typ = "directory" 138 | if opts&Descend != 0 { 139 | msg = "rm: descend into%s%s %q? " 140 | } 141 | } 142 | 143 | fmt.Fprintf(ctx.Stderr, msg, wp, typ, name) 144 | yes, err := getYesNo(ctx.Stdin) 145 | return yes && err == nil 146 | } 147 | } 148 | 149 | if r.Log != nil { 150 | defer close(r.Log) 151 | go func() { 152 | for msg := range r.Log { 153 | fmt.Fprintln(ctx.Stdout, msg) 154 | } 155 | }() 156 | } 157 | 158 | var nerrs int 159 | for _, name := range c.f.Args() { 160 | switch err := r.Remove(name); err.(type) { 161 | case nil: 162 | // OK 163 | case rmError: 164 | fmt.Fprintf(ctx.Stderr, "rm: %v\n", err) 165 | default: 166 | fmt.Fprintf(ctx.Stderr, "rm: %v\n", err) 167 | return err 168 | } 169 | } 170 | if nerrs > 0 { 171 | return errNonFatal 172 | } 173 | return nil 174 | } 175 | 176 | var errNonFatal = errors.New("at least one non-fatal error occurred") 177 | 178 | func getYesNo(r io.Reader) (yes bool, err error) { 179 | var resp string 180 | fmt.Fscanln(r, &resp) 181 | switch resp { 182 | case "yes", "Y", "y": 183 | return true, nil 184 | case "no", "N", "n": 185 | return false, nil 186 | default: 187 | return false, errors.New("unknown response (must be 'yes' or 'no')") 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /rm/internal/sys/sys_unix.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package sys 4 | 5 | import ( 6 | "os" 7 | "syscall" 8 | ) 9 | 10 | var root *syscall.Stat_t 11 | 12 | func init() { 13 | if info, err := os.Lstat("/"); err == nil { 14 | root = info.Sys().(*syscall.Stat_t) 15 | } 16 | } 17 | 18 | func IsRoot(info os.FileInfo) bool { 19 | stat := info.Sys().(*syscall.Stat_t) 20 | return root.Ino == stat.Ino && root.Dev == stat.Dev 21 | } 22 | 23 | func DiffFS(orig, test os.FileInfo) bool { 24 | return orig.Sys().(*syscall.Stat_t).Dev != test.Sys().(*syscall.Stat_t).Dev 25 | } 26 | -------------------------------------------------------------------------------- /rm/internal/sys/sys_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package sys 4 | 5 | import "os" 6 | 7 | func IsRoot(_ os.FileInfo) bool { return false } 8 | func DiffFS(_, _ os.FileInfo) bool { return false } 9 | -------------------------------------------------------------------------------- /rm/rm.go: -------------------------------------------------------------------------------- 1 | package rm 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | "path/filepath" 8 | "runtime" 9 | 10 | "github.com/ericlagergren/go-coreutils/rm/internal/sys" 11 | "golang.org/x/sys/unix" 12 | ) 13 | 14 | type RemoveOption uint8 15 | 16 | const ( 17 | NoPreserveRoot = 1 << iota 18 | Force 19 | Recursive 20 | RemoveEmpty 21 | IgnoreMissing 22 | OneFileSystem 23 | Verbose 24 | PromptAlways 25 | ) 26 | 27 | type PromptOption uint8 28 | 29 | const ( 30 | // WriteProtected signals that the object to be removed or descended upon 31 | // has write protection. 32 | WriteProtected PromptOption = 1 << iota 33 | // Directory indicates the action is on a directory. 34 | Directory 35 | // Descend indicates the action is to descend into an object. 36 | Descend 37 | // Remove indicates the action is to remove an object. 38 | Remove 39 | ) 40 | 41 | func NewRemover(opts RemoveOption) *Remover { 42 | r := Remover{opts: opts} 43 | if opts&Verbose != 0 { 44 | r.Log = make(chan string) 45 | } 46 | return &r 47 | } 48 | 49 | type Remover struct { 50 | opts RemoveOption 51 | root os.FileInfo 52 | 53 | // Prompt, if non-nil, will be called depending on the Remover's configured 54 | // options. If it returns true, the action continues, otherwise it stops. 55 | Prompt func(name string, opts PromptOption) bool 56 | 57 | Log chan string 58 | 59 | stack []node 60 | } 61 | 62 | type node struct { 63 | path string 64 | info os.FileInfo 65 | kids int 66 | } 67 | 68 | func (r *Remover) Remove(path string) (err error) { 69 | r.root, err = os.Lstat(path) 70 | if err != nil { 71 | return err 72 | } 73 | 74 | if r.opts&Recursive == 0 || !r.root.Mode().IsDir() { 75 | if err := r.remove(path, r.root); err != nil && err != errRefused { 76 | return err 77 | } 78 | return nil 79 | } 80 | 81 | // GNU rm uses a DFS that, once it reaches a leaf node (doesn't contain any 82 | // further directories), clears out all files and "walks back" to the most 83 | // recently seen non-leaf node. This is typicall DFS behavior, but the 84 | // walking back is important: it allows the prompt for interactive usage to 85 | // look like this: 86 | // 87 | // $ mkdir a/b/c 88 | // $ touch a/b/c/d.txt 89 | // $ rm a/ 90 | // rm: descend into 'a'? 91 | // rm: descend into 'a/b'? 92 | // rm: descend into 'a/b/c'? 93 | // rm: remove file 'a/b/c/d.txt'? 94 | // rm: remove directory 'a/b/c'? 95 | // rm: remove directory 'a/b'? 96 | // rm: remove directory 'a'? 97 | // 98 | // Unfortunately, filepath.Walk doesn't allow us to walk back, so we're 99 | // forced to do a little state management ourselves. We push each directory 100 | // we encounter onto a stack. Once we hit a leaf node, we manually work our 101 | // way back by popping every consecutive leaf node off the stack, removing 102 | // it as we go. Since filepath.Walk doesn't work backwards, this works. 103 | // 104 | // A major downside is the requirement of determining how many objects are 105 | // in a directory. This means Stat will be called twice for each directory: 106 | // once for filepath.Walk, once for us. Same goes for Readdirnames. 107 | return filepath.Walk(path, func(path string, info os.FileInfo, err error) error { 108 | if err != nil { 109 | return err 110 | } 111 | 112 | if info.IsDir() { 113 | if !r.prompt(path, Descend) { 114 | return filepath.SkipDir 115 | } 116 | dir, err := os.Open(path) 117 | if err != nil { 118 | return err 119 | } 120 | files, err := dir.Readdirnames(-1) 121 | if err != nil { 122 | return err 123 | } 124 | r.stack = append(r.stack, node{path: path, info: info, kids: len(files)}) 125 | return dir.Close() 126 | } 127 | 128 | err = r.remove(path, info) 129 | 130 | // Work our way down the r.stack. 131 | for i := len(r.stack) - 1; i >= 0; i-- { 132 | s := &r.stack[i] 133 | s.kids-- 134 | if s.kids != 0 { 135 | r.stack = r.stack[:i+1] 136 | break 137 | } 138 | if err := r.remove(s.path, s.info); err != nil && err != errRefused { 139 | return err 140 | } 141 | } 142 | 143 | if err != nil && err != errRefused { 144 | return err 145 | } 146 | return nil 147 | }) 148 | } 149 | 150 | var errRefused = errors.New("user refused prompt") 151 | 152 | type rmError struct{ msg string } 153 | 154 | func (r rmError) Error() string { return r.msg } 155 | 156 | func (r *Remover) prompt(name string, opts PromptOption) bool { 157 | if r.opts&PromptAlways != 0 && r.Prompt != nil { 158 | return r.Prompt(name, opts) 159 | } 160 | return true 161 | } 162 | 163 | func (r *Remover) rm(name string, dir bool) (err error) { 164 | opts := Remove 165 | if dir { 166 | opts |= Directory 167 | } 168 | if !r.prompt(name, opts) { 169 | return errRefused 170 | } 171 | 172 | switch runtime.GOOS { 173 | case "windows", "plan9": 174 | err = os.Remove(name) 175 | default: 176 | // For unix systems, os.Remove is a call to Unlink followed by a call to 177 | // Rmdir. Since os.Remove doesn't know whether the object is a file or 178 | // directory, this provides better performance in the common case. But, 179 | // since we know the type of the object ahead of time, we can simply call 180 | // the proper syscall. 181 | if !dir { 182 | err = unix.Unlink(name) 183 | } else { 184 | err = unix.Rmdir(name) 185 | } 186 | if err != nil { 187 | err = &os.PathError{Op: "remove", Path: name, Err: err} 188 | } 189 | } 190 | if err != nil && (r.opts&IgnoreMissing == 0 || !os.IsNotExist(err)) { 191 | return err 192 | } 193 | if r.opts&Verbose != 0 { 194 | if dir { 195 | r.Log <- fmt.Sprintf("removed directory %s") 196 | } else { 197 | r.Log <- fmt.Sprintf("removed %s") 198 | } 199 | } 200 | return nil 201 | } 202 | 203 | func (r *Remover) remove(path string, info os.FileInfo) error { 204 | if info.Mode()&os.ModeDir != 0 { 205 | switch info.Name() { 206 | // POSIX doesn't let us do anything with . or .. 207 | case ".", "..": 208 | return rmError{msg: "cannot remove '.' or '..'"} 209 | case "/": 210 | return rmError{msg: "cannot remove root directory"} 211 | default: 212 | if r.opts&NoPreserveRoot == 0 && sys.IsRoot(info) { 213 | return rmError{msg: "cannot remove root directory"} 214 | } 215 | } 216 | if r.opts&Recursive == 0 && (r.opts&RemoveEmpty == 0 || isEmpty(path)) { 217 | return rmError{msg: fmt.Sprintf("cannot remove directory: %q", path)} 218 | } 219 | return r.rm(path, true) 220 | } 221 | if r.opts&OneFileSystem != 0 && sys.DiffFS(r.root, info) { 222 | return rmError{msg: "cannot recurse into a different filesystem"} 223 | } 224 | return r.rm(path, false) 225 | } 226 | 227 | func isEmpty(path string) bool { 228 | file, err := os.Open(path) 229 | if err != nil { 230 | return false 231 | } 232 | defer file.Close() 233 | names, err := file.Readdirnames(1) 234 | return len(names) != 0 && err == nil 235 | } 236 | -------------------------------------------------------------------------------- /rmdir/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/rmdir/.gitignore -------------------------------------------------------------------------------- /rmdir/rmdir.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /runcon/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/runcon/.gitignore -------------------------------------------------------------------------------- /runcon/runcon.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /seq/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/seq/.gitignore -------------------------------------------------------------------------------- /seq/seq.go: -------------------------------------------------------------------------------- 1 | /* 2 | This program is free software: you can redistribute it and/or modify 3 | it under the terms of the GNU General Public License version 3 as 4 | published by the Free Software Foundation. 5 | 6 | This program is distributed in the hope that it will be useful, 7 | but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | GNU General Public License for more details. 10 | 11 | You should have received a copy of the GNU General Public License 12 | along with this program. If not, see . 13 | */ 14 | 15 | package main 16 | 17 | import ( 18 | "os" 19 | "strconv" 20 | ) 21 | import "fmt" 22 | 23 | func main() { 24 | // TODO: Also handle floats. 25 | start, inc, end := 1, 1, 0 26 | nargs := len(os.Args) 27 | switch nargs { 28 | case 4: 29 | inc = parseInt(os.Args[2]) 30 | fallthrough 31 | case 3: 32 | start = parseInt(os.Args[1]) 33 | fallthrough 34 | case 2: 35 | end = parseInt(os.Args[nargs-1]) 36 | default: 37 | msg := "missing operand" 38 | if nargs > 4 { 39 | msg = fmt.Sprintf("extra operand '%s'", os.Args[4]) 40 | } 41 | fmt.Println("seq:", msg) 42 | os.Exit(1) 43 | } 44 | 45 | for i := start; i <= end; i += inc { 46 | fmt.Println(i) 47 | } 48 | } 49 | 50 | func parseInt(a string) int { 51 | i, err := strconv.Atoi(a) 52 | if err != nil { 53 | fmt.Println("seq:", err) 54 | os.Exit(1) 55 | } 56 | return i 57 | } 58 | -------------------------------------------------------------------------------- /sha1sum/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/sha1sum/.gitignore -------------------------------------------------------------------------------- /sha1sum/sha1sum.go: -------------------------------------------------------------------------------- 1 | /* 2 | go sha1sum 3 | 4 | Copyright (c) 2014-2015 Dingjun Fang 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License version 3 as 8 | published by the Free Software Foundation. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | /* 20 | 21 | Sha1sum util implement by go. 22 | 23 | Usage: sha1sum [OPTION]... [FILE]... 24 | 25 | Print or check SHA1 (160-bit) checksums. 26 | 27 | With no FILE, or when FILE is -, read standard input. 28 | 29 | -b, --binary read in binary mode(default) 30 | -c, --check read SHA1 sums from the FILEs and check them 31 | -t, --text read in text mode 32 | Note: there is no difference between text and binary mode option. 33 | 34 | The following three options are useful only when verifying checksums: 35 | --quiet don't print OK for each successfully verified file 36 | --status don't output anything, status code shows success 37 | -w, --warn warn about improperly formated checksum lines 38 | 39 | --help show help and exit 40 | --version show version and exit 41 | 42 | The sums are computed as described in FIPS-180-1. When checking, the input 43 | should be a former output of this program. The default mode is to print 44 | a line with checksum, a character indicating type ('*' for binary, ' ' for 45 | text), and name for each FILE. 46 | */ 47 | package main 48 | 49 | import ( 50 | "fmt" 51 | cc "github.com/fangdingjun/go-coreutils/md5sum/checksum_common" 52 | flag "github.com/ogier/pflag" 53 | "os" 54 | ) 55 | 56 | const ( 57 | Help = `Usage: sha1sum [OPTION]... [FILE]... 58 | Print or check SHA1 (160-bit) checksums. 59 | With no FILE, or when FILE is -, read standard input. 60 | 61 | -b, --binary read in binary mode(default) 62 | -c, --check read SHA1 sums from the FILEs and check them 63 | -t, --text read in text mode 64 | Note: there is no difference between text and binary mode option. 65 | 66 | The following three options are useful only when verifying checksums: 67 | --quiet don't print OK for each successfully verified file 68 | --status don't output anything, status code shows success 69 | -w, --warn warn about improperly formated checksum lines 70 | 71 | --help show help and exit 72 | --version show version and exit 73 | 74 | The sums are computed as described in FIPS-180-1. When checking, the input 75 | should be a former output of this program. The default mode is to print 76 | a line with checksum, a character indicating type ('*' for binary, ' ' for 77 | text), and name for each FILE. 78 | ` 79 | Version = `sha1sum (Go coreutils) 0.1 80 | Copyright (C) 2015 Dingjun Fang 81 | License GPLv3+: GNU GPL version 3 or later . 82 | This is free software: you are free to change and redistribute it. 83 | There is NO WARRANTY, to the extent permitted by law. 84 | ` 85 | ) 86 | 87 | var ( 88 | check_sum = flag.BoolP("check", "c", false, "") 89 | no_output = flag.BoolP("quiet", "q", false, "") 90 | no_output_s = flag.BoolP("status", "", false, "") 91 | show_warn = flag.BoolP("warn", "w", true, "") 92 | show_version = flag.BoolP("version", "v", false, "") 93 | text_mode = flag.BoolP("text", "t", false, "") 94 | binary_mode = flag.BoolP("binary", "b", false, "") 95 | ) 96 | 97 | func main() { 98 | flag.Usage = func() { 99 | fmt.Fprintf(os.Stderr, "%s", Help) 100 | os.Exit(1) 101 | } 102 | 103 | flag.Parse() 104 | 105 | /* trust --status and --quiet as the same */ 106 | if *no_output_s == true { 107 | *no_output = true 108 | } 109 | 110 | has_error := false 111 | 112 | file_lists := flag.Args() 113 | if len(file_lists) == 0 { 114 | file_lists = append(file_lists, "-") 115 | } 116 | 117 | switch { 118 | case *show_version: 119 | fmt.Fprintf(os.Stdout, "%s", Version) 120 | os.Exit(0) 121 | case *check_sum: 122 | if r := cc.CompareChecksum(file_lists, "sha1", 123 | !(*no_output), *show_warn); !r { 124 | has_error = true 125 | } 126 | default: 127 | if r := cc.GenerateChecksum(file_lists, "sha1"); !r { 128 | has_error = true 129 | } 130 | } 131 | 132 | if has_error { 133 | os.Exit(1) 134 | } 135 | 136 | os.Exit(0) 137 | } 138 | -------------------------------------------------------------------------------- /sha224sum/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/sha224sum/.gitignore -------------------------------------------------------------------------------- /sha224sum/sha224sum.go: -------------------------------------------------------------------------------- 1 | /* 2 | go sha224sum 3 | 4 | Copyright (c) 2014-2015 Dingjun Fang 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License version 3 as 8 | published by the Free Software Foundation. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | /* 20 | 21 | Sha224sum util implement by go. 22 | 23 | Usage: sha224sum [OPTION]... [FILE]... 24 | 25 | Print or check SHA224 (224-bit) checksums. 26 | 27 | With no FILE, or when FILE is -, read standard input. 28 | 29 | -b, --binary read in binary mode(default) 30 | -c, --check read SHA224 sums from the FILEs and check them 31 | -t, --text read in text mode 32 | Note: there is no difference between text and binary mode option. 33 | 34 | The following three options are useful only when verifying checksums: 35 | --quiet don't print OK for each successfully verified file 36 | --status don't output anything, status code shows success 37 | -w, --warn warn about improperly formated checksum lines 38 | 39 | --help show help and exit 40 | --version show version and exit 41 | 42 | The sums are computed as described in RFC 3874. When checking, the input 43 | should be a former output of this program. The default mode is to print 44 | a line with checksum, a character indicating type ('*' for binary, ' ' for 45 | text), and name for each FILE. 46 | */ 47 | package main 48 | 49 | import ( 50 | "fmt" 51 | cc "github.com/fangdingjun/go-coreutils/md5sum/checksum_common" 52 | flag "github.com/ogier/pflag" 53 | "os" 54 | ) 55 | 56 | const ( 57 | Help = `Usage: sha224sum [OPTION]... [FILE]... 58 | Print or check SHA224 (224-bit) checksums. 59 | With no FILE, or when FILE is -, read standard input. 60 | 61 | -b, --binary read in binary mode(default) 62 | -c, --check read SHA224 sums from the FILEs and check them 63 | -t, --text read in text mode 64 | Note: there is no difference between text and binary mode option. 65 | 66 | The following three options are useful only when verifying checksums: 67 | --quiet don't print OK for each successfully verified file 68 | --status don't output anything, status code shows success 69 | -w, --warn warn about improperly formated checksum lines 70 | 71 | --help show help and exit 72 | --version show version and exit 73 | 74 | The sums are computed as described in RFC 3874. When checking, the input 75 | should be a former output of this program. The default mode is to print 76 | a line with checksum, a character indicating type ('*' for binary, ' ' for 77 | text), and name for each FILE. 78 | ` 79 | Version = `sha224sum (Go coreutils) 0.1 80 | Copyright (C) 2015 Dingjun Fang 81 | License GPLv3+: GNU GPL version 3 or later . 82 | This is free software: you are free to change and redistribute it. 83 | There is NO WARRANTY, to the extent permitted by law. 84 | ` 85 | ) 86 | 87 | var ( 88 | check_sum = flag.BoolP("check", "c", false, "") 89 | no_output = flag.BoolP("quiet", "q", false, "") 90 | no_output_s = flag.BoolP("status", "", false, "") 91 | show_warn = flag.BoolP("warn", "w", true, "") 92 | show_version = flag.BoolP("version", "v", false, "") 93 | text_mode = flag.BoolP("text", "t", false, "") 94 | binary_mode = flag.BoolP("binary", "b", false, "") 95 | ) 96 | 97 | func main() { 98 | flag.Usage = func() { 99 | fmt.Fprintf(os.Stderr, "%s", Help) 100 | os.Exit(1) 101 | } 102 | 103 | flag.Parse() 104 | 105 | /* trust --status and --quiet as the same */ 106 | if *no_output_s == true { 107 | *no_output = true 108 | } 109 | 110 | has_error := false 111 | 112 | file_lists := flag.Args() 113 | if len(file_lists) == 0 { 114 | file_lists = append(file_lists, "-") 115 | } 116 | 117 | switch { 118 | case *show_version: 119 | fmt.Fprintf(os.Stdout, "%s", Version) 120 | os.Exit(0) 121 | case *check_sum: 122 | if r := cc.CompareChecksum(file_lists, "sha224", 123 | !(*no_output), *show_warn); !r { 124 | has_error = true 125 | } 126 | default: 127 | if r := cc.GenerateChecksum(file_lists, "sha224"); !r { 128 | has_error = true 129 | } 130 | } 131 | 132 | if has_error { 133 | os.Exit(1) 134 | } 135 | 136 | os.Exit(0) 137 | } 138 | -------------------------------------------------------------------------------- /sha256sum/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/sha256sum/.gitignore -------------------------------------------------------------------------------- /sha256sum/sha256sum.go: -------------------------------------------------------------------------------- 1 | /* 2 | go sha256sum 3 | 4 | Copyright (c) 2014-2015 Dingjun Fang 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License version 3 as 8 | published by the Free Software Foundation. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | /* 20 | 21 | Sha256sum util implement by go. 22 | 23 | Usage: sha256sum [OPTION]... [FILE]... 24 | 25 | Print or check SHA256 (256-bit) checksums. 26 | 27 | With no FILE, or when FILE is -, read standard input. 28 | 29 | -b, --binary read in binary mode(default) 30 | -c, --check read SHA256 sums from the FILEs and check them 31 | -t, --text read in text mode 32 | Note: there is no difference between text and binary mode option. 33 | 34 | The following three options are useful only when verifying checksums: 35 | --quiet don't print OK for each successfully verified file 36 | --status don't output anything, status code shows success 37 | -w, --warn warn about improperly formated checksum lines 38 | 39 | --help show help and exit 40 | --version show version and exit 41 | 42 | The sums are computed as described in FIPS-180-2. When checking, the input 43 | should be a former output of this program. The default mode is to print 44 | a line with checksum, a character indicating type ('*' for binary, ' ' for 45 | text), and name for each FILE. 46 | */ 47 | package main 48 | 49 | import ( 50 | "fmt" 51 | cc "github.com/fangdingjun/go-coreutils/md5sum/checksum_common" 52 | flag "github.com/ogier/pflag" 53 | "os" 54 | ) 55 | 56 | const ( 57 | Help = `Usage: sha256sum [OPTION]... [FILE]... 58 | Print or check SHA256 (256-bit) checksums. 59 | With no FILE, or when FILE is -, read standard input. 60 | 61 | -b, --binary read in binary mode(default) 62 | -c, --check read SHA256 sums from the FILEs and check them 63 | -t, --text read in text mode 64 | Note: there is no difference between text and binary mode option. 65 | 66 | The following three options are useful only when verifying checksums: 67 | --quiet don't print OK for each successfully verified file 68 | --status don't output anything, status code shows success 69 | -w, --warn warn about improperly formated checksum lines 70 | 71 | --help show help and exit 72 | --version show version and exit 73 | 74 | The sums are computed as described in FIPS-180-2. When checking, the input 75 | should be a former output of this program. The default mode is to print 76 | a line with checksum, a character indicating type ('*' for binary, ' ' for 77 | text), and name for each FILE. 78 | ` 79 | Version = `sha256sum (Go coreutils) 0.1 80 | Copyright (C) 2015 Dingjun Fang 81 | License GPLv3+: GNU GPL version 3 or later . 82 | This is free software: you are free to change and redistribute it. 83 | There is NO WARRANTY, to the extent permitted by law. 84 | ` 85 | ) 86 | 87 | var ( 88 | check_sum = flag.BoolP("check", "c", false, "") 89 | no_output = flag.BoolP("quiet", "q", false, "") 90 | no_output_s = flag.BoolP("status", "", false, "") 91 | show_warn = flag.BoolP("warn", "w", true, "") 92 | show_version = flag.BoolP("version", "v", false, "") 93 | text_mode = flag.BoolP("text", "t", false, "") 94 | binary_mode = flag.BoolP("binary", "b", false, "") 95 | ) 96 | 97 | func main() { 98 | flag.Usage = func() { 99 | fmt.Fprintf(os.Stderr, "%s", Help) 100 | os.Exit(1) 101 | } 102 | 103 | flag.Parse() 104 | 105 | /* trust --status and --quiet as the same */ 106 | if *no_output_s == true { 107 | *no_output = true 108 | } 109 | 110 | has_error := false 111 | 112 | file_lists := flag.Args() 113 | if len(file_lists) == 0 { 114 | file_lists = append(file_lists, "-") 115 | } 116 | 117 | switch { 118 | case *show_version: 119 | fmt.Fprintf(os.Stdout, "%s", Version) 120 | os.Exit(0) 121 | case *check_sum: 122 | if r := cc.CompareChecksum(file_lists, "sha256", 123 | !(*no_output), *show_warn); !r { 124 | has_error = true 125 | } 126 | default: 127 | if r := cc.GenerateChecksum(file_lists, "sha256"); !r { 128 | has_error = true 129 | } 130 | } 131 | 132 | if has_error { 133 | os.Exit(1) 134 | } 135 | 136 | os.Exit(0) 137 | } 138 | -------------------------------------------------------------------------------- /sha384sum/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/sha384sum/.gitignore -------------------------------------------------------------------------------- /sha384sum/sha384sum.go: -------------------------------------------------------------------------------- 1 | /* 2 | go sha384sum 3 | 4 | Copyright (c) 2014-2015 Dingjun Fang 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License version 3 as 8 | published by the Free Software Foundation. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | /* 20 | 21 | Sha384sum util implement by go. 22 | 23 | Usage: sha384sum [OPTION]... [FILE]... 24 | 25 | Print or check SHA384 (384-bit) checksums. 26 | 27 | With no FILE, or when FILE is -, read standard input. 28 | 29 | -b, --binary read in binary mode(default) 30 | -c, --check read SHA384 sums from the FILEs and check them 31 | -t, --text read in text mode 32 | Note: there is no difference between text and binary mode option. 33 | 34 | The following three options are useful only when verifying checksums: 35 | --quiet don't print OK for each successfully verified file 36 | --status don't output anything, status code shows success 37 | -w, --warn warn about improperly formated checksum lines 38 | 39 | --help show help and exit 40 | --version show version and exit 41 | 42 | The sums are computed as described in FIPS-180-2. When checking, the input 43 | should be a former output of this program. The default mode is to print 44 | a line with checksum, a character indicating type ('*' for binary, ' ' for 45 | text), and name for each FILE. 46 | */ 47 | package main 48 | 49 | import ( 50 | "fmt" 51 | cc "github.com/fangdingjun/go-coreutils/md5sum/checksum_common" 52 | flag "github.com/ogier/pflag" 53 | "os" 54 | ) 55 | 56 | const ( 57 | Help = `Usage: sha384sum [OPTION]... [FILE]... 58 | Print or check SHA384 (384-bit) checksums. 59 | With no FILE, or when FILE is -, read standard input. 60 | 61 | -b, --binary read in binary mode(default) 62 | -c, --check read SHA384 sums from the FILEs and check them 63 | -t, --text read in text mode 64 | Note: there is no difference between text and binary mode option. 65 | 66 | The following three options are useful only when verifying checksums: 67 | --quiet don't print OK for each successfully verified file 68 | --status don't output anything, status code shows success 69 | -w, --warn warn about improperly formated checksum lines 70 | 71 | --help show help and exit 72 | --version show version and exit 73 | 74 | The sums are computed as described in FIPS-180-2. When checking, the input 75 | should be a former output of this program. The default mode is to print 76 | a line with checksum, a character indicating type ('*' for binary, ' ' for 77 | text), and name for each FILE. 78 | ` 79 | Version = `sha384sum (Go coreutils) 0.1 80 | Copyright (C) 2015 Dingjun Fang 81 | License GPLv3+: GNU GPL version 3 or later . 82 | This is free software: you are free to change and redistribute it. 83 | There is NO WARRANTY, to the extent permitted by law. 84 | ` 85 | ) 86 | 87 | var ( 88 | check_sum = flag.BoolP("check", "c", false, "") 89 | no_output = flag.BoolP("quiet", "q", false, "") 90 | no_output_s = flag.BoolP("status", "", false, "") 91 | show_warn = flag.BoolP("warn", "w", true, "") 92 | show_version = flag.BoolP("version", "v", false, "") 93 | text_mode = flag.BoolP("text", "t", false, "") 94 | binary_mode = flag.BoolP("binary", "b", false, "") 95 | ) 96 | 97 | func main() { 98 | flag.Usage = func() { 99 | fmt.Fprintf(os.Stderr, "%s", Help) 100 | os.Exit(1) 101 | } 102 | 103 | flag.Parse() 104 | 105 | /* trust --status and --quiet as the same */ 106 | if *no_output_s == true { 107 | *no_output = true 108 | } 109 | 110 | has_error := false 111 | 112 | file_lists := flag.Args() 113 | if len(file_lists) == 0 { 114 | file_lists = append(file_lists, "-") 115 | } 116 | 117 | switch { 118 | case *show_version: 119 | fmt.Fprintf(os.Stdout, "%s", Version) 120 | os.Exit(0) 121 | case *check_sum: 122 | if r := cc.CompareChecksum(file_lists, "sha384", 123 | !(*no_output), *show_warn); !r { 124 | has_error = true 125 | } 126 | default: 127 | if r := cc.GenerateChecksum(file_lists, "sha384"); !r { 128 | has_error = true 129 | } 130 | } 131 | 132 | if has_error { 133 | os.Exit(1) 134 | } 135 | 136 | os.Exit(0) 137 | } 138 | -------------------------------------------------------------------------------- /sha512sum/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/sha512sum/.gitignore -------------------------------------------------------------------------------- /sha512sum/sha512sum.go: -------------------------------------------------------------------------------- 1 | /* 2 | go sha512sum 3 | 4 | Copyright (c) 2014-2015 Dingjun Fang 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License version 3 as 8 | published by the Free Software Foundation. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | /* 20 | 21 | Sha512sum util implement by go. 22 | 23 | Usage: sha512sum [OPTION]... [FILE]... 24 | 25 | Print or check SHA512 (512-bit) checksums. 26 | 27 | With no FILE, or when FILE is -, read standard input. 28 | 29 | -b, --binary read in binary mode(default) 30 | -c, --check read SHA512 sums from the FILEs and check them 31 | -t, --text read in text mode 32 | Note: there is no difference between text and binary mode option. 33 | 34 | The following three options are useful only when verifying checksums: 35 | --quiet don't print OK for each successfully verified file 36 | --status don't output anything, status code shows success 37 | -w, --warn warn about improperly formated checksum lines 38 | 39 | --help show help and exit 40 | --version show version and exit 41 | 42 | The sums are computed as described in FIPS-180-2. When checking, the input 43 | should be a former output of this program. The default mode is to print 44 | a line with checksum, a character indicating type ('*' for binary, ' ' for 45 | text), and name for each FILE. 46 | */ 47 | package main 48 | 49 | import ( 50 | "fmt" 51 | cc "github.com/fangdingjun/go-coreutils/md5sum/checksum_common" 52 | flag "github.com/ogier/pflag" 53 | "os" 54 | ) 55 | 56 | const ( 57 | Help = `Usage: sha512sum [OPTION]... [FILE]... 58 | Print or check SHA512 (512-bit) checksums. 59 | With no FILE, or when FILE is -, read standard input. 60 | 61 | -b, --binary read in binary mode(default) 62 | -c, --check read SHA512 sums from the FILEs and check them 63 | -t, --text read in text mode 64 | Note: there is no difference between text and binary mode option. 65 | 66 | The following three options are useful only when verifying checksums: 67 | --quiet don't print OK for each successfully verified file 68 | --status don't output anything, status code shows success 69 | -w, --warn warn about improperly formated checksum lines 70 | 71 | --help show help and exit 72 | --version show version and exit 73 | 74 | The sums are computed as described in FIPS-180-2. When checking, the input 75 | should be a former output of this program. The default mode is to print 76 | a line with checksum, a character indicating type ('*' for binary, ' ' for 77 | text), and name for each FILE. 78 | ` 79 | Version = `sha512sum (Go coreutils) 0.1 80 | Copyright (C) 2015 Dingjun Fang 81 | License GPLv3+: GNU GPL version 3 or later . 82 | This is free software: you are free to change and redistribute it. 83 | There is NO WARRANTY, to the extent permitted by law. 84 | ` 85 | ) 86 | 87 | var ( 88 | check_sum = flag.BoolP("check", "c", false, "") 89 | no_output = flag.BoolP("quiet", "q", false, "") 90 | no_output_s = flag.BoolP("status", "", false, "") 91 | show_warn = flag.BoolP("warn", "w", true, "") 92 | show_version = flag.BoolP("version", "v", false, "") 93 | text_mode = flag.BoolP("text", "t", false, "") 94 | binary_mode = flag.BoolP("binary", "b", false, "") 95 | ) 96 | 97 | func main() { 98 | flag.Usage = func() { 99 | fmt.Fprintf(os.Stderr, "%s", Help) 100 | os.Exit(1) 101 | } 102 | 103 | flag.Parse() 104 | 105 | /* trust --status and --quiet as the same */ 106 | if *no_output_s == true { 107 | *no_output = true 108 | } 109 | 110 | has_error := false 111 | 112 | file_lists := flag.Args() 113 | if len(file_lists) == 0 { 114 | file_lists = append(file_lists, "-") 115 | } 116 | 117 | switch { 118 | case *show_version: 119 | fmt.Fprintf(os.Stdout, "%s", Version) 120 | os.Exit(0) 121 | case *check_sum: 122 | if r := cc.CompareChecksum(file_lists, "sha512", 123 | !(*no_output), *show_warn); !r { 124 | has_error = true 125 | } 126 | default: 127 | if r := cc.GenerateChecksum(file_lists, "sha512"); !r { 128 | has_error = true 129 | } 130 | } 131 | 132 | if has_error { 133 | os.Exit(1) 134 | } 135 | 136 | os.Exit(0) 137 | } 138 | -------------------------------------------------------------------------------- /shred/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/shred/.gitignore -------------------------------------------------------------------------------- /shred/shred.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /shuf/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/shuf/.gitignore -------------------------------------------------------------------------------- /shuf/shuf.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /sleep/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/sleep/.gitignore -------------------------------------------------------------------------------- /sleep/sleep.go: -------------------------------------------------------------------------------- 1 | /* 2 | This program is free software: you can redistribute it and/or modify 3 | it under the terms of the GNU General Public License version 3 as 4 | published by the Free Software Foundation. 5 | 6 | This program is distributed in the hope that it will be useful, 7 | but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | GNU General Public License for more details. 10 | 11 | You should have received a copy of the GNU General Public License 12 | along with this program. If not, see . 13 | */ 14 | 15 | package main 16 | 17 | import "time" 18 | import "os" 19 | import "strconv" 20 | 21 | func main() { 22 | if len(os.Args) >= 2 { 23 | duration, err := strconv.ParseInt(os.Args[1], 0, 64) 24 | if err != nil || duration < 0 { 25 | os.Exit(1) 26 | } 27 | time.Sleep(time.Duration(duration) * time.Second) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /sort/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/sort/.gitignore -------------------------------------------------------------------------------- /sort/sort.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /split/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/split/.gitignore -------------------------------------------------------------------------------- /split/split.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /stat/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/stat/.gitignore -------------------------------------------------------------------------------- /stat/stat.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /stdbuf/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/stdbuf/.gitignore -------------------------------------------------------------------------------- /stdbuf/stdbuf.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /stty/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/stty/.gitignore -------------------------------------------------------------------------------- /stty/stty.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /sum/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/sum/.gitignore -------------------------------------------------------------------------------- /sum/sum.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /sync/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/sync/.gitignore -------------------------------------------------------------------------------- /sync/sync_linux.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "syscall" 7 | 8 | flag "github.com/ogier/pflag" 9 | ) 10 | 11 | const ( 12 | Help = `Usage: sync [OPTION] 13 | Force changed blocks to disk, update the super block. 14 | 15 | --help display this help and exit 16 | --version output version information and exit 17 | 18 | Report wc bugs to ericscottlagergren@gmail.com 19 | Go coreutils home page: 20 | ` 21 | Version = `sync (coreutils) 1 22 | Copyright (C) 2015 Eric Lagergren. 23 | License GPLv3+: GNU GPL version 3 or later . 24 | This is free software: you are free to change and redistribute it. 25 | There is NO WARRANTY, to the extent permitted by law. 26 | 27 | Written by Eric Lagergren 28 | ` 29 | ) 30 | 31 | var version = flag.BoolP("version", "v", false, "") 32 | 33 | func main() { 34 | flag.Usage = func() { 35 | fmt.Fprintf(os.Stderr, "%s", Help) 36 | os.Exit(1) 37 | } 38 | flag.Parse() 39 | 40 | // Nothing can fail. 41 | syscall.Sync() 42 | } 43 | -------------------------------------------------------------------------------- /sync/sync_windows.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | "path/filepath" 8 | "syscall" 9 | 10 | flag "github.com/ogier/pflag" 11 | ) 12 | 13 | const ( 14 | Help = `Usage: sync [OPTION] 15 | Force changed blocks to disk, update the super block. 16 | 17 | --help display this help and exit 18 | --version output version information and exit 19 | 20 | Report wc bugs to ericscottlagergren@gmail.com 21 | Go coreutils home page: 22 | ` 23 | Version = `sync (coreutils) 1 24 | Copyright (C) 2015 Eric Lagergren. 25 | License GPLv3+: GNU GPL version 3 or later . 26 | This is free software: you are free to change and redistribute it. 27 | There is NO WARRANTY, to the extent permitted by law. 28 | 29 | Written by Eric Lagergren 30 | ` 31 | ) 32 | 33 | var ( 34 | version = flag.BoolP("version", "v", false, "") 35 | fatal = log.New(os.Stderr, "", 0) 36 | ) 37 | 38 | func main() { 39 | flag.Usage = func() { 40 | fmt.Fprintf(os.Stderr, "%s", Help) 41 | os.Exit(1) 42 | } 43 | flag.Parse() 44 | 45 | dir, err := os.Getwd() 46 | if err != nil { 47 | fatal.Fatalln(err) 48 | } 49 | 50 | // "To flush all open files on a volume, call FlushFileBuffers with a handle to the volume. 51 | // The caller must have administrative privileges. For more information, see Running with Special Privileges." 52 | // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364439(v=vs.85).aspx 53 | fp := filepath.VolumeName(dir) 54 | file, err := os.Open(fp) 55 | if err != nil { 56 | fatal.Fatalln(err) 57 | } 58 | 59 | err = syscall.Fsync(syscall.Handle(file.Fd())) 60 | if err != nil { 61 | fatal.Fatalln(err) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /tac/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/tac/.gitignore -------------------------------------------------------------------------------- /tac/tac.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /tail/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/tail/.gitignore -------------------------------------------------------------------------------- /tail/tail.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /tee/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/tee/.gitignore -------------------------------------------------------------------------------- /tee/tee.go: -------------------------------------------------------------------------------- 1 | /* 2 | This program is free software: you can redistribute it and/or modify 3 | it under the terms of the GNU General Public License version 3 as 4 | published by the Free Software Foundation. 5 | 6 | This program is distributed in the hope that it will be useful, 7 | but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | GNU General Public License for more details. 10 | 11 | You should have received a copy of the GNU General Public License 12 | along with this program. If not, see . 13 | */ 14 | 15 | package main 16 | 17 | import "os" 18 | import "fmt" 19 | import "io/ioutil" 20 | import flag "github.com/ogier/pflag" 21 | import "log" 22 | 23 | func main() { 24 | flagAppend := flag.BoolP("append", "a", false, "append to file") 25 | flag.Parse() 26 | bytes, _ := ioutil.ReadAll(os.Stdin) 27 | for i := 0; i < len(flag.Args()); i++ { 28 | if *flagAppend { 29 | f, err := os.OpenFile(flag.Args()[i], os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) 30 | if err != nil { 31 | log.Fatal(err) 32 | } 33 | f.Write(bytes) 34 | f.Close() 35 | } else { 36 | f, err := os.OpenFile(flag.Args()[i], os.O_WRONLY|os.O_CREATE, 0644) 37 | if err != nil { 38 | log.Fatal(err) 39 | } 40 | f.Write(bytes) 41 | f.Close() 42 | } 43 | } 44 | fmt.Printf("%s", string(bytes)) 45 | } 46 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/test/.gitignore -------------------------------------------------------------------------------- /test/test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /timeout/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/timeout/.gitignore -------------------------------------------------------------------------------- /timeout/timeout.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /touch/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/touch/.gitignore -------------------------------------------------------------------------------- /touch/touch.go: -------------------------------------------------------------------------------- 1 | /* 2 | Go touch - prints the current working directory. 3 | Copyright (C) 2015 Robert Deusser 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | /* 17 | Written by Robert Deusser 18 | */ 19 | 20 | package main 21 | 22 | import ( 23 | "fmt" 24 | "log" 25 | "os" 26 | "time" 27 | 28 | flag "github.com/ogier/pflag" 29 | ) 30 | 31 | const ( 32 | Help = ` 33 | Usage: touch [OPTION]... FILE... 34 | Update the access and modification times of each FILE to the current time. 35 | 36 | A FILE argument that does not exist is created empty, unless -c or -h 37 | is supplied. 38 | 39 | A FILE argument string of - is handled specially and causes touch to 40 | change the times of the file associated with standard output. 41 | 42 | Mandatory arguments to long options are mandatory for short options too. 43 | -a change only the access time 44 | -c, --no-create do not create any files 45 | -d, --date=STRING parse STRING and use it instead of current time 46 | -f (ignored) 47 | -h, --no-dereference affect each symbolic link instead of any referenced 48 | file (useful only on systems that can change the 49 | timestamps of a symlink) 50 | -m change only the modification time 51 | -r, --reference=FILE use this file's times instead of current time 52 | -t STAMP use [[CC]YY]MMDDhhmm[.ss] instead of current time 53 | --time=WORD change the specified time: 54 | WORD is access, atime, or use: equivalent to -a 55 | WORD is modify or mtime: equivalent to -m 56 | --help display this help and exit 57 | --version output version information and exit 58 | 59 | Note that the -d and -t options accept different time-date formats. 60 | 61 | ` 62 | Version = ` 63 | touch (Go coreutils) 0.1 64 | Copyright (C) 2015 Robert Deusser 65 | License GPLv3+: GNU GPL version 3 or later . 66 | This is free software: you are free to change and redistribute it. 67 | There is NO WARRANTY, to the extent permitted by law. 68 | 69 | ` 70 | ) 71 | 72 | var ( 73 | nocreate = flag.BoolP("no-create", "c", false, "") 74 | version = flag.BoolP("version", "v", false, "") 75 | ) 76 | 77 | func main() { 78 | flag.Usage = func() { 79 | fmt.Fprintf(os.Stderr, "%s", Help) 80 | os.Exit(1) 81 | } 82 | flag.Parse() 83 | 84 | if *version { 85 | fmt.Fprintf(os.Stdout, "%s", Version) 86 | os.Exit(0) 87 | } 88 | 89 | if len(flag.Args()) > 0 { 90 | for i := 0; i < len(flag.Args()); i++ { 91 | filename := flag.Arg(i) 92 | _, err := os.Stat(filename) 93 | if err == nil { 94 | now := time.Now() 95 | os.Chtimes(filename, now, now) 96 | } else if !(*nocreate) { 97 | f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE, 0644) 98 | f.Close() 99 | if err != nil { 100 | log.Fatal(err) 101 | } 102 | } 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /tr/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/tr/.gitignore -------------------------------------------------------------------------------- /tr/tr.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /true/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/true/.gitignore -------------------------------------------------------------------------------- /true/true.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | const ( 9 | Help = `Usage: /usr/bin/true [ignored command line arguments] 10 | or: /usr/bin/true OPTION 11 | Exit with a status code indicating success. 12 | 13 | --help display this help and exit 14 | --version output version information and exit 15 | 16 | NOTE: your shell may have its own version of true, which usually supersedes 17 | the version described here. Please refer to your shell's documentation 18 | for details about the options it supports. 19 | ` 20 | Version = `true (Go coreutils) 1.0 21 | Copyright (C) 2015 Eric Lagergren 22 | License GPLv3+: GNU GPL version 3 or later . 23 | This is free software: you are free to change and redistribute it. 24 | There is NO WARRANTY, to the extent permitted by law. 25 | ` 26 | ) 27 | 28 | func main() { 29 | if len(os.Args) == 2 { 30 | if os.Args[1] == "--help" { 31 | fmt.Printf("%s", Help) 32 | } 33 | 34 | if os.Args[1] == "--version" { 35 | fmt.Printf("%s", Version) 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /truncate/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/truncate/.gitignore -------------------------------------------------------------------------------- /truncate/truncate.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /tsort/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/tsort/.gitignore -------------------------------------------------------------------------------- /tsort/tsort_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | ) 7 | 8 | var ( 9 | nums = map[string]string{ 10 | `3 8 11 | 3 10 12 | 5 11 13 | 7 8 14 | 7 11 15 | 8 9 16 | 11 2 17 | 11 9 18 | 11 10`: `3 19 | 5 20 | 7 21 | 11 22 | 8 23 | 10 24 | 2 25 | 9 26 | `, `8 9 27 | 1 4 28 | 1 2 29 | 4 2 30 | 4 3 31 | 3 2 32 | 5 2 33 | 3 5 34 | 8 2 35 | 8 6`: `1 36 | 8 37 | 4 38 | 6 39 | 9 40 | 3 41 | 5 42 | 2 43 | `, 44 | `4 4 45 | 2 4 46 | 4 1 47 | 3 1`: `2 48 | 3 49 | 4 50 | 1 51 | `} 52 | ) 53 | 54 | func TestTsort(t *testing.T) { 55 | 56 | for unsorted, sorted := range nums { 57 | var buf bytes.Buffer 58 | 59 | buf.WriteString(unsorted) 60 | 61 | tsort(&buf) 62 | 63 | if buf.String() != sorted { 64 | t.Errorf("Got: %q\n\nWanted: %q", buf.String(), sorted) 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /tty/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/tty/.gitignore -------------------------------------------------------------------------------- /tty/tty.go: -------------------------------------------------------------------------------- 1 | /* 2 | Go tty -- print the name of the terminal connected to standard input 3 | 4 | Copyright (C) 2015 Eric Lagergren 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | package main 21 | 22 | import ( 23 | "fmt" 24 | "os" 25 | 26 | "github.com/EricLagergren/go-gnulib/ttyname" 27 | flag "github.com/ogier/pflag" 28 | ) 29 | 30 | const ( 31 | VERSION = `tty (Go coreutils) 1.0 32 | Copyright (C) 2015 Eric Lagergren 33 | License GPLv3+: GNU GPL version 3 or later . 34 | This is free software: you are free to change and redistribute it. 35 | There is NO WARRANTY, to the extent permitted by law. 36 | 37 | Written by Eric Lagergren 38 | Inspired by David MacKenzie.` 39 | HELP = `Usage: tty [OPTION]... 40 | Print the file name of the terminal connected to standard input. 41 | 42 | -s, --silent, --quiet print nothing, only return an exit status 43 | --help display this help and exit 44 | --version output version information and exit 45 | 46 | Report uname bugs to ericscottlagergren@gmail.com 47 | Go coreutils home page: ` 48 | ) 49 | 50 | var ( 51 | version = flag.Bool("version", false, "print version") 52 | quiet1 = flag.BoolP("silent", "s", false, "no output") 53 | quiet2 = flag.Bool("quiet", false, "no output") 54 | ) 55 | 56 | func main() { 57 | flag.Usage = func() { 58 | fmt.Fprintf(os.Stderr, "%s\n", HELP) 59 | return 60 | } 61 | flag.Parse() 62 | 63 | if *version { 64 | fmt.Printf("%s\n", VERSION) 65 | return 66 | } 67 | 68 | silent := *quiet1 || *quiet2 69 | 70 | si := os.Stdin.Fd() 71 | tty, err := ttyname.TtyName(si) 72 | if !silent { 73 | if err == ttyname.NotTty { 74 | fmt.Println("not a tty") 75 | os.Exit(1) 76 | } 77 | if tty != "" { 78 | fmt.Println(tty) 79 | return 80 | } else { 81 | fmt.Println("tty") 82 | } 83 | } 84 | 85 | if err != nil { 86 | os.Exit(1) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /uname/.gitignore: -------------------------------------------------------------------------------- 1 | # binary 2 | uname -------------------------------------------------------------------------------- /uname/README.md: -------------------------------------------------------------------------------- 1 | The -o, --operating-system switch should work just fine for most 2 | standard OSs. 3 | 4 | If you need to set a custom value, please install the tool as such: 5 | 6 | `go install --tags=ostypes -ldflags '-X main.hostOS=FOO'` 7 | 8 | If you do not know the value you need to set, please run `go generate` prior 9 | to installing this command. -------------------------------------------------------------------------------- /uname/generate.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | //go:generate go run ostypes.go 4 | -------------------------------------------------------------------------------- /uname/host_os.go: -------------------------------------------------------------------------------- 1 | // +build ostypes 2 | 3 | package main 4 | 5 | var hostOS = unknown 6 | -------------------------------------------------------------------------------- /uname/host_os_darwin.go: -------------------------------------------------------------------------------- 1 | // +build darwin,!ostypes 2 | 3 | package main 4 | 5 | const hostOS = "Darwin" 6 | -------------------------------------------------------------------------------- /uname/host_os_dragonfly.go: -------------------------------------------------------------------------------- 1 | // +build dragonfly,!ostypes 2 | 3 | package main 4 | 5 | const hostOS = "Dragonfly" 6 | -------------------------------------------------------------------------------- /uname/host_os_freebsd.go: -------------------------------------------------------------------------------- 1 | // +build linux,!ostypes 2 | 3 | package main 4 | 5 | const hostOS = "GNU/Linux" 6 | -------------------------------------------------------------------------------- /uname/host_os_linux.go: -------------------------------------------------------------------------------- 1 | // +build linux,!ostypes 2 | 3 | package main 4 | 5 | const hostOS = "GNU/Linux" 6 | -------------------------------------------------------------------------------- /uname/host_os_netbsd.go: -------------------------------------------------------------------------------- 1 | // +build netbsd,!ostypes 2 | 3 | package main 4 | 5 | const hostOS = "NetBSD" 6 | -------------------------------------------------------------------------------- /uname/host_os_openbsd.go: -------------------------------------------------------------------------------- 1 | // +build openbsd,!ostypes 2 | 3 | package main 4 | 5 | const hostOS = "OpenBSD" 6 | -------------------------------------------------------------------------------- /uname/host_os_plan9.go: -------------------------------------------------------------------------------- 1 | // +build plan9,!ostypes 2 | 3 | package main 4 | 5 | const hostOS = "Plan 9" 6 | -------------------------------------------------------------------------------- /uname/host_os_solaris.go: -------------------------------------------------------------------------------- 1 | // +build solaris,!ostypes 2 | 3 | package main 4 | 5 | const hostOS = "Solaris" 6 | -------------------------------------------------------------------------------- /uname/host_os_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows,!ostypes 2 | 3 | package main 4 | 5 | const hostOS = "Windows NT" 6 | -------------------------------------------------------------------------------- /uname/ostypes.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "os" 8 | "os/exec" 9 | "path/filepath" 10 | "strings" 11 | ) 12 | 13 | // globs are stolen from GNU coreutils' host-os.m4 file. 14 | // see GNU-LICENSE.txt 15 | var globs = map[string]string{ 16 | "winnt*": "Windows NT", 17 | "vos*": "VOS", 18 | "sysv*": "Unix System V", 19 | "superux*": "SUPER-UX", 20 | "sunos*": "SunOS", 21 | "stop*": "STOP", 22 | "sco*": "SCO Unix", 23 | "riscos*": "RISC OS", 24 | "riscix*": "RISCiX", 25 | "qnx*": "QNX", 26 | "pw32*": "PW32", 27 | "ptx*": "ptx", 28 | "plan9*": "Plan 9", 29 | "osf*": "Tru64", 30 | "os2*": "OS/2", 31 | "openbsd*": "OpenBSD", 32 | "nsk*": "NonStop Kernel", 33 | "nonstopux*": "NonStop-UX", 34 | "netbsd*-gnu*": "GNU/NetBSD", 35 | "netbsd*": "NetBSD", 36 | "mirbsd*": "MirBSD", 37 | "knetbsd*-gnu": "GNU/kNetBSD", 38 | "kfreebsd*-gnu": "GNU/kFreeBSD", 39 | "msdosdjgpp*": "DJGPP", 40 | "mpeix*": "MPE/iX", 41 | "mint*": "MiNT", 42 | "mingw*": "MinGW", 43 | "lynxos*": "LynxOS", 44 | "linux*": "GNU/Linux", 45 | "hpux*": "HP-UX", 46 | "hiux*": "HI-UX", 47 | "gnu*": "GNU", 48 | "freebsd*": "FreeBSD", 49 | "dgux*": "DG/UX", 50 | "bsdi*": "BSD/OS", 51 | "bsd*": "BSD", 52 | "beos*": "BeOS", 53 | "aux*": "A/UX", 54 | "atheos*": "AtheOS", 55 | "amigaos*": "Amiga OS", 56 | "aix*": "AIX", 57 | } 58 | 59 | func match(pattern, name string) bool { 60 | ok, err := filepath.Match(pattern, name) 61 | return ok && err == nil 62 | } 63 | 64 | func main() { 65 | const pkg = "main" 66 | 67 | // Shell locals... 68 | out, err := exec.Command("sh", "-c", "echo $OSTYPE").Output() 69 | if err != nil { 70 | panic(err) 71 | } 72 | 73 | if len(out) > 0 && out[len(out)-1] == '\n' { 74 | out = out[:len(out)-1] 75 | } 76 | 77 | file, err := os.Create("host_os.go") 78 | if err != nil { 79 | panic(err) 80 | } 81 | defer file.Close() 82 | 83 | rawHostOS := string(out) 84 | 85 | fmt.Fprintln(file, "// +build ostypes") 86 | fmt.Fprintf(file, "// generated by ostypes. DO NOT EDIT.\n\n") 87 | fmt.Fprintf(file, "package %s\n\nconst hostOS = ", pkg) 88 | 89 | // This is what uname does. 90 | if rawHostOS == "" { 91 | fmt.Fprintf(file, "%q\n\n", "unknown") 92 | return 93 | } 94 | 95 | var realHostOS string 96 | for glob, val := range globs { 97 | if match(glob, rawHostOS) { 98 | realHostOS = val 99 | break 100 | } 101 | } 102 | 103 | // No matches found, so apply the default heuristic. 104 | if realHostOS == "" { 105 | if match("[A-Za-z]*", rawHostOS) { 106 | realHostOS := strings.ToUpper(string(rawHostOS[0])) 107 | if len(rawHostOS) > 1 { 108 | realHostOS += rawHostOS[1:] 109 | } 110 | } else { 111 | realHostOS = rawHostOS 112 | } 113 | } 114 | 115 | fmt.Fprintf(file, "%q\n\n", realHostOS) 116 | } 117 | -------------------------------------------------------------------------------- /uname/uname.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014-2016 Eric Lagergren 2 | // Use of this source code is governed by the GPL v3 or later. 3 | 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "log" 9 | "os" 10 | 11 | "github.com/EricLagergren/go-coreutils/internal/flag" 12 | ) 13 | 14 | const ( 15 | unknown = "unknown" 16 | procCPU = "/proc/cpuinfo" 17 | maxUint = ^printer(0) 18 | ) 19 | 20 | var ( 21 | all = flag.BoolP("all", "a", false, `print all information, in the following order, 22 | except omit -p and -i if unknown:`) 23 | kernelName = flag.BoolP("kernel-name", "s", false, "print the kernel name") 24 | nodeName = flag.BoolP("nodename", "n", false, "print the network node hostname") 25 | release = flag.BoolP("kernel-release", "r", false, "print the kernel release") 26 | version = flag.BoolP("kernel-version", "v", false, "print the kernel version") 27 | machine = flag.BoolP("machine", "m", false, "print the machine hardware name") 28 | processor = flag.BoolP("processor", "p", false, "print the processor tyoe or \"unknown\"") 29 | hwPlatform = flag.BoolP("hardware-platform", "i", false, "print the hardware platform or \"unknown\"") 30 | operatingSystem = flag.BoolP("operating-system", "o", false, "print the operating system") 31 | 32 | fatal = log.New(os.Stderr, "", 0) 33 | ) 34 | 35 | type printer uint 36 | 37 | // Enumerated printing options. 38 | const ( 39 | printKernelName printer = 1 << iota 40 | printNodeName 41 | printKernelRelease 42 | printKernelVersion 43 | printMachine 44 | printProcessor 45 | printHardwarePlatform 46 | printOperatingSystem 47 | ) 48 | 49 | func (p printer) isSet(val printer) bool { 50 | return p&val != 0 51 | } 52 | 53 | var printed bool 54 | 55 | func print(element string) { 56 | if printed { 57 | fmt.Print(" ") 58 | } 59 | printed = true 60 | fmt.Printf("%s", element) 61 | } 62 | 63 | func decode(b bool, flag printer) printer { 64 | if b { 65 | return flag 66 | } 67 | return 0 68 | } 69 | 70 | func decodeFlags() printer { 71 | var toprint printer 72 | toprint |= decode(*all, maxUint) 73 | toprint |= decode(*kernelName, printKernelName) 74 | toprint |= decode(*nodeName, printNodeName) 75 | toprint |= decode(*release, printKernelRelease) 76 | toprint |= decode(*version, printKernelVersion) 77 | toprint |= decode(*machine, printMachine) 78 | toprint |= decode(*processor, printProcessor) 79 | toprint |= decode(*hwPlatform, printHardwarePlatform) 80 | toprint |= decode(*operatingSystem, printOperatingSystem) 81 | return toprint 82 | } 83 | 84 | func main() { 85 | flag.Usage = func() { 86 | fmt.Printf(`Usage: %s [OPTION]... 87 | Print certain system information. With no OPTION, same as -s. 88 | 89 | `, flag.Program) 90 | flag.DBE() 91 | } 92 | flag.ProgVersion = "1.1" 93 | flag.Parse() 94 | 95 | toprint := decodeFlags() 96 | if toprint == 0 { 97 | toprint = printKernelName 98 | } 99 | 100 | if toprint.isSet( 101 | (printKernelName | printNodeName | printKernelRelease | 102 | printKernelVersion | printMachine)) { 103 | 104 | name, err := genInfo() 105 | if err != nil { 106 | fatal.Fatalln("cannot get system name") 107 | } 108 | 109 | if toprint.isSet(printKernelName) { 110 | print(name.sysname) 111 | } 112 | if toprint.isSet(printNodeName) { 113 | print(name.nodename) 114 | } 115 | if toprint.isSet(printKernelRelease) { 116 | print(name.release) 117 | } 118 | if toprint.isSet(printKernelVersion) { 119 | print(name.version) 120 | } 121 | if toprint.isSet(printMachine) { 122 | print(name.machine) 123 | } 124 | } 125 | 126 | if toprint.isSet(printProcessor) { 127 | element := unknown 128 | if toprint != maxUint || element != unknown { 129 | print(element) 130 | } 131 | } 132 | 133 | if toprint.isSet(printHardwarePlatform) { 134 | element := unknown 135 | if toprint != maxUint || hostOS != unknown { 136 | print(element) 137 | } 138 | } 139 | 140 | if toprint.isSet(printOperatingSystem) { 141 | print(hostOS) 142 | } 143 | 144 | os.Stdout.WriteString("\n") 145 | } 146 | -------------------------------------------------------------------------------- /uname/uname_freebsd.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014-2016 Eric Lagergren 2 | // Use of this source code is governed by the GPL v3 or later. 3 | 4 | package main 5 | -------------------------------------------------------------------------------- /uname/uname_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014-2016 Eric Lagergren 2 | // Use of this source code is governed by the GPL v3 or later. 3 | 4 | package main 5 | 6 | import "golang.org/x/sys/unix" 7 | 8 | type info struct { 9 | sysname string 10 | nodename string 11 | release string 12 | version string 13 | machine string 14 | } 15 | 16 | func intToString(a [65]int8) string { 17 | var ( 18 | tmp [65]byte 19 | i int 20 | ) 21 | for i = 0; a[i] != 0; i++ { 22 | tmp[i] = byte(a[i]) 23 | } 24 | return string(tmp[:i]) 25 | } 26 | 27 | func genInfo() (info, error) { 28 | var name unix.Utsname 29 | err := unix.Uname(&name) 30 | return info{ 31 | sysname: intToString(name.Sysname), 32 | nodename: intToString(name.Nodename), 33 | release: intToString(name.Release), 34 | version: intToString(name.Version), 35 | machine: intToString(name.Machine), 36 | }, err 37 | } 38 | -------------------------------------------------------------------------------- /uname/uname_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014-2016 Eric Lagergren 2 | // Use of this source code is governed by the GPL v3 or later. 3 | 4 | package main 5 | -------------------------------------------------------------------------------- /unexpand/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/unexpand/.gitignore -------------------------------------------------------------------------------- /unexpand/unexpand.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /uniq/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/uniq/.gitignore -------------------------------------------------------------------------------- /uniq/uniq.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /unlink/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/unlink/.gitignore -------------------------------------------------------------------------------- /unlink/unlink.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /uptime/.gitignore: -------------------------------------------------------------------------------- 1 | untitled.* 2 | -------------------------------------------------------------------------------- /uptime/uptime.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/EricLagergren/go-gnulib/utmp" 8 | 9 | flag "github.com/ogier/pflag" 10 | ) 11 | 12 | func main() { 13 | flag.Usage = func() { 14 | // This is a little weird because I want to insert the correct 15 | // UTMP/WTMP file names into the Help output, but usually my 16 | // Help constants are raw string literals, so I had to 17 | // break it up into a couple chunks and move around some formatting. 18 | fmt.Fprintf(os.Stderr, "%s %s. %s %s", 19 | Help1, utmp.UtmpFile, utmp.WtmpFile, Help2) 20 | os.Exit(1) 21 | } 22 | flag.Parse() 23 | 24 | if *version { 25 | fmt.Printf("%s\n", Version) 26 | os.Exit(0) 27 | } 28 | 29 | switch flag.NArg() { 30 | case 0: 31 | uptime(utmp.UtmpFile, utmp.CheckPIDs) 32 | case 1: 33 | uptime(flag.Arg(0), 0) 34 | default: 35 | fatal.Fatalf("extra operand %s\n", flag.Arg(1)) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /uptime/uptime_freebsd.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "log" 8 | "math" 9 | "os" 10 | "strconv" 11 | "syscall" 12 | "time" 13 | 14 | "github.com/EricLagergren/go-gnulib/stdlib" 15 | "github.com/EricLagergren/go-gnulib/utmp" 16 | 17 | flag "github.com/ogier/pflag" 18 | ) 19 | 20 | const ( 21 | Help1 = `Usage: uptime [OPTION]... [FILE] 22 | Print the current time, the length of time the system has been up, 23 | the number of users on the system, and the average number of jobs 24 | in the run queue over the last 1, 5 and 15 minutes. Processes in 25 | an uninterruptible sleep state also contribute to the load average. 26 | If FILE is not specified, use` 27 | Help2 = `as FILE is common. 28 | 29 | --help display this help and exit 30 | --version output version information and exit 31 | 32 | Report wc bugs to ericscottlagergren@gmail.com 33 | Go coreutils home page: 34 | ` 35 | 36 | Version = ` 37 | uptime (Go coreutils) 1.0 38 | Copyright (C) 2015 Eric Lagergren 39 | License GPLv3+: GNU GPL version 3 or later . 40 | This is free software: you are free to change and redistribute it. 41 | There is NO WARRANTY, to the extent permitted by law. 42 | ` 43 | 44 | delim = " " 45 | ) 46 | 47 | var ( 48 | version = flag.BoolP("version", "v", false, "") 49 | 50 | // fatal = log.New(os.Stderr, "", log.Lshortfile) 51 | fatal = log.New(os.Stderr, "", 0) 52 | ) 53 | 54 | func printUptime(us []utmp.Utmp) { 55 | 56 | var ( 57 | bootTime int32 58 | entries int64 59 | now utmp.TimeVal 60 | 61 | days, hours, mins int 62 | uptime float64 63 | ) 64 | 65 | request := "kern.boottime" 66 | secs, err := syscall.SysctlUint32(request) 67 | if err != nil { 68 | panic(err) 69 | } 70 | secs = float64(secs) 71 | 72 | if 0 <= secs || secs < math.MaxFloat64 { 73 | uptime = secs 74 | } else { 75 | uptime = -1 76 | } 77 | 78 | for _, v := range us { 79 | 80 | if v.IsUserProcess() { 81 | entries++ 82 | } 83 | 84 | if v.Type == utmp.BootTime { 85 | bootTime = v.Time.Sec 86 | } 87 | } 88 | 89 | now.GetTimeOfDay() 90 | if uptime == 0 { 91 | if bootTime == 0 { 92 | fatal.Fatalln("couldn't get boot time") 93 | } 94 | 95 | uptime = float64(now.Sec - bootTime) 96 | } 97 | 98 | days = int(uptime) / 86400 99 | hours = (int(uptime) - (days * 86400)) / 3600 100 | mins = (int(uptime) - (days * 86400) - (hours * 3600)) / 60 101 | 102 | fmt.Print(time.Now().Local().Format(" 15:04pm ")) 103 | 104 | if uptime == -1 { 105 | fmt.Print("up ???? days ??:??, ") 106 | } else { 107 | if 0 < days { 108 | if days > 1 { 109 | fmt.Printf("up %d days %2d:%02d, ", days, hours, mins) 110 | } else { 111 | fmt.Printf("up %d day %2d:%02d, ", days, hours, mins) 112 | } 113 | } else { 114 | fmt.Printf("up %2d:%02d, ", hours, mins) 115 | } 116 | } 117 | 118 | if len(us) > 1 || len(us) == 0 { 119 | fmt.Printf("%d users", entries) 120 | } else { 121 | fmt.Printf("%d user", entries) 122 | } 123 | 124 | var avg [3]float64 125 | loads := stdlib.GetLoadAvg(&avg) 126 | 127 | if loads == -1 { 128 | fmt.Printf("%s", "\n") 129 | } else { 130 | if loads > 0 { 131 | fmt.Printf(", load average: %.2f", avg[0]) 132 | } 133 | 134 | if loads > 1 { 135 | fmt.Printf(", %.2f", avg[1]) 136 | } 137 | 138 | if loads > 2 { 139 | fmt.Printf(", %.2f", avg[2]) 140 | } 141 | 142 | if loads > 0 { 143 | fmt.Printf("%s", "\n") 144 | } 145 | } 146 | } 147 | 148 | func uptime(fname string, opts int) { 149 | var u utmp.Utmpx 150 | 151 | const usize = int64(unsafe.Sizeof(u)) 152 | entries := uint64(0) 153 | 154 | size := stat.Size() 155 | us := make([]utmp.Utmpx, size/usize) 156 | 157 | stat, err := os.Stat(fname) 158 | if err != nil { 159 | fatal.Fatalln(err) 160 | } 161 | 162 | i := 0 163 | for { 164 | u = utmp.GetUtxEnt() 165 | if u == nil { 166 | break 167 | } 168 | 169 | if len(*us) <= int(i) { 170 | *us = append(*us, u) 171 | } else { 172 | (*us)[i] = u 173 | } 174 | i++ 175 | } 176 | 177 | printUptime(us) 178 | } 179 | -------------------------------------------------------------------------------- /uptime/uptime_linux.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "log" 8 | "math" 9 | "os" 10 | "strconv" 11 | "time" 12 | 13 | "github.com/EricLagergren/go-gnulib/stdlib" 14 | "github.com/EricLagergren/go-gnulib/utmp" 15 | 16 | flag "github.com/ogier/pflag" 17 | ) 18 | 19 | const ( 20 | Help1 = `Usage: uptime [OPTION]... [FILE] 21 | Print the current time, the length of time the system has been up, 22 | the number of users on the system, and the average number of jobs 23 | in the run queue over the last 1, 5 and 15 minutes. Processes in 24 | an uninterruptible sleep state also contribute to the load average. 25 | If FILE is not specified, use` 26 | Help2 = `as FILE is common. 27 | 28 | --help display this help and exit 29 | --version output version information and exit 30 | 31 | Report wc bugs to ericscottlagergren@gmail.com 32 | Go coreutils home page: 33 | ` 34 | 35 | Version = ` 36 | uptime (Go coreutils) 1.0 37 | Copyright (C) 2015 Eric Lagergren 38 | License GPLv3+: GNU GPL version 3 or later . 39 | This is free software: you are free to change and redistribute it. 40 | There is NO WARRANTY, to the extent permitted by law. 41 | ` 42 | 43 | delim = " " 44 | ) 45 | 46 | var ( 47 | version = flag.BoolP("version", "v", false, "") 48 | 49 | // fatal = log.New(os.Stderr, "", log.Lshortfile) 50 | fatal = log.New(os.Stderr, "", 0) 51 | ) 52 | 53 | func printUptime(us []*utmp.Utmp) { 54 | 55 | var ( 56 | bootTime int32 57 | entries int64 58 | now utmp.TimeVal 59 | 60 | days, hours, mins int 61 | uptime float64 62 | ) 63 | 64 | file, err := os.Open("/proc/uptime") 65 | if err != nil { 66 | fatal.Fatalln(err) 67 | } 68 | defer file.Close() 69 | 70 | buf := make([]byte, utmp.BufSiz) 71 | 72 | n, err := file.Read(buf) 73 | if err != nil && err != io.EOF { 74 | fatal.Fatalln(err) 75 | } 76 | 77 | // /proc/uptime's output is in the format of "%f %f\n" 78 | // The first space in the buffer will be the end of the first number. 79 | line := string(buf[:bytes.IndexByte(buf[:n], ' ')]) 80 | 81 | secs, err := strconv.ParseFloat(line, 64) 82 | if err != nil { 83 | fatal.Fatalln(err) 84 | } 85 | 86 | uptime = -1 87 | if 0 <= secs || secs < math.MaxFloat64 { 88 | uptime = secs 89 | } 90 | 91 | for _, v := range us { 92 | 93 | if v.IsUserProcess() { 94 | entries++ 95 | } 96 | 97 | if v.TypeEquals(utmp.BootTime) { 98 | bootTime = v.Time.Sec 99 | } 100 | } 101 | 102 | now.GetTimeOfDay() 103 | if uptime == 0 { 104 | if bootTime == 0 { 105 | fatal.Fatalln("can't get boot time") 106 | } 107 | 108 | uptime = float64(now.Sec - bootTime) 109 | } 110 | 111 | days = int(uptime) / 86400 112 | hours = (int(uptime) - (days * 86400)) / 3600 113 | mins = (int(uptime) - (days * 86400) - (hours * 3600)) / 60 114 | 115 | os.Stdout.WriteString(time.Now().Local().Format(" 15:04pm ")) 116 | 117 | if uptime == -1 { 118 | os.Stdout.WriteString("up ???? days ??:??, ") 119 | } else { 120 | if 0 < days { 121 | fmt.Printf(GetPlural("up %d day %2d:%02d, ", 122 | "up %d days %2d:%02d, ", uint64(days)), days, hours, mins) 123 | } else { 124 | fmt.Printf("up %2d:%02d, ", hours, mins) 125 | } 126 | } 127 | 128 | fmt.Printf(GetPlural("%d user", "%d users", uint64(entries)), entries) 129 | 130 | var avg [3]float64 131 | loads := stdlib.GetLoadAvg(&avg) 132 | 133 | if loads == -1 { 134 | fmt.Printf("%s", "\n") 135 | } else { 136 | if loads > 0 { 137 | fmt.Printf(", load average: %.2f", avg[0]) 138 | } 139 | 140 | if loads > 1 { 141 | fmt.Printf(", %.2f", avg[1]) 142 | } 143 | 144 | if loads > 2 { 145 | fmt.Printf(", %.2f", avg[2]) 146 | } 147 | 148 | if loads > 0 { 149 | fmt.Printf("%s", "\n") 150 | } 151 | } 152 | } 153 | 154 | func uptime(fname string, opts int) { 155 | entries := uint64(0) 156 | us, err := utmp.ReadUtmp(fname, &entries, 0, opts) 157 | if err != nil { 158 | fatal.Fatalln(err) 159 | } 160 | 161 | printUptime(us) 162 | } 163 | 164 | func selectPlural(n uint64) uint64 { 165 | const pluralReducer = 1000000 166 | if n <= math.MaxUint64 { 167 | return n 168 | } 169 | return n%pluralReducer + pluralReducer 170 | } 171 | 172 | func GetPlural(msg1, msg2 string, n uint64) string { 173 | if n == 1 { 174 | return msg1 175 | } 176 | return msg2 177 | } 178 | -------------------------------------------------------------------------------- /users/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/users/.gitignore -------------------------------------------------------------------------------- /users/users.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | "sort" 8 | 9 | "github.com/EricLagergren/go-coreutils/internal/flag" 10 | 11 | "github.com/EricLagergren/go-gnulib/utmp" 12 | ) 13 | 14 | func main() { 15 | flag.Usage = func() { 16 | fmt.Printf("Usage: %s [OPTION]... [FILE]\n", flag.Program) 17 | fmt.Printf(`Output who is currently logged in according to FILE. 18 | If FILE is not specified, use %s. %s as FILE is common. 19 | 20 | `, 21 | utmp.UtmpxFile, utmp.Wtmpxfile) 22 | flag.PrintDefaults() 23 | fmt.Printf(` 24 | Report %s bugs to ericscottlagergren@gmail.com 25 | Go coreutils home page: 26 | `, flag.Program) 27 | os.Exit(0) 28 | } 29 | 30 | flag.Parse() 31 | 32 | switch flag.NArg() { 33 | case 0: 34 | users(utmp.UtmpxFile, utmp.CheckPIDs) 35 | case 1: 36 | users(flag.Arg(0), 0) 37 | default: 38 | log.Fatalf("extra operand(s) %v", flag.Args()[1:]) 39 | } 40 | 41 | } 42 | 43 | func users(file string, opts int) { 44 | utmps, err := utmp.ReadUtmp(utmp.UtmpxFile, utmp.CheckPIDs) 45 | if err != nil { 46 | log.Fatalln(err) 47 | } 48 | 49 | var names []string 50 | for _, u := range utmps { 51 | if u.IsUserProcess() { 52 | names = append(names, u.ExtractTrimmedName()) 53 | } 54 | } 55 | sort.Strings(names) 56 | for _, name := range names { 57 | fmt.Println(name) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /vdir/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/vdir/.gitignore -------------------------------------------------------------------------------- /vdir/vdir.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /wc/_testdata/coreutils_man_en.txt: -------------------------------------------------------------------------------- 1 | Next: sum invocation, Up: Summarizing files 2 | 3 | 6.1 wc: Print newline, word, and byte counts 4 | 5 | wc counts the number of bytes, characters, whitespace-separated words, and newlines in each given file, or standard input if none are given or for a file of ‘-’. Synopsis: 6 | 7 | wc [option]... [file]... 8 | wc prints one line of counts for each file, and if the file was given as an argument, it prints the file name following the counts. If more than one file is given, wc prints a final line containing the cumulative counts, with the file name total. The counts are printed in this order: newlines, words, characters, bytes, maximum line length. Each count is printed right-justified in a field with at least one space between fields so that the numbers and file names normally line up nicely in columns. The width of the count fields varies depending on the inputs, so you should not depend on a particular field width. However, as a GNU extension, if only one count is printed, it is guaranteed to be printed without leading spaces. 9 | 10 | By default, wc prints three counts: the newline, words, and byte counts. Options can specify that only certain counts be printed. Options do not undo others previously given, so 11 | 12 | wc --bytes --words 13 | prints both the byte counts and the word counts. 14 | 15 | With the --max-line-length option, wc prints the length of the longest line per file, and if there is more than one file it prints the maximum (not the sum) of those lengths. The line lengths here are measured in screen columns, according to the current locale and assuming tab positions in every 8th column. 16 | 17 | The program accepts the following options. Also see Common options. 18 | 19 | ‘-c’ 20 | ‘--bytes’ 21 | Print only the byte counts. 22 | ‘-m’ 23 | ‘--chars’ 24 | Print only the character counts. 25 | ‘-w’ 26 | ‘--words’ 27 | Print only the word counts. 28 | ‘-l’ 29 | ‘--lines’ 30 | Print only the newline counts. 31 | ‘-L’ 32 | ‘--max-line-length’ 33 | Print only the maximum line lengths. 34 | ‘--files0-from=file’ 35 | Disallow processing files named on the command line, and instead process those named in file file; each name being terminated by a zero byte (ASCII NUL). This is useful when the list of file names is so long that it may exceed a command line length limitation. In such cases, running wc via xargs is undesirable because it splits the list into pieces and makes wc print a total for each sublist rather than for the entire list. One way to produce a list of ASCII NUL terminated file names is with GNU find, using its -print0 predicate. If file is ‘-’ then the ASCII NUL terminated file names are read from standard input. 36 | For example, to find the length of the longest line in any .c or .h file in the current hierarchy, do this: 37 | 38 | find . -name '*.[ch]' -print0 | 39 | wc -L --files0-from=- | tail -n1 40 | An exit status of zero indicates success, and a nonzero value indicates failure. -------------------------------------------------------------------------------- /wc/_testdata/file_list.txt: -------------------------------------------------------------------------------- 1 | ./test_files/file_list.txt./test_files/spaces_en.txt./test_files/dict_en.txt./test_files/lang_ru.txt./test_files/coreutils_man_en.txt -------------------------------------------------------------------------------- /wc/_testdata/spaces_en.txt: -------------------------------------------------------------------------------- 1 | Hello, world! 2 | This is a test file to see if1 my wc utilit y 3 | 4 | is 5 | able 6 | 7 | to det 8 | ermine the correct counts for different fi 9 | les. 10 | -------------------------------------------------------------------------------- /wc/cmd.go: -------------------------------------------------------------------------------- 1 | package wc 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "errors" 7 | "fmt" 8 | "io" 9 | "math" 10 | "math/bits" 11 | "os" 12 | "unicode" 13 | 14 | coreutils "github.com/ericlagergren/go-coreutils" 15 | flag "github.com/spf13/pflag" 16 | ) 17 | 18 | func init() { 19 | coreutils.Register("wc", run) 20 | } 21 | 22 | func newCommand() *cmd { 23 | var c cmd 24 | c.f.BoolVarP(&c.lines, "lines", "l", false, "print the newline counts") 25 | c.f.BoolVarP(&c.words, "words", "w", false, "print the word counts") 26 | c.f.BoolVarP(&c.chars, "chars", "m", false, "print the character counts") 27 | c.f.BoolVarP(&c.bytes, "bytes", "c", false, "print the byte counts") 28 | c.f.BoolVarP(&c.maxLength, "max-line-length", "L", false, "print the length of the longest line") 29 | c.f.StringVar(&c.filesFrom, "files0-from", "", `read input from the files specified by 30 | NUL-terminated names in file F; 31 | If F is - then read names from standard input`) 32 | c.f.Int64VarP(&c.tabWidth, "tab", "t", 8, "change the tab width") 33 | c.f.BoolVarP(&c.unicode, "unicode-version", "u", false, "display unicode version and exit") 34 | c.f.BoolVar(&c.version, "version", false, "display version information and exit") 35 | return &c 36 | } 37 | 38 | type cmd struct { 39 | f flag.FlagSet 40 | lines, words, chars, bytes, maxLength bool 41 | filesFrom string 42 | tabWidth int64 43 | unicode bool 44 | version bool 45 | } 46 | 47 | var errMixedArgs = errors.New("file operands cannot be combined with --files0-from") 48 | 49 | func run(ctx coreutils.Context, args ...string) error { 50 | c := newCommand() 51 | 52 | if err := c.f.Parse(args); err != nil { 53 | return err 54 | } 55 | 56 | if c.version { 57 | fmt.Fprintf(ctx.Stdout, "wc (go-coreutils) 1.0") 58 | return nil 59 | } 60 | 61 | if c.unicode { 62 | fmt.Fprintf(ctx.Stdout, "Unicode version: %s\n", unicode.Version) 63 | return nil 64 | } 65 | 66 | var opts uint8 67 | if c.lines { 68 | opts |= Lines 69 | } 70 | if c.words { 71 | opts |= Words 72 | } 73 | if c.chars { 74 | opts |= Chars 75 | } 76 | if c.bytes { 77 | opts |= Bytes 78 | } 79 | if c.maxLength { 80 | opts |= MaxLength 81 | } 82 | 83 | if opts == 0 { 84 | opts = Lines | Words | Bytes 85 | } 86 | 87 | ctr := NewCounter(opts) 88 | ctr.TabWidth = c.tabWidth 89 | 90 | var s interface { 91 | Scan() bool 92 | Text() string 93 | } 94 | var hint int // To keep from allocating, if possible. 95 | if c.filesFrom == "" { 96 | if c.f.NArg() == 0 { 97 | res, err := ctr.Count(ctx.Stdin) 98 | if err != nil { 99 | fmt.Fprintln(ctx.Stderr, err) 100 | return err 101 | } 102 | width := 7 103 | if opts&(opts-1) == 0 { // power of 2, so 1 argument set. 104 | width = 1 105 | } 106 | writeCounts(ctx.Stdout, width, opts, res, "") 107 | return nil 108 | } 109 | s = &sliceScanner{s: c.f.Args()} 110 | hint = c.f.NArg() 111 | } else { 112 | if c.f.NArg() > 0 { 113 | fmt.Fprintln(ctx.Stderr, errMixedArgs) 114 | return errMixedArgs 115 | } 116 | file, err := os.Open(c.filesFrom) 117 | if err != nil { 118 | fmt.Fprintln(ctx.Stderr, err) 119 | return err 120 | } 121 | defer file.Close() 122 | s = bufio.NewScanner(file) 123 | s.(*bufio.Scanner).Split(filesFromSplit) 124 | } 125 | 126 | var ( 127 | results = make([]Results, 0, hint) 128 | names = make([]string, 0, hint) 129 | total Results 130 | maxBytes int64 131 | minWidth = 1 132 | ) 133 | 134 | for s.Scan() { 135 | fname := s.Text() 136 | 137 | file, err := os.Open(fname) 138 | if err != nil { 139 | fmt.Fprintln(ctx.Stderr, err) 140 | return err 141 | } 142 | 143 | stat, err := file.Stat() 144 | if err != nil || (err == nil && !stat.Mode().IsRegular()) { 145 | minWidth = 7 146 | } 147 | 148 | res, err := ctr.Count(file) 149 | if err != nil { 150 | fmt.Fprintln(ctx.Stderr, err) 151 | return err 152 | } 153 | results = append(results, res) 154 | names = append(names, fname) 155 | 156 | total.Lines += res.Lines 157 | total.Words += res.Words 158 | total.Chars += res.Chars 159 | total.Bytes += res.Bytes 160 | 161 | if res.Bytes > maxBytes { 162 | maxBytes = res.Bytes 163 | } 164 | 165 | if res.MaxLength > total.MaxLength { 166 | total.MaxLength = res.MaxLength 167 | } 168 | 169 | if err := file.Close(); err != nil { 170 | fmt.Fprintln(ctx.Stderr, err) 171 | return err 172 | } 173 | } 174 | 175 | // Fast integer log 10. The call to math.Pow and subsequent comparison can 176 | // be dropped in favor of simply adding +1 to width if it's alright for the 177 | // result to be +1 too large for some numbers. 178 | width := int((bits.Len64(uint64(maxBytes)) * 1233) >> 12) 179 | if int64(math.Pow10(width)) < maxBytes { 180 | width++ 181 | } 182 | if width < minWidth { 183 | width = minWidth 184 | } 185 | for i, r := range results { 186 | writeCounts(ctx.Stdout, width, opts, r, names[i]) 187 | } 188 | if len(results) > 1 { 189 | writeCounts(ctx.Stdout, width, opts, total, "total") 190 | } 191 | return nil 192 | } 193 | 194 | type sliceScanner struct{ s []string } 195 | 196 | func (s *sliceScanner) Scan() bool { return len(s.s) > 0 } 197 | func (s *sliceScanner) Text() string { 198 | t := s.s[0] 199 | s.s = s.s[1:] 200 | return t 201 | } 202 | 203 | func filesFromSplit(data []byte, atEOF bool) (adv int, token []byte, err error) { 204 | if atEOF && len(data) == 0 { 205 | return 0, nil, nil 206 | } 207 | if i := bytes.IndexByte(data, 0x00); i >= 0 { 208 | return i + 1, dropNull(data[0:i]), nil 209 | } 210 | if atEOF { 211 | return len(data), dropNull(data), nil 212 | } 213 | return 0, nil, nil 214 | } 215 | 216 | func dropNull(data []byte) []byte { 217 | if len(data) > 0 && data[len(data)-1] == 0x00 { 218 | return data[0 : len(data)-1] 219 | } 220 | return data 221 | } 222 | 223 | func writeCounts(w io.Writer, width int, opts uint8, r Results, fname string) { 224 | const fmtSpInt = " %*d" 225 | 226 | fmtInt := "%*d" 227 | if opts&Lines != 0 { 228 | fmt.Fprintf(w, fmtInt, width, r.Lines) 229 | fmtInt = fmtSpInt 230 | } 231 | if opts&Words != 0 { 232 | fmt.Fprintf(w, fmtInt, width, r.Words) 233 | fmtInt = fmtSpInt 234 | } 235 | if opts&Chars != 0 { 236 | fmt.Fprintf(w, fmtInt, width, r.Chars) 237 | fmtInt = fmtSpInt 238 | } 239 | if opts&Bytes != 0 { 240 | fmt.Fprintf(w, fmtInt, width, r.Bytes) 241 | fmtInt = fmtSpInt 242 | } 243 | if opts&MaxLength != 0 { 244 | fmt.Fprintf(w, fmtInt, width, r.MaxLength) 245 | } 246 | fmt.Fprintf(w, " %s\n", fname) 247 | } 248 | -------------------------------------------------------------------------------- /wc/internal/sys/fadv.go: -------------------------------------------------------------------------------- 1 | // +build !linux,!freebsd 2 | 3 | package sys 4 | 5 | func Fadvise(_ int) error { return nil } 6 | -------------------------------------------------------------------------------- /wc/internal/sys/fadv_unix.go: -------------------------------------------------------------------------------- 1 | // +build linux freebsd 2 | 3 | package sys 4 | 5 | import "golang.org/x/sys/unix" 6 | 7 | func Fadvise(fd int) error { 8 | return unix.Fadvise(fd, 0, 0, unix.FADV_SEQUENTIAL) 9 | } 10 | -------------------------------------------------------------------------------- /wc/wc.go: -------------------------------------------------------------------------------- 1 | package wc 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | "os" 7 | "unicode" 8 | "unicode/utf8" 9 | 10 | "github.com/ericlagergren/go-coreutils/wc/internal/sys" 11 | ) 12 | 13 | type Results struct { 14 | Lines int64 15 | Words int64 16 | Chars int64 17 | Bytes int64 18 | MaxLength int64 19 | } 20 | 21 | type Counter struct { 22 | TabWidth int64 23 | 24 | buf [1 << 17]byte 25 | opts uint8 26 | } 27 | 28 | const ( 29 | Lines = 1 << iota // count lines 30 | Words // count words 31 | Chars // count chars 32 | Bytes // count bytes 33 | MaxLength // find max line length 34 | ) 35 | 36 | func NewCounter(opts uint8) *Counter { 37 | return &Counter{opts: opts, TabWidth: 8} 38 | } 39 | 40 | func (c *Counter) read(r io.Reader) (int64, error) { 41 | n, err := r.Read(c.buf[:]) 42 | if err != nil { 43 | return 0, err 44 | } 45 | return int64(n), nil 46 | } 47 | 48 | var newLine = []byte{'\n'} 49 | 50 | func (c *Counter) Count(r io.Reader) (res Results, err error) { 51 | if file, ok := r.(*os.File); ok { 52 | if c.opts == Bytes { 53 | if n, ok := statSize(file); ok { 54 | return Results{Bytes: n}, nil 55 | } 56 | } 57 | sys.Fadvise(int(file.Fd())) 58 | } 59 | switch c.opts { 60 | case Bytes: 61 | for { 62 | n, err := c.read(r) 63 | res.Bytes += n 64 | if err != nil { 65 | if err == io.EOF { 66 | return res, nil 67 | } 68 | return res, err 69 | } 70 | } 71 | case Lines, Lines | Bytes: 72 | for { 73 | n, err := c.read(r) 74 | res.Bytes += n 75 | res.Lines += int64(bytes.Count(c.buf[:n], newLine)) 76 | if err != nil { 77 | if err == io.EOF { 78 | return res, nil 79 | } 80 | return res, err 81 | } 82 | } 83 | default: 84 | return c.countComplicated(r) 85 | } 86 | } 87 | 88 | func (c *Counter) countComplicated(r io.Reader) (res Results, err error) { 89 | var ( 90 | pos int64 91 | inWord bool 92 | ) 93 | 94 | for { 95 | n, err := c.read(r) 96 | res.Bytes += n 97 | if err != nil { 98 | if err == io.EOF { 99 | break 100 | } 101 | return res, err 102 | } 103 | 104 | for bp := 0; int64(bp) < n; { 105 | r, s := utf8.DecodeRune(c.buf[bp:]) 106 | switch r { 107 | case '\n': 108 | res.Lines++ 109 | fallthrough 110 | case '\r', '\f': 111 | if pos > res.MaxLength { 112 | res.MaxLength = pos 113 | } 114 | pos = 0 115 | if inWord { 116 | res.Words++ 117 | } 118 | inWord = false 119 | case '\t': 120 | pos += c.TabWidth - (pos % c.TabWidth) 121 | if inWord { 122 | res.Words++ 123 | } 124 | inWord = false 125 | case ' ': 126 | pos++ 127 | fallthrough 128 | case '\v': 129 | if inWord { 130 | res.Words++ 131 | } 132 | inWord = false 133 | default: 134 | if !unicode.IsPrint(r) { 135 | break 136 | } 137 | 138 | pos++ 139 | if unicode.IsSpace(r) { 140 | if inWord { 141 | res.Words++ 142 | } 143 | inWord = false 144 | } else { 145 | inWord = true 146 | } 147 | } 148 | res.Chars++ 149 | bp += s 150 | } 151 | } 152 | if pos > res.MaxLength { 153 | res.MaxLength = pos 154 | } 155 | if inWord { 156 | res.Words++ 157 | } 158 | return res, nil 159 | } 160 | 161 | func statSize(file *os.File) (n int64, ok bool) { 162 | stat, err := file.Stat() 163 | if err != nil { 164 | return 0, false 165 | } 166 | 167 | const badMode = os.ModeDir | os.ModeNamedPipe | os.ModeSocket 168 | if stat.Mode()&badMode != 0 { 169 | return 0, false 170 | } 171 | 172 | // NOTE(eric): GNU's wc says we should seek 1 block size from EOF because it 173 | // works better on proc-like systems. I like the idea, but I don't want this 174 | // code to be under the GPL. 175 | 176 | return stat.Size(), true 177 | } 178 | -------------------------------------------------------------------------------- /wc/wc_test.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | package wc 4 | 5 | import ( 6 | "bytes" 7 | "io" 8 | "os" 9 | "os/exec" 10 | "testing" 11 | ) 12 | 13 | var flist = []string{ 14 | "_testdata/lang_ru.txt", 15 | "_testdata/dict_en.txt", 16 | "_testdata/spaces_en.txt", 17 | "_testdata/coreutils_man_en.txt", 18 | } 19 | 20 | var buf bytes.Buffer 21 | 22 | func TestWC(t *testing.T) { 23 | 24 | fs := getFileStatus(flist) 25 | numberWidth = findNumberWidth(fs) 26 | 27 | *printLines = true 28 | *printWords = true 29 | *printChars = true 30 | *printBytes = true 31 | *printLineLength = true 32 | 33 | // set up our capture of stdout 34 | stdout := os.Stdout 35 | r, w, err := os.Pipe() 36 | if err != nil { 37 | t.Fatal(err) 38 | } 39 | os.Stdout = w 40 | 41 | // now output stdout 42 | for i, file := range flist { 43 | wcFile(file, fs[i]) 44 | } 45 | writeCounts(totalLines, totalWords, 46 | totalChars, totalBytes, maxLineLength, "total") 47 | 48 | // capture the stdout 49 | outC := make(chan string) 50 | go func() { 51 | var b bytes.Buffer 52 | _, err := io.Copy(&b, r) 53 | r.Close() 54 | if err != nil { 55 | t.Fatal(err) 56 | } 57 | outC <- b.String() 58 | }() 59 | 60 | // now get stdout of native wc 61 | wc := exec.Command("wc", "-lwmcL", 62 | flist[0], flist[1], flist[2], flist[3]) 63 | 64 | b, err := wc.Output() 65 | if err != nil { 66 | t.Fatal(err) 67 | } 68 | buf.Write(b) 69 | 70 | // stop capturing of stdout 71 | w.Close() 72 | os.Stdout = stdout 73 | out := <-outC 74 | 75 | // check strings 76 | if out != buf.String() { 77 | t.Fatalf("Got:\n%s\n\nExpected:\n%s\n", out, buf.String()) 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /who/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/who/.gitignore -------------------------------------------------------------------------------- /whoami/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/whoami/.gitignore -------------------------------------------------------------------------------- /whoami/whoami: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericlagergren/go-coreutils/70e5762048c92a7ec35b97bac8bcb38a0d00f413/whoami/whoami -------------------------------------------------------------------------------- /whoami/whoami.go: -------------------------------------------------------------------------------- 1 | /* 2 | Go whoami -- print effective userid 3 | 4 | Copyright (c) 2015 Eric Lagergren 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | /* Equivalent to 'id -un'. */ 21 | /* Written by Eric Lagergren and mattn */ 22 | 23 | package main 24 | 25 | import ( 26 | "fmt" 27 | "log" 28 | "os" 29 | 30 | flag "github.com/ogier/pflag" 31 | ) 32 | 33 | const ( 34 | Help = `Usage: whoami [OPTION]... 35 | Print the user name associated with the current effective user ID. 36 | Same as id -un. 37 | 38 | --help display this help and exit 39 | --version output version information and exit 40 | 41 | Report whoami bugs to ericscottlagergren@gmail.com 42 | Go coreutils home page: ` 43 | 44 | Version = `whoami (Go coreutils) 1.0 45 | Copyright (C) 2015 Eric Lagergren 46 | License GPLv3+: GNU GPL version 3 or later . 47 | This is free software: you are free to change and redistribute it. 48 | There is NO WARRANTY, to the extent permitted by law. 49 | 50 | Written by Eric Lagergren` 51 | ) 52 | 53 | var ( 54 | version = flag.BoolP("version", "v", false, "") 55 | fatal = log.New(os.Stderr, "", 0) 56 | ) 57 | 58 | func main() { 59 | flag.Usage = func() { 60 | fmt.Fprintf(os.Stderr, "%s", Help) 61 | os.Exit(0) 62 | } 63 | flag.Parse() 64 | 65 | if *version { 66 | fmt.Fprintf(os.Stderr, "%s", Version) 67 | os.Exit(0) 68 | } 69 | 70 | // This function call *should* be inlined on both 71 | // Windows and Unix 72 | fmt.Println(getUser()) 73 | } 74 | -------------------------------------------------------------------------------- /whoami/whoami_test.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package main 4 | 5 | import ( 6 | "os" 7 | "os/exec" 8 | "os/user" 9 | "strconv" 10 | "testing" 11 | ) 12 | 13 | func TestWhoami(t *testing.T) { 14 | 15 | cmd := exec.Command("whoami") 16 | b, err := cmd.Output() 17 | if err != nil { 18 | t.Fatalf("%s\n", err.Error()) 19 | } 20 | 21 | uid := strconv.Itoa(os.Geteuid()) 22 | u, err := user.LookupId(uid) 23 | if err != nil { 24 | t.Fatalf("%s\n", err.Error()) 25 | } 26 | 27 | if string(b[:len(b)-1]) != u.Username { 28 | t.Errorf("got: %q, want: %q", b, u.Username) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /whoami/whoami_unix.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | /* 4 | Go whoami -- print effective userid 5 | 6 | Copyright (c) 2015 Eric Lagergren 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /* Equivalent to 'id -un'. */ 23 | /* Written by Eric Lagergren */ 24 | 25 | package main 26 | 27 | import ( 28 | "os" 29 | "os/user" 30 | "strconv" 31 | ) 32 | 33 | func getUser() string { 34 | uid := strconv.Itoa(os.Geteuid()) 35 | u, err := user.LookupId(uid) 36 | if err != nil { 37 | fatal.Fatalf("cannot find name for user ID %s\n", uid) 38 | } 39 | return u.Username 40 | } 41 | -------------------------------------------------------------------------------- /whoami/whoami_windows.go: -------------------------------------------------------------------------------- 1 | /* 2 | Go whoami -- print effective userid 3 | 4 | Copyright (c) 2015 Eric Lagergren 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | /* Equivalent to 'id -un'. */ 21 | /* Written by Eric Lagergren and mattn */ 22 | 23 | package main 24 | 25 | import "os/user" 26 | 27 | func getUser() string { 28 | u, err := user.Current() 29 | // TODO(eric): Have this output match whoami_unix.go 30 | if err != nil { 31 | fatal.Fatalln("cannot find name for current user") 32 | } 33 | return u.Username 34 | } 35 | -------------------------------------------------------------------------------- /xxd/xxd_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "crypto/rand" 6 | "flag" 7 | "fmt" 8 | "io" 9 | "io/ioutil" 10 | "os/exec" 11 | "strings" 12 | "testing" 13 | "testing/quick" 14 | ) 15 | 16 | var xxdFile = flag.String("xxdFile", "", "File to test against.") 17 | 18 | func TestXXD(t *testing.T) { 19 | if *xxdFile == "" { 20 | t.Skip("-xxdFile argument not given") 21 | } 22 | data, err := ioutil.ReadFile(*xxdFile) 23 | if err != nil { 24 | t.Fatal(err) 25 | } 26 | test := func(fn func(r io.Reader, w io.Writer, s string) error) func(n uint64) []string { 27 | return func(n uint64) []string { 28 | size := n % uint64(len(data)) 29 | fmt.Printf("%d\n", size) 30 | var out bytes.Buffer 31 | if err := fn(&pathologicalReader{data[0:size]}, &out, ""); err != nil { 32 | return []string{err.Error()} 33 | } 34 | return strings.Split(out.String(), "\n") 35 | } 36 | } 37 | if err := quick.CheckEqual(test(xxd), test(xxdNative), nil); err != nil { 38 | cErr := err.(*quick.CheckEqualError) 39 | size := cErr.In[0].(uint64) % uint64(len(data)) 40 | for i := range cErr.Out1[0].([]string) { 41 | got := cErr.Out1[0].([]string)[i] 42 | want := cErr.Out2[0].([]string)[i] 43 | if got != want { 44 | t.Errorf("size: %d\n\ngot : %s\nwant: %s\n", size, got, want) 45 | break 46 | } 47 | } 48 | } 49 | } 50 | 51 | type pathologicalReader struct { 52 | data []byte 53 | } 54 | 55 | func (p *pathologicalReader) Read(b []byte) (int, error) { 56 | n := len(b) 57 | if n > len(p.data) { 58 | n = len(p.data) 59 | } 60 | if n > 1 { 61 | n-- 62 | } 63 | copy(b, p.data[0:n]) 64 | p.data = p.data[n:] 65 | if len(p.data) == 0 { 66 | return n, io.EOF 67 | } 68 | return n, nil 69 | } 70 | 71 | func BenchmarkXXD(b *testing.B) { 72 | b.StopTimer() 73 | data := make([]byte, b.N) 74 | if _, err := io.ReadFull(rand.Reader, data); err != nil { 75 | b.Fatal(err) 76 | } 77 | buf := bytes.NewBuffer(data) 78 | b.StartTimer() 79 | if err := xxd(buf, ioutil.Discard, ""); err != nil { 80 | b.Fatal(err) 81 | } 82 | } 83 | 84 | func xxdNative(r io.Reader, w io.Writer, s string) error { 85 | xxd := exec.Command("xxd.bak", "-") 86 | xxd.Stdin = r 87 | xxd.Stdout = w 88 | xxd.Stderr = w 89 | return xxd.Run() 90 | } 91 | 92 | func main() {} 93 | -------------------------------------------------------------------------------- /yes/yes.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "flag" 6 | "fmt" 7 | "os" 8 | ) 9 | 10 | var version bool 11 | 12 | func main() { 13 | flag.BoolVar(&version, "version", false, "") 14 | flag.BoolVar(&version, "v", false, "") 15 | 16 | flag.Usage = func() { 17 | fmt.Printf(`Usage: yes [STRING]... 18 | or: yes OPTION 19 | Repeatedly output a line with all specified STRING(s), or 'y'. 20 | 21 | --help display this help and exit 22 | --version output version information and exit 23 | 24 | Report yes bugs to eric@ericlagergren.com 25 | Go coreutils home page: 26 | `) 27 | } 28 | flag.Parse() 29 | 30 | if version { 31 | fmt.Printf(`yes (Go coreutils) 1.1 32 | Copyright (C) 2015-2017 Eric Lagergren. 33 | License GPLv3+: GNU GPL version 3 or later . 34 | This is free software: you are free to change and redistribute it. 35 | There is NO WARRANTY, to the extent permitted by law. 36 | `) 37 | return 38 | } 39 | 40 | var buf []byte 41 | if flag.NArg() == 0 { 42 | buf = bytes.Repeat([]byte{'y', '\n'}, 4096) 43 | } else { 44 | for _, arg := range flag.Args() { 45 | buf = append(buf, arg...) 46 | buf = append(buf, ' ') 47 | } 48 | buf = append(buf, '\n') 49 | } 50 | 51 | for { 52 | os.Stdout.Write(buf) 53 | } 54 | } 55 | --------------------------------------------------------------------------------