Source File: go-coreutils/od/main.go

package main

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

func Fail(err error, format string, v ...any) {
  err_format := fmt.Sprintf("ERROR: %v; %s", err, format)
  log.Printf(err_format, v...)
  os.Exit(1)
}

type Opts struct {
  Width int
  Filenames []string
  Hex bool
  Octal bool
  Format string
}

func parse_opts() (Opts) {
  var opts Opts

  flag.IntVar(&opts.Width, "w", 16, "Width of output grid")
  flag.BoolVar(&opts.Hex, "x", false, "Output hex bytes")
  flag.BoolVar(&opts.Octal, "o", false, "Output octal bytes")

  flag.Parse()

  if flag.NArg() == 0 {
    log.Fatal("USAGE: od [files]")
  }

  if opts.Hex {
    opts.Format = "%0.2x "
  } else {
    opts.Format = "%0.3o "
  }

  opts.Filenames = flag.Args()
  return opts
}

func main() {
  opts := parse_opts()

  for _, filename := range opts.Filenames {
    reader, err := os.Open(filename)
    defer reader.Close()
    if err != nil { Fail(err, "can't open: %s", filename) }

    buf := bufio.NewReader(reader)
    count := buf.Size()

    fmt.Printf("%0.8o ", 0);

    for index := 0; index < count; index++ {
      data, err := buf.ReadByte()
      if err != nil { break }
      fmt.Printf(opts.Format, data);

      if (index + 1) % opts.Width == 0 {
        fmt.Print("\n")
        fmt.Printf("%0.8o ", index);
      }
    }
  }
}