Still learning and playing with Go, I’ve rewritten my cat experiment, to use a *bufio.Reader, which is more correct I think. I’m also slowly wrapping my mind around the concept of Interfaces. As a non-OO programmer (C and non-OO Perl) is starting to see why this is useful.

So today’s exercises:

  1. Write a cat implementation in Go. See below.
  2. Write a grep implementation in Go. See below.

Cat in go

package main

// A implementation of cat in Go

import (
    "os";
    "fmt";
    "bufio";
    "flag";
)

var numberFlag = flag.Bool("n", false, "number each line")

func cat(r *bufio.Reader) bool {
    i := 1;
    for {
	    buf, e := r.ReadBytes('\n');
	    if e == os.EOF {
		    break
	    }
	    if *numberFlag {
		    fmt.Fprintf(os.Stdout, "%5d  %s", i, buf);
		    i++
	    } else {
		    fmt.Fprintf(os.Stdout, "%s", buf)
	    }
    }
    return true;
}

func main() {
    flag.Parse();
    if flag.NArg() == 0 {
	    cat(bufio.NewReader(os.Stdin))
    }
    for i := 0; i < flag.NArg(); i++ {
	    f, e := os.Open(flag.Arg(i), os.O_RDONLY, 0);
	    if e != nil {
		    fmt.Fprintf(os.Stderr, "%s: error reading from %s: %s\n",
			    os.Args[0], flag.Arg(i), e.String());
		    continue;
	    }
	    if !cat(bufio.NewReader(f)) {
		    os.Exit(1)
	    }
    }
}

Grep in go

package main

// A implementation of Unix grep in Go
// TODO(mg) better error handling

import (
    "os";
    "fmt";
    "bufio";
    "regexp";
    "flag";
)

var numberFlag = flag.Bool("n", false, "number each line")
var filenameFlag = flag.Bool("l", false, "print names of matching files")

func grep(r *bufio.Reader, reg string) (match bool) {
    i := 0;
    for {
	    buf, e := r.ReadBytes('\n');
	    i++;
	    if e == os.EOF {
		    break
	    }
	    if m, _ := regexp.Match(reg, buf); m == true {
		    match = true;
		    if *filenameFlag {
			    return match
		    }
		    if *numberFlag {
			    fmt.Fprintf(os.Stdout, "%5.d:  %s", i, buf)
		    } else {
			    fmt.Fprintf(os.Stdout, "%s", buf)
		    }
	    }
    }
    return match;
}

func main() {
    flag.Parse();
    if flag.NArg() < 1 {
	    fmt.Fprintf(os.Stderr, "%s: missing regexp\n", os.Args[0]);
	    os.Exit(1);
    }
    if flag.NArg() == 1 {
	    if grep(bufio.NewReader(os.Stdin), flag.Arg(0)) {
		    if *filenameFlag {
			    fmt.Fprintf(os.Stdout, "(standard input)\n");
		    }
	    }
    }
    for i := 1; i < flag.NArg(); i++ {
	    f, e := os.Open(flag.Arg(i), os.O_RDONLY, 0);
	    if e != nil {
		    fmt.Fprintf(os.Stderr, "%s: error reading from %s: %s\n",
			    os.Args[0], flag.Arg(i), e.String());
		    continue;
	    }
	    if grep(bufio.NewReader(f), flag.Arg(0)) {
		    if *filenameFlag {
			    fmt.Fprintf(os.Stdout, "%s\n", flag.Arg(i))
		    }
	    }
    }
}