diff --git a/cmd/dumpbytes/main.go b/cmd/dumpbytes/main.go new file mode 100644 index 0000000..defccbc --- /dev/null +++ b/cmd/dumpbytes/main.go @@ -0,0 +1,71 @@ +package main + +import ( + "flag" + "fmt" + "git.wntrmute.dev/kyle/goutils/die" + "io" + "os" +) + +func usage(w io.Writer, exc int) { + fmt.Fprintln(w, `usage: dumpbytes `) + os.Exit(exc) +} + +func printBytes(buf []byte) { + fmt.Printf("\t") + for i := 0; i < len(buf); i++ { + fmt.Printf("0x%02x, ", buf[i]) + } + fmt.Println() +} + +func dumpFile(path string, indentLevel int) error { + indent := "" + for i := 0; i < indentLevel; i++ { + indent += "\t" + } + + file, err := os.Open(path) + if err != nil { + return err + } + + defer file.Close() + + fmt.Printf("%svar buffer = []byte{\n", indent) + for { + buf := make([]byte, 8) + n, err := file.Read(buf) + if err == io.EOF { + if n > 0 { + fmt.Printf("%s", indent) + printBytes(buf[:n]) + } + break + } + + if err != nil { + return err + } + + fmt.Printf("%s", indent) + printBytes(buf[:n]) + } + + fmt.Printf("%s}\n", indent) + return nil +} + +func main() { + indent := 0 + flag.Usage = func() { usage(os.Stderr, 0) } + flag.IntVar(&indent, "n", 0, "indent level") + flag.Parse() + + for _, file := range flag.Args() { + err := dumpFile(file, indent) + die.If(err) + } +} diff --git a/cmd/zsearch/main.go b/cmd/zsearch/main.go new file mode 100644 index 0000000..c2c9adc --- /dev/null +++ b/cmd/zsearch/main.go @@ -0,0 +1,136 @@ +// zsearch is a utility for searching zlib-compressed files for a +// search string. It was really designed for use with the Git object +// store, i.e. to aid in the recovery of files after Git does what Git +// do. +package main + +import ( + "bufio" + "bytes" + "compress/zlib" + "flag" + "fmt" + "io" + "os" + "path/filepath" + "regexp" +) + +const defaultDirectory = ".git/objects" + +func errorf(format string, a ...interface{}) { + fmt.Fprintf(os.Stderr, format, a...) + if format[len(format)-1] != '\n' { + fmt.Fprintf(os.Stderr, "\n") + } +} + +func isDir(path string) bool { + fi, err := os.Stat(path) + if err != nil { + return false + } + + return fi.IsDir() +} + +func loadFile(path string) ([]byte, error) { + file, err := os.Open(path) + if err != nil { + return nil, err + } + defer file.Close() + + buf := new(bytes.Buffer) + zread, err := zlib.NewReader(file) + if err != nil { + return nil, err + } + defer zread.Close() + + _, err = io.Copy(buf, zread) + if err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +func showFile(path string) { + fileData, err := loadFile(path) + if err != nil { + errorf("%v", err) + return + } + + fmt.Printf("%s\n", fileData) +} + +func searchFile(path string, search *regexp.Regexp) error { + file, err := os.Open(path) + if err != nil { + errorf("%v") + return err + } + defer file.Close() + + zread, err := zlib.NewReader(file) + if err != nil { + errorf("%v", err) + return err + } + defer zread.Close() + + zbuf := bufio.NewReader(zread) + if search.MatchReader(zbuf) { + fileData, err := loadFile(path) + if err != nil { + errorf("%v", err) + return err + } + fmt.Printf("%s:\n%s\n", path, fileData) + } + return nil +} + +func buildWalker(searchExpr *regexp.Regexp) filepath.WalkFunc { + return func(path string, info os.FileInfo, err error) error { + if info.Mode().IsRegular() { + return searchFile(path, searchExpr) + } + return nil + } +} + +func main() { + flSearch := flag.String("s", "", "search string (should be an RE2 regular expression)") + flag.Parse() + + if *flSearch == "" { + for _, path := range flag.Args() { + showFile(path) + } + } else { + search, err := regexp.Compile(*flSearch) + if err != nil { + errorf("Bad regexp: %v", err) + return + } + + pathList := flag.Args() + if len(pathList) == 0 { + pathList = []string{defaultDirectory} + } + + for _, path := range pathList { + if isDir(path) { + err := filepath.Walk(path, buildWalker(search)) + if err != nil { + errorf("%v", err) + return + } + } else { + searchFile(path, search) + } + } + } +}