Monday, August 13, 2012

A Tool to Escape HTML Characters in Go

I created a handy tool to escape HTML characters, especially for pasting code in a blog like this.
Usage: ./escapehtml  [dest_dir]
If the source is a directory, the tool will scan the whole directory and escape each file found and output the escaped string to stdout (if dest_dir isn't specified) or to a file (if dest_dir is specified).
escapehtml.go
package main

import (
    "fmt"
    "os"
    "errors"
    "path/filepath"
    "io/ioutil"
    "html"
    "strings"
)

func printUsage() {
    fmt.Println("Usage:", os.Args[0],
        "<source_file/source_dir>", "[dest_dir]")
}

func errorMessage(s string) string {
    return "Error: " + s
}

type fileType struct {
    directory bool
    regularFile bool
}

func fileExists(path string) (*fileType, error) {
    file, err := os.Open(path)
    if err != nil {
        if os.IsNotExist(err) {
            return nil, errors.New(
                errorMessage(path + " does not exist"))
        }
    }
    defer file.Close()
    fileInfo, err := file.Stat()
    if err != nil {
        return nil, err
    }
    if fileInfo.IsDir() {
        return &fileType{directory: true}, nil
    }
    return &fileType{regularFile: true}, nil
}

func validateArgs() (bool, error) {
    if len(os.Args) != 2 && len(os.Args) != 3 {
        return false, nil
    }

    if _, err := fileExists(os.Args[1]); err != nil {
        return false, err
    }
    if len(os.Args) == 3 {
        ft, _ := fileExists(os.Args[2])
        if ft != nil && !ft.directory {
            return false, errors.New(
                errorMessage(os.Args[2] + " must be a directory"))
        }
    }
    return true, nil
}

func printHeader(header string) {
    fmt.Println(strings.Repeat("=", 72))
    fmt.Println(header)
    fmt.Println(strings.Repeat("=", 72))
}

func escapeHTML(srcPath string, destPath string) {
    filepath.Walk(srcPath,
        func(path string, info os.FileInfo, err error) error {
            if info.IsDir() {
                return nil
            }

            b, err := ioutil.ReadFile(path)
            if err != nil {
                return nil
            }

            escapedString := html.EscapeString(string(b))
            if destPath == "" {
                printHeader(path)
                fmt.Println(escapedString)
            } else {
                if ft, _ := fileExists(destPath); ft == nil {
                    if e := os.MkdirAll(destPath, 0775); e != nil {
                        errors.New("Unable to create directory: " +
                            destPath)
                    } else {
                        fmt.Println("Creating directory: " + destPath)
                    }
                }
                newPath := filepath.Join(destPath,
                    filepath.Base(path) + ".txt")
                fmt.Println("Creating", newPath)
                e := ioutil.WriteFile(newPath, []byte(escapedString), 0644)
                if e != nil {
                    return e
                }
            }
            return nil
        })
}

func main() {
    if valid, err := validateArgs(); !valid {
        if err != nil {
            fmt.Println(err)
            os.Exit(1)
        } else {
            printUsage()
            os.Exit(1)
        }
    }

    srcPath := os.Args[1]
    destPath := ""
    if len(os.Args) == 3 {
        destPath = os.Args[2]
    }
    escapeHTML(srcPath, destPath)
}
To build it, just type
go build escapehtml.go

No comments:

Post a Comment