package main import ( "bytes" _ "embed" "fmt" "github.com/mholt/archiver/v4" "log" "net/http" "os" "os/exec" "strings" ) var m2h = "/home/sophuwu/Documents/project/manpages/build/mh.2" //go:embed index.html var index []byte //go:embed font.css var font []byte //go:embed dark_theme.css var css []byte var CFG struct { Hostname string ListenAddr string ListenPort string MANPATH string Pandoc string } func cmdout(s string) string { ss := strings.Split(s, " ") b, e := exec.Command("/usr/bin/"+ss[0], ss[1:]...).Output() if e != nil { log.Fatal("Fatal: unable to get " + ss[0]) } return strings.TrimSpace(string(b)) } func init() { CFG.MANPATH = cmdout("manpath -g") CFG.Hostname = cmdout("hostname") CFG.ListenAddr = os.Getenv("ListenAddr") CFG.ListenPort = os.Getenv("ListenPort") if CFG.ListenPort == "" { CFG.ListenPort = "8082" } b, _ := exec.Command("which", "pandoc").Output() CFG.Pandoc = strings.TrimSpace(string(b)) css = append(css, font...) } func main() { http.HandleFunc("/style.css", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/css; charset=utf-8") w.Header().Set("Content-Length", fmt.Sprint(len(css))) w.WriteHeader(http.StatusOK) w.Write(css) }) http.Handle("/favicon.ico", http.NotFoundHandler()) http.HandleFunc("/", indexHandler) http.ListenAndServe(CFG.ListenAddr+":"+CFG.ListenPort, nil) } type ManPage struct { Section string Name string Path string WhatIs string } func readCompressed(fh *os.File, buff *bytes.Buffer) error { decompressor, err := archiver.Gz{}.OpenReader(fh) if err != nil { return err } defer decompressor.Close() _, err = buff.ReadFrom(decompressor) return err } func ReadFh(path string) (string, error) { var buff bytes.Buffer fh, err := os.OpenFile(path, os.O_RDONLY, 0) if err != nil { return "", err } defer fh.Close() if strings.HasSuffix(path, ".gz") { err = readCompressed(fh, &buff) return buff.String(), err } _, err = buff.ReadFrom(fh) return buff.String(), err } func runM2h(input string, host string) (string, error) { var inbuff bytes.Buffer inbuff.WriteString(input) cmd := exec.Command(m2h, "-H", host, "-M", "/", "-") cmd.Stdin = &inbuff b, err := cmd.Output() return string(b), err } func pandocConvert(input string) (string, error) { if CFG.Pandoc == "" { return "", fmt.Errorf("pandoc not found, required for syntax conversion") } cmd := exec.Command(CFG.Pandoc, "-st", "man", "-f", "man") cmd.Env = append(cmd.Env, os.Environ()...) cmd.Stdin = strings.NewReader(input) b, err := cmd.Output() return string(b), err } func (m *ManPage) html(w http.ResponseWriter, r *http.Request) error { if m.Path == "" { return fmt.Errorf("no path") } var b, fh string var err error fh, err = ReadFh(m.Path) if err != nil { return err } b, err = runM2h(fh, r.Host) if err != nil { return fmt.Errorf("page not found") } if strings.Contains(b, "