diff --git a/Makefile b/Makefile deleted file mode 100644 index 8906abb..0000000 --- a/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -# goblin - Plan 9 command line tools proted to Go - -include config.mk - -SUBDIRS = basename\ - cal\ - cat\ - cleanname\ - echo\ - md5sum\ - mkdir\ - pbd\ - sha1sum\ - sleep\ - tee\ - touch - -all: - @for i in ${SUBDIRS}; do cd $$i; ${MAKE} || exit; cd ..; done; - -clean: - @for i in ${SUBDIRS}; do cd $$i; ${MAKE} clean || exit; cd ..; done - @rm -f goblin-${VERSION}.tar.gz - @echo cleaned goblin - -install: all - @for i in ${SUBDIRS}; do cd $$i; ${MAKE} install || exit; cd ..; done - @echo installed goblin to ${DESTDIR}${PREFIX} - -uninstall: - @for i in ${SUBDIRS}; do cd $$i; ${MAKE} uninstall || exit; cd ..; done - @echo uninstalled goblin - -dist: clean - @mkdir -p goblin-${VERSION} - @cp -R Makefile README LICENSE std.mk config.mk ${SUBDIRS} goblin-${VERSION} - @tar -cf goblin-${VERSION}.tar goblin-${VERSION} - @gzip -9 goblin-${VERSION}.tar - @rm -rf goblin-${VERSION} - @echo created distribution goblin-${VERSION}.tar.gz diff --git a/basename/Makefile b/basename/Makefile deleted file mode 100644 index d24beae..0000000 --- a/basename/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# basename - strip file name affixes -TARG = basename - -include ../std.mk - -pre-uninstall: - -post-install: diff --git a/basename/basename.go b/basename/basename.go index 52562a4..423b1c7 100644 --- a/basename/basename.go +++ b/basename/basename.go @@ -7,51 +7,33 @@ import ( "flag" ) -var dirMode = flag.Bool("d", false, "Print directory component") +var dflag = flag.Bool("d", false, "Print directory component") func usage() { - fmt.Fprintf( - os.Stderr, - "usage: basename [-d] string [suffix]\n") + fmt.Fprintln(os.Stderr, "usage: basename [-d] string [suffix]") os.Exit(1) } func printDir(str string) { - index := strings.LastIndex(str, "/") - - if index == -1 { - fmt.Fprintf(os.Stdout, ".\n") - } else { - if index == 0 { - fmt.Fprintf(os.Stdout, "\n") - } else { - fmt.Fprintf(os.Stdout, "%s\n", str[0:index]) - } + i := strings.LastIndex(str, "/") + if i < 0 { + fmt.Println(".") + return } + fmt.Println(str[:i]) } func printName(str, suf string) { - index := strings.LastIndex(str, "/") - name := str[index+1:len(str)] - - if len(suf) > 0 { - index2 := strings.LastIndex(name, suf) - - if index2 != -1 { - name = name[0:index2] - } - } - fmt.Fprintf(os.Stdout, "%s\n", name) + i, j := strings.LastIndex(str, "/"), strings.LastIndex(str, suf) + fmt.Println(str[i+1:j]) } func main() { flag.Parse() - if flag.NArg() == 0 || flag.NArg() > 2 { usage() } - - if *dirMode { + if *dflag { printDir(flag.Arg(0)) } else { if flag.NArg() == 2 { diff --git a/cal/Makefile b/cal/Makefile deleted file mode 100644 index 1baa3be..0000000 --- a/cal/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# cal - print calendar -TARG = cal - -include ../std.mk - -pre-uninstall: - -post-install: diff --git a/cal/cal.go b/cal/cal.go index 9375395..93049e8 100644 --- a/cal/cal.go +++ b/cal/cal.go @@ -1,57 +1,56 @@ package main import ( - "os" - "fmt" - "time" "flag" + "fmt" + "os" "strconv" + "time" ) - -func parseMonth(month string) int { +func parseMonth(month string) time.Month { switch month { - case "jan", "january": - return 1 - case "feb", "february": - return 2 - case "mar", "march": - return 3 - case "apr", "april": - return 4 - case "may": - return 5 - case "jun", "june": - return 6 - case "jul", "july": - return 7 - case "aug", "august": - return 8 - case "sep", "september": - return 9 - case "oct", "october": - return 10 - case "nov", "november": - return 11 - case "dec", "december": - return 12 + case "jan", "january": + return time.January + case "feb", "february": + return time.February + case "mar", "march": + return time.March + case "apr", "april": + return time.April + case "may": + return time.May + case "jun", "june": + return time.June + case "jul", "july": + return time.July + case "aug", "august": + return time.August + case "sep", "september": + return time.September + case "oct", "october": + return time.October + case "nov", "november": + return time.November + case "dec", "december": + return time.December } - return 0 + return time.Month(0) } -func parseYear(year string) int64 { - var yr, er = strconv.Atoi(year) +func parseYear(year string) int { + var yr, err = strconv.ParseInt(year, 10, 32) - if er != nil { - fmt.Fprintf(os.Stderr, "cal: error parsing parameters\n") + if err != nil { + fmt.Fprintln(os.Stderr, "cal: error parsing year:", err.Error()) os.Exit(1) } - return int64(yr) + return int(yr) } -func januaryFirst(year int64) int { - d := 4 + year + (year + 3) / 4 +func januaryFirst(year int) int { + d := 4 + year + (year+3)/4 if year > 1800 { d -= (year - 1701) / 100 @@ -65,51 +64,51 @@ func januaryFirst(year int64) int { return int(d % 7) } -var nonleapyear = []int{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} -var leapyear = []int{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} +var ( + nonleapyear = []int{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} + leapyear = []int{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} +) -func months(year int64) []int { +func months(year int) []int { if year%4 == 0 && (year%100 != 0 || year%400 == 0) { return leapyear } return nonleapyear } -func printCal(month int, year int64) { - var dayw string = " Su Mo Tu We Th Fr Sa" - - smon := [...]string{"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"} +func printCal(month time.Month, year int) { + dayw := "Su Mo Tu We Th Fr Sa" - var s string = smon[month-1] + " " + strconv.Itoa64(year) + s := month.String() + " " + strconv.FormatInt(int64(year), 10) - var off int = (20 - len(s)) / 2 + off := (20 - len(s)) / 2 for i := 0; i < off; i++ { s = " " + s } - s = s + "\n" + dayw + "\n" + s += "\n" + dayw + "\n" mth := months(year) day := januaryFirst(year) - for i := 1; i < month; i++ { + for i := 1; i < int(month); i++ { day += mth[i-1] } - for i := 0; i < day % 7; i++ { + for i := 0; i < day%7; i++ { s = s + " " } for i := 1; i <= mth[month-1]; i++ { - s = s + " " + s = s + " " if i < 10 { s = s + " " } s = s + strconv.Itoa(i) day += 1 - if day % 7 == 0 { + if day%7 == 0 { s = s + "\n" } } @@ -122,10 +121,10 @@ func printCal(month int, year int64) { func main() { flag.Parse() - var local = *time.LocalTime() + local := time.Now() - var month int = 0 - var year int64 = 0 + var month time.Month + var year int if flag.NArg() > 2 { fmt.Fprintf(os.Stderr, "cal: error parsing parameters\n") @@ -142,16 +141,16 @@ func main() { } } else { if flag.NArg() == 1 { - year = local.Year + year = local.Year() month = parseMonth(flag.Arg(0)) - if month == 0 { + if month == time.Month(0) { year = parseYear(flag.Arg(0)) - month = local.Month + month = local.Month() } } else { - year = local.Year - month = local.Month + year = local.Year() + month = local.Month() } } diff --git a/cat/Makefile b/cat/Makefile deleted file mode 100644 index a1b6637..0000000 --- a/cat/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# cat - catenate files -TARG = cat - -include ../std.mk - -pre-uninstall: - -post-install: diff --git a/cat/cat.go b/cat/cat.go index 7d3dea5..7f44464 100644 --- a/cat/cat.go +++ b/cat/cat.go @@ -6,57 +6,26 @@ package main import ( - "os" "flag" "fmt" + "os" ) -func cat(f *os.File) { - const NBUF = 8192 - var buf [NBUF]byte - - for { - switch nr, rerr := f.Read(buf[:]); true { - case nr > 0: - var nw, werr = os.Stdout.Write(buf[0:nr]) - if nw != nr { - fmt.Fprintf( - os.Stderr, - "cat: write error copying %s: %s", - f.Name(), - werr.String()) - os.Exit(1) - } - case nr == 0: - return - case nr < 0: - fmt.Fprintf( - os.Stderr, - "cat: error reading %s: %s", - f.Name(), - rerr.String()) - os.Exit(1) - } - } -} +const NBUF = 8192 func main() { flag.Parse() - if flag.NArg() > 0 { - for i := 0; i < flag.NArg(); i++ { - var f, err = os.Open(flag.Arg(i), os.O_RDONLY, 0666) - if f == nil { - fmt.Fprintf( - os.Stderr, - "cat: can't open %s: %s", - flag.Arg(i), - err.String()) + if flag.NArg() == 0 { + io.copy(os.Stdin, os.Stdout) + } else { + for _, v := range flag.Args() { + f, err := os.Open(v) + if err != nil { + fmt.Fprintln(os.Stderr, "cat:" err.Error()) os.Exit(1) } - cat(f) + io.copy(f, os.Stdout) f.Close() } - } else { - cat(os.Stdin) } } diff --git a/cleanname/Makefile b/cleanname/Makefile deleted file mode 100644 index 7096b70..0000000 --- a/cleanname/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# cleanname - clean a path name -TARG = cleanname - -include ../std.mk - -pre-uninstall: - -post-install: diff --git a/config.mk b/config.mk deleted file mode 100644 index fc85cbe..0000000 --- a/config.mk +++ /dev/null @@ -1,14 +0,0 @@ -# Customize to fit your system - -VERSION = 0.0.1 - -# paths -PREFIX = /usr/local/goblin -MANPREFIX = ${PREFIX}/share/man - -OBJTYPE = ${GOARCH} -O = 8 - -# Compilers -GC = ${O}g -LD = ${O}l diff --git a/date/date.go b/date/date.go new file mode 100644 index 0000000..a4a2952 --- /dev/null +++ b/date/date.go @@ -0,0 +1,47 @@ +package main + +import ( + "flag" + "fmt" + "os" + "strconv" + "time" +) + +var ( + uflag = flag.Bool("u", false, "Report Coordinated Universal Time (UTC) rather than local time.") + nflag = flag.Bool("n", false, "Report the date as the number of seconds since the epoch, 00:00:00 UTC, January 1, 1970") +) + +func usage() { + fmt.Fprintln(os.Stderr, "usage: date [ -u ] [ -n ] [ seconds ]") + os.Exit(1) +} + +func main() { + flag.Parse() + var t time.Time + + switch flag.NArg() { + case 0: + t = time.Now() + case 1: + i, err := strconv.ParseInt(flag.Arg(0), 10, 64) + if err != nil { + fmt.Fprintln(os.Stderr, "date:", err.Error()) + os.Exit(1) + } + t = time.Unix(i, 0) + default: + usage() + } + + switch { + case *nflag: + fmt.Println(t.Unix()) + case *uflag: + fmt.Println(t.UTC()) + default: + fmt.Println(t) + } +} diff --git a/echo/Makefile b/echo/Makefile deleted file mode 100644 index 5cdad38..0000000 --- a/echo/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# echo - print arguments - -TARG = echo - -include ../std.mk - -pre-uninstall: - -post-install: diff --git a/echo/echo.go b/echo/echo.go index 32bda52..63d9a52 100644 --- a/echo/echo.go +++ b/echo/echo.go @@ -19,11 +19,11 @@ const ( func main() { flag.Parse() var s string = "" - for i := 0; i < flag.NArg(); i++ { + for i, v := range flag.Args() { if i > 0 { s += Space } - s += flag.Arg(i) + s += v } if !*suppressNewline { s += Newline diff --git a/md5sum/Makefile b/md5sum/Makefile deleted file mode 100644 index 43686d3..0000000 --- a/md5sum/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# md5sum - calculate RFC1321 hash of files - -TARG = md5sum - -include ../std.mk - -pre-uninstall: - -post-install: diff --git a/md5sum/md5sum.go b/md5sum/md5sum.go index 802205c..60bcafa 100644 --- a/md5sum/md5sum.go +++ b/md5sum/md5sum.go @@ -1,84 +1,50 @@ package main import ( - "os" - "fmt" - "flag" "crypto/md5" + "flag" + "fmt" "io/ioutil" + "os" ) func usage() { - fmt.Fprintf(os.Stderr, "usage: md5sum [file ...]\n") + fmt.Fprintln(os.Stderr, "usage: md5sum [file ...]") os.Exit(1) } func main() { flag.Parse() - - if flag.NArg() == 0 { // Stdin - f := os.Stdin - h := md5.New() - var buf [64]byte - + var buf [64]byte + h := md5.New() + + if flag.NArg() == 0 { for { - switch nr, _ := f.Read(buf[:]); true { - case nr > 0: - _, e := h.Write(buf[0:nr]) - - if e != nil { - fmt.Fprintf(os.Stderr, "md5sum: error generating hash\n") - os.Exit(1) - } - case nr == 0: - s := h.Sum() - - for j := 0; j < len(s); j++ { - if s[j] < 0x10 { - fmt.Fprintf(os.Stdout, "0%0x", s[j]) - } else { - fmt.Fprintf(os.Stdout, "%0x", s[j]) - } - } - fmt.Fprintf(os.Stdout, " -\n") - return - case nr < 0: - fmt.Fprintf(os.Stderr, "md5sum: error generating hash\n") - os.Exit(1) + nr, rerr := os.Stdin.Read(buf[:]) + switch { + case nr > 0: + // h.Write never returns an error. + h.Write(buf[0:nr]) + case nr == 0: + fmt.Printf("%x\n", h.Sum(nil)) + os.Exit(0) + case nr < 0: + fmt.Fprintln(os.Stderr, "md5sum:", rerr) + os.Exit(1) } } } else { - h := md5.New() - - for i := 0; i < flag.NArg(); i++ { - d, e := ioutil.ReadFile(flag.Arg(i)) - - if e != nil { - fmt.Fprintf(os.Stderr, "md5sum: cant read file %s\n", flag.Arg(i)) - os.Exit(1) - } - - _, e = h.Write(d) - - if e != nil { - fmt.Fprintf(os.Stderr, "md5sum: error generating hash\n") + for _, v := range flag.Args() { + data, err := ioutil.ReadFile(v) + if err != nil { + fmt.Fprintln(os.Stderr, "md5sum:", err) os.Exit(1) } - s := h.Sum() - - for j := 0; j < len(s); j++ { - if s[j] < 0x10 { - fmt.Fprintf(os.Stdout, "0%0x", s[j]) - } else { - fmt.Fprintf(os.Stdout, "%0x", s[j]) - } - } - - fmt.Fprintf(os.Stdout, " %s\n", flag.Arg(i)) - - h.Reset() // Reset has for next file + // h.Write never returns an error. + h.Write(data) + fmt.Printf("%x %s\n", h.Sum(nil), v) + h.Reset() } } } - diff --git a/mkdir/Makefile b/mkdir/Makefile deleted file mode 100644 index 64e495e..0000000 --- a/mkdir/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# mkdir - make a directory -TARG = mkdir - -include ../std.mk - -pre-uninstall: - -post-install: diff --git a/mkdir/mkdir.go b/mkdir/mkdir.go index 29f46e9..e0f426d 100644 --- a/mkdir/mkdir.go +++ b/mkdir/mkdir.go @@ -1,66 +1,50 @@ package main import ( - "os" - "fmt" "flag" + "fmt" + "os" "strconv" ) -var makeParents = flag.Bool("p", false, "Create parent directories") -var mode = flag.String("m", "777", "Mode") +var ( + pflag = flag.Bool("p", false, "Create any necessary parent directories and do not complain if the target directory already exists.") + mflag = flag.String("m", "777", "Sets the permissions to be used when creating the directory.") +) -func parseMode(perm string) uint32 { +func usage() { + fmt.Fprintln(os.Stderr, "usage: mkdir [ -p ] [ -m mode ] dirname ...") + os.Exit(1) +} +func parseMode(perm string) (os.FileMode, error) { if len(perm) < 3 || len(perm) > 4 { - fmt.Fprintf( - os.Stderr, - "mkdir: Unknown mode 1\n") + fmt.Fprintf(os.Stderr, "mkdir: Unknown mode 1\n") os.Exit(1) } - - if len(perm) == 3 { - perm = "0" + perm - } - - newMode, cerr := strconv.Btoui64(perm, 8) - - if cerr != nil { - fmt.Fprintf( - os.Stderr, - "mkdir: Unknown mode\n") - os.Exit(1) - } - - return uint32(newMode) + mode, err := strconv.ParseUint(perm, 8, 32) + return os.FileMode(mode), err } func main() { flag.Parse() - - var nm uint32 = parseMode(*mode) - - if flag.NArg() > 0 { - for i := 0; i < flag.NArg(); i++ { - if *makeParents { - var err = os.MkdirAll(flag.Arg(i), 0777) - if err != nil { - fmt.Fprintf( - os.Stderr, - "mkdir: %s\n", - err.String()) - } - } else { - var err = os.Mkdir(flag.Arg(i), nm) - if err != nil { - fmt.Fprintf( - os.Stderr, - "mkdir: %s\n", - err.String()) - } + if flag.NArg() == 0 { + usage() + } + mode, err := parseMode(*mflag) + if err != nil { + fmt.Fprintln(os.Stderr, "mkdir:", err.Error()) + } + + for _, name := range flag.Args() { + if *pflag { + if err := os.MkdirAll(name, mode); err != nil { + fmt.Fprintln(os.Stderr, "mkdir:", err.Error()) + } + } else { + if err := os.Mkdir(name, mode); err != nil { + fmt.Fprintln(os.Stderr, "mkdir:", err.Error()) } - - os.Chmod(flag.Arg(i), nm) } } } diff --git a/pbd/Makefile b/pbd/Makefile deleted file mode 100644 index b9b5c3a..0000000 --- a/pbd/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# pdb - working directory -TARG = pbd - -include ../std.mk - -pre-uninstall: - -post-install: diff --git a/pbd/pbd.go b/pbd/pbd.go index d2793a6..80d7110 100644 --- a/pbd/pbd.go +++ b/pbd/pbd.go @@ -1,16 +1,16 @@ package main import ( - "os" "fmt" + "os" ) func main() { - var p, e = os.Getwd() - if e != nil { - fmt.Fprintf(os.Stderr, "pdb: can't find working directory: %s", e.String()) + if p, err := os.Getwd(); err != nil { + fmt.Fprintln(os.Stderr, "pdb: can't find working directory:", err.Error()) os.Exit(1) + } else { + fmt.Print(p) } - fmt.Fprintf(os.Stdout, p) } diff --git a/sha1sum/Makefile b/sha1sum/Makefile deleted file mode 100644 index 54a02f0..0000000 --- a/sha1sum/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# sha1sum - calculate SHA1 secure hash - -TARG = sha1sum - -include ../std.mk - -pre-uninstall: - -post-install: diff --git a/sha1sum/sha1sum.go b/sha1sum/sha1sum.go index c27a47e..52152f1 100644 --- a/sha1sum/sha1sum.go +++ b/sha1sum/sha1sum.go @@ -1,11 +1,11 @@ package main import ( - "os" - "fmt" - "flag" "crypto/sha1" + "flag" + "fmt" "io/ioutil" + "os" ) func usage() { @@ -15,70 +15,36 @@ func usage() { func main() { flag.Parse() - - if flag.NArg() == 0 { // Stdin - f := os.Stdin - h := sha1.New() - var buf [64]byte - + var buf [64]byte + h := sha1.New() + + if flag.NArg() == 0 { for { - switch nr, _ := f.Read(buf[:]); true { - case nr > 0: - _, e := h.Write(buf[0:nr]) - - if e != nil { - fmt.Fprintf(os.Stderr, "sha1sum: error generating hash\n") - os.Exit(1) - } - case nr == 0: - s := h.Sum() - - for j := 0; j < len(s); j++ { - if s[j] < 0x10 { - fmt.Fprintf(os.Stdout, "0%0x", s[j]) - } else { - fmt.Fprintf(os.Stdout, "%0x", s[j]) - } - } - fmt.Fprintf(os.Stdout, " -\n") - return - case nr < 0: - fmt.Fprintf(os.Stderr, "sha1sum: error generating hash\n") - os.Exit(1) + nr, rerr := os.Stdin.Read(buf[:]) + switch { + case nr > 0: + // h.Write never returns an error. + h.Write(buf[0:nr]) + case nr == 0: + fmt.Printf("%x\n", h.Sum(nil)) + os.Exit(0) + case nr < 0: + fmt.Fprintf(os.Stderr, "sha1sum: error reading from os.Stdin: %s\n", rerr) + os.Exit(1) } } } else { - h := sha1.New() - - for i := 0; i < flag.NArg(); i++ { - d, e := ioutil.ReadFile(flag.Arg(i)) - - if e != nil { - fmt.Fprintf(os.Stderr, "sha1sum: cant read file %s\n", flag.Arg(i)) - os.Exit(1) - } - - _, e = h.Write(d) - - if e != nil { - fmt.Fprintf(os.Stderr, "sha1sum: error generating hash\n") + for _, v := range flag.Args() { + data, err := ioutil.ReadFile(v) + if err != nil { + fmt.Fprintf(os.Stderr, "sha1sum: error reading file %s: %s\n", v, err) os.Exit(1) } - s := h.Sum() - - for j := 0; j < len(s); j++ { - if s[j] < 0x10 { - fmt.Fprintf(os.Stdout, "0%0x", s[j]) - } else { - fmt.Fprintf(os.Stdout, "%0x", s[j]) - } - } - - fmt.Fprintf(os.Stdout, " %s\n", flag.Arg(i)) - - h.Reset() // Reset has for next file + // h.Write never returns an error. + h.Write(data) + fmt.Printf("%x %s\n", h.Sum(nil), v) + h.Reset() } } } - diff --git a/sleep/Makefile b/sleep/Makefile deleted file mode 100644 index d570d9a..0000000 --- a/sleep/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# sleep - suspend execution for an interval -TARG = sleep - -include ../std.mk - -pre-uninstall: - -post-install: diff --git a/sleep/sleep.go b/sleep/sleep.go index 84061b6..d29965d 100644 --- a/sleep/sleep.go +++ b/sleep/sleep.go @@ -1,12 +1,10 @@ package main import ( - "os" - "time" "flag" "fmt" - "strconv" - "math" + "os" + "time" ) func main() { @@ -17,16 +15,10 @@ func main() { os.Exit(1) } - secs, err := strconv.Atof64(flag.Arg(0)) - - if err != nil { + if t, err := time.ParseDuration(flag.Arg(0)); err != nil { fmt.Fprintf(os.Stderr, "sleep: Unknown Argument\n") os.Exit(1) + } else { + time.Sleep(t) } - - nsfp := secs * math.Pow10(9) - - nsi, _ := math.Modf(nsfp) - - time.Sleep(int64(nsi)) } diff --git a/std.mk b/std.mk deleted file mode 100644 index 29adafe..0000000 --- a/std.mk +++ /dev/null @@ -1,33 +0,0 @@ -# std.mk - included by most Makefiles in subdirs - -include ../config.mk - -OFILES ?= ${TARG}.$O -MANFILE ?= ${TARG}.1 - -all: ${TARG} - @echo built ${TARG} - -install: install-default post-install - -install-default: ${TARG} - @mkdir -p ${DESTDIR}${PREFIX}/bin - @cp -f ${TARG} ${DESTDIR}${PREFIX}/bin/ - @chmod 755 ${DESTDIR}${PREFIX}/bin/${TARG} - @mkdir -p ${DESTDIR}${MANPREFIX}/man1 - @cp -f ${MANFILE} ${DESTDIR}${MANPREFIX}/man1/ - @chmod 444 ${DESTDIR}${MANPREFIX}/man1/${MANFILE} - -uninstall: pre-uninstall - rm -f ${DESTDIR}${PREFIX}/bin/${TARG} - rm -f ${DESTDIR}${MANPREFIX}/man1/${MANFILE} - -%.$O:%.go - $(GC) -o $@ $^ - -clean: - rm -f ${OFILES} ${TARG} - -${TARG}: ${OFILES} - $(LD) -o $@ $^ - diff --git a/tee/Makefile b/tee/Makefile deleted file mode 100644 index 114a21c..0000000 --- a/tee/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# tee - pipe fitting - -TARG = tee - -include ../std.mk - -pre-uninstall: - -post-install: diff --git a/tee/tee.go b/tee/tee.go index d021edf..efe6d6e 100644 --- a/tee/tee.go +++ b/tee/tee.go @@ -1,87 +1,58 @@ +// tee - pipe fitting + package main import ( - "os" - "fmt" "flag" - "container/vector" + "fmt" + "os" ) - -var ignoreInterrupts = flag.Bool("i", false, "Ignore interrupts") -var appendOutput = flag.Bool("a", false, "Append the output to the files rather than rewriting them") +var aflag = flag.Bool("a", false, "Append the output to the files rather than rewriting them") func main() { flag.Parse() - var vec vector.Vector - - vec.Push(os.Stdout) - - if *ignoreInterrupts { - fmt.Fprintf(os.Stdout, "tee: -i flag not supported\n") - os.Exit(1) - } - - for i := 0; i < flag.NArg(); i++ { - if *appendOutput { - f, e := os.Open(flag.Arg(i), os.O_CREAT | os.O_WRONLY | os.O_APPEND, 0666) - - if e != nil { - fmt.Fprintf( - os.Stderr, - "tee: unable to open file %s: %s\n", - flag.Arg(i), - e.String()) - os.Exit(1) - } + files := make([]*os.File, 0, flag.NArg() + 1) + files = append(files, os.Stdout) - vec.Push(f) + for _, v := range flag.Args() { + var f *os.File + var err error + + if *aflag { + f, err = os.OpenFile(v, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) } else { - f, e := os.Open(flag.Arg(i), os.O_CREAT | os.O_WRONLY, 0666) - - if e != nil { - fmt.Fprintf( - os.Stderr, - "tee: unable to open file %s: %s\n", - flag.Arg(i), - e.String()) - os.Exit(1) - } + f, err = os.Create(v) + } + defer f.Close() - vec.Push(f) + if err != nil { + fmt.Fprintf(os.Stderr, "tee: unable to open file %s: %s\n", v, err.Error()) + os.Exit(1) } + files = append(files, f) } - // Copied from cat.go var buf [64]byte f := os.Stdin for { - switch nr, _ := f.Read(buf[:]); true { - case nr > 0: - for x := 0; x < len(vec); x++ { - el := vec.At(x).(*os.File) - _, e := el.Write(buf[0:nr]) - - if e != nil { - fmt.Fprintf( - os.Stderr, - "tee: error writting to file %s: %s\n", - el.Name(), - e.String()) - os.Exit(1) - } + switch nr, rerr := f.Read(buf[:]); true { + case nr > 0: + for _, f := range files { + _, err := f.Write(buf[0:nr]) + + if err != nil { + fmt.Fprintf(os.Stderr, "tee: error writting to file %s: %s\n", f.Name(), err.Error()) + os.Exit(1) } - case nr == 0: - for x := 0; x < len(vec); x++ { - el := vec.At(x).(*os.File) - el.Close() - } - return - case nr < 0: - fmt.Fprintf(os.Stderr, "tee: error reading from stdin\n") - os.Exit(1) + } + case nr == 0: + os.Exit(0) + case nr < 0: + fmt.Fprintln(os.Stderr, "tee: error reading from stdin:", rerr) + os.Exit(1) } } } diff --git a/touch/Makefile b/touch/Makefile deleted file mode 100644 index e6dae25..0000000 --- a/touch/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# touch - set modification date of a file -TARG = touch - -include ../std.mk - -pre-uninstall: - -post-install: diff --git a/touch/touch.1 b/touch/touch.1 deleted file mode 100644 index 962b34a..0000000 --- a/touch/touch.1 +++ /dev/null @@ -1,24 +0,0 @@ -.TH TOUCH 1 -.SH NAME -touch \- set modification date of a file -.SH SYNOPSIS -.B touch -[ -.B -c -] -[ -.B -t time -] -.I files ... -.SH DESCRIPTION -.PP -.B Touch -attempts to set the modification time of the -.B files -to -.B time -(by default, the current time). If a -.B file -does not exist, it will be created unless option -.B -c -is present. diff --git a/touch/touch.go b/touch/touch.go index 886d991..be6af32 100644 --- a/touch/touch.go +++ b/touch/touch.go @@ -5,62 +5,41 @@ import ( "os" "flag" "fmt" - "syscall" "time" ) -var create = flag.Bool("c", false, "Don't create if not exists") -var newTime = flag.Int("t", int(time.Seconds()), "Set to time provided") +var ( + aflag = flag.Bool("a", false, "Change access time instead of modification time") + tflag = flag.Int("t", 0, "Set to time provided") +) func usage() { - fmt.Fprintf( - os.Stderr, - "usage: touch [-c] [-t time] names...\n") + fmt.Fprintf(os.Stderr, "usage: touch [-c] [-t time] names...\n") os.Exit(1) } func main() { flag.Parse(); - if flag.NArg() < 1 { usage() } - - for i := 0; i < flag.NArg(); i++ { - var name = flag.Arg(i) - var tb syscall.Utimbuf - tb.Actime = (int32)(*newTime) - tb.Modtime = (int32)(*newTime) - var e = syscall.Utime(name, &tb) - - if (e != 0) && *create { - fmt.Fprintf( - os.Stderr, - "touch: cannot touch `%s'\n", - name) - os.Exit(1) + var atime, mtime time.Time + if *tflag == 0 { + if *aflag { + atime = time.Now() + } else { + mtime = time.Now() } - - f, err := os.Open(name, os.O_CREAT, 0666) - if err != nil { - fmt.Fprintf( - os.Stderr, - "touch: cannot touch `%s': %s\n", - name, - err.String()) - os.Exit(1) + } else { + if *aflag { + atime = time.Unix(int64(*tflag), 0) + } else { + mtime = time.Unix(int64(*tflag), 0) } - f.Close() - - e = syscall.Utime(name, &tb) - if e != 0{ - fmt.Fprintf( - os.Stderr, - "touch: cannot touch `%s'\n", - name) - os.Exit(1) + } + for _, name := range flag.Args() { + if err := os.Chtimes(name, atime, mtime); err != nil { + fmt.Fprintln(os.Stderr, "touch: cannot touch %s: %s", name, err.Error()) } } - - os.Exit(0) -} +} \ No newline at end of file diff --git a/wc/wc.go b/wc/wc.go new file mode 100644 index 0000000..98150dd --- /dev/null +++ b/wc/wc.go @@ -0,0 +1,353 @@ +// Copyright 2011 Robert Bloomquist + +// NAME +// wc - count lines, words, and characters +// +// SYNOPSIS +// wc [ -lwceb ] [ file ... ] +// +// DESCRIPTION +// Wc writes to standard output a tally of lines, words, and +// characters found in each file, assumed to be text in UTF +// format. If no files are named, standard input is read. One +// line is output per file. If several files are specified, an +// additional line is written giving totals. +// +// `Words' are maximal sequences of characters separated by +// blanks, tabs and newlines. +// +// Counts are output in the same order as the listing of the +// option letters lwceb; select lines, words, UTF characters, +// erroneously-encoded characters, and bytes, respectively. If +// no options are given, lines, words, and characters are +// counted. +// +// BUGS +// The Unicode Standard has many blank characters scattered +// through it, but wc looks for only ASCII space, tab, and new- +// line. +// +// Wc should have options to count suboptimal UTF codes and +// bytes that cannot occur in any UTF code. + +package main + +import ( + "flag" + "fmt" + "os" +) + +const NBUF = 8 * 1024 + +// Command-line flags +var ( + lflag = flag.Bool("l", false, "print number of lines") + wflag = flag.Bool("w", false, "print number of words") + cflag = flag.Bool("c", false, "print number of characters") + eflag = flag.Bool("e", false, "print number of erroneously-encoded characters") + bflag = flag.Bool("b", false, "print number of bytes") +) + +type counter struct { + lines, words, chars, errors, bytes uint64 +} + +func report(c *counter, name string) { + var s string + if *lflag { + s += fmt.Sprintf("%7d", c.lines) + } + if *wflag { + s += fmt.Sprintf("%7d", c.words) + } + if *cflag { + s += fmt.Sprintf("%7d", c.chars) + } + if *eflag { + s += fmt.Sprintf("%7d", c.errors) + } + if *bflag { + s += fmt.Sprintf("%7d", c.bytes) + } + s += " " + name + "\n" + os.Stdout.WriteString(s) +} + +// How it works. Start in statesp. Each time we read a character, +// increment various counts, and do state transitions according to the +// following table. If we're not in statesp or statewd when done, the +// file ends with a partial rune. +// | character +// state |09,20| 0a |00-7f|80-bf|c0-df|e0-ef|f0-ff +// -------+-----+-----+-----+-----+-----+-----+----- +// statesp|ASP |ASPN |AWDW |AWDWX|AC2W |AC3W |AWDWX +// statewd|ASP |ASPN |AWD |AWDX |AC2 |AC3 |AWDX +// statec2|ASPX |ASPNX|AWDX |AWDR |AC2X |AC3X |AWDX +// statec3|ASPX |ASPNX|AWDX |AC2R |AC2X |AC3X |AWDX + +const ( // actions + AC2 = iota // enter statec2 + AC2R // enter statec2, don't count a rune + AC2W // enter statec2, count a word + AC2X // enter statec2, count a bad rune + AC3 // enter statec3 + AC3W // enter statec3, count a word + AC3X // enter statec3, count a bad rune + ASP // enter statesp + ASPN // enter statesp, count a newline + ASPNX // enter statesp, count a newline, count a bad rune + ASPX // enter statesp, count a bad rune + AWD // enter statewd + AWDR // enter statewd, don't count a rune + AWDW // enter statewd, count a word + AWDWX // enter statewd, count a word, count a bad rune + AWDX // enter statewd, count a bad rune +) + +var statesp = [256]byte{ // looking for the start of a word + AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, // 00-07 + AWDW, ASP, ASPN, AWDW, AWDW, AWDW, AWDW, AWDW, // 08-0f + AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, // 10-17 + AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, // 18-1f + ASP, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, // 20-27 + AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, // 28-2f + AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, // 30-37 + AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, // 38-3f + AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, // 40-47 + AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, // 48-4f + AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, // 50-57 + AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, // 58-5f + AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, // 60-67 + AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, // 68-6f + AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, // 70-77 + AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, // 78-7f + AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, // 80-87 + AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, // 88-8f + AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, // 90-97 + AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, // 98-9f + AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, // a0-a7 + AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, // a8-af + AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, // b0-b7 + AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, // b8-bf + AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, // c0-c7 + AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, // c8-cf + AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, // d0-d7 + AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, // d8-df + AC3W, AC3W, AC3W, AC3W, AC3W, AC3W, AC3W, AC3W, // e0-e7 + AC3W, AC3W, AC3W, AC3W, AC3W, AC3W, AC3W, AC3W, // e8-ef + AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, // f0-f7 + AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, AWDWX, // f8-ff +} + +var statewd = [256]byte{ // looking for the next character in a word + AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, // 00-07 + AWD, ASP, ASPN, AWD, AWD, AWD, AWD, AWD, // 08-0f + AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, // 10-17 + AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, // 18-1f + ASP, AWD, AWD, AWD, AWD, AWD, AWD, AWD, // 20-27 + AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, // 28-2f + AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, // 30-37 + AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, // 38-3f + AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, // 40-47 + AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, // 48-4f + AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, // 50-57 + AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, // 58-5f + AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, // 60-67 + AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, // 68-6f + AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, // 70-77 + AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, // 78-7f + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 80-87 + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 88-8f + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 90-97 + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 98-9f + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // a0-a7 + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // a8-af + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // b0-b7 + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // b8-bf + AC2, AC2, AC2, AC2, AC2, AC2, AC2, AC2, // c0-c7 + AC2, AC2, AC2, AC2, AC2, AC2, AC2, AC2, // c8-cf + AC2, AC2, AC2, AC2, AC2, AC2, AC2, AC2, // d0-d7 + AC2, AC2, AC2, AC2, AC2, AC2, AC2, AC2, // d8-df + AC3, AC3, AC3, AC3, AC3, AC3, AC3, AC3, // e0-e7 + AC3, AC3, AC3, AC3, AC3, AC3, AC3, AC3, // e8-ef + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // f0-f7 + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // f8-ff +} + +var statec2 = [256]byte{ // looking for 10xxxxxx to complete a rune + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 00-07 + AWDX, ASPX, ASPNX, AWDX, AWDX, AWDX, AWDX, AWDX, // 08-0f + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 10-17 + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 18-1f + ASPX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 20-27 + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 28-2f + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 30-37 + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 38-3f + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 40-47 + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 48-4f + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 50-57 + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 58-5f + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 60-67 + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 68-6f + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 70-77 + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 78-7f + AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, // 80-87 + AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, // 88-8f + AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, // 90-97 + AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, // 98-9f + AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, // a0-a7 + AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, // a8-af + AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, // b0-b7 + AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, // b8-bf + AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, // c0-c7 + AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, // c8-cf + AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, // d0-d7 + AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, // d8-df + AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, // e0-e7 + AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, // e8-ef + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // f0-f7 + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // f8-ff +} + +var statec3 = [256]byte{ // looking for 10xxxxxx,10xxxxxx to complete a rune + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 00-07 + AWDX, ASPX, ASPNX, AWDX, AWDX, AWDX, AWDX, AWDX, // 08-0f + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 10-17 + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 18-1f + ASPX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 20-27 + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 28-2f + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 30-37 + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 38-3f + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 40-47 + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 48-4f + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 50-57 + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 58-5f + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 60-67 + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 68-6f + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 70-77 + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // 78-7f + AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, // 80-87 + AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, // 88-8f + AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, // 90-97 + AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, // 98-9f + AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, // a0-a7 + AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, // a8-af + AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, // b0-b7 + AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, // b8-bf + AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, // c0-c7 + AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, // c8-cf + AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, // d0-d7 + AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, // d8-df + AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, // e0-e7 + AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, // e8-ef + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // f0-f7 + AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, // f8-ff +} + +func count(n *counter, f *os.File) { + state := statesp[:] + var buf [NBUF]byte + n.lines = 0 + n.words = 0 + n.chars = 0 + n.errors = 0 + n.bytes = 0 + for { + nr, er := f.Read(buf[:]) + if nr == 0 { + break + } + if nr < 0 { + fmt.Fprintf(os.Stderr, "wc: error reading from %s: %s\n", f.Name(), er.Error()) + os.Exit(1) + } + n.bytes += uint64(nr) + n.chars += uint64(nr) // might be too large, gets decreased later + for i := 0; i < nr; i++ { + switch state[buf[i]] { + case AC2: + state = statec2[:] + case AC2R: + state = statec2[:] + n.chars-- + case AC2W: + state = statec2[:] + n.words++ + case AC2X: + state = statec2[:] + n.errors++ + case AC3: + state = statec3[:] + case AC3W: + state = statec3[:] + n.words++ + case AC3X: + state = statec3[:] + n.errors++ + case ASP: + state = statesp[:] + case ASPN: + state = statesp[:] + n.lines++ + case ASPNX: + state = statesp[:] + n.lines++ + n.errors++ + case ASPX: + state = statesp[:] + n.errors++ + case AWD: + state = statewd[:] + case AWDR: + state = statewd[:] + n.chars-- + case AWDW: + state = statewd[:] + n.words++ + case AWDWX: + state = statewd[:] + n.words++ + n.errors++ + case AWDX: + state = statewd[:] + n.errors++ + } + } + } +} + +func main() { + n := new(counter) + t := new(counter) + + flag.Parse() + if flag.NFlag() == 0 { + *lflag = true + *wflag = true + *cflag = true + } + + if flag.NArg() == 0 { + count(n, os.Stdin) + report(n, "") + } + for i := 0; i < flag.NArg(); i++ { + f, err := os.Open(flag.Arg(i)) + defer f.Close() + if err != nil { + fmt.Fprintf(os.Stderr, "wc: can't open %s: error %s\n", flag.Arg(i), err) + os.Exit(1) + } + count(n, f) + t.lines += n.lines + t.words += n.words + t.chars += n.chars + t.errors += n.errors + t.bytes += n.bytes + report(n, flag.Arg(i)) + } + if flag.NArg() > 1 { + report(t, "total") + } +}