diff options
-rw-r--r-- | data.go | 175 | ||||
-rw-r--r-- | main.go | 190 | ||||
-rw-r--r-- | types.go | 26 |
3 files changed, 391 insertions, 0 deletions
@@ -0,0 +1,175 @@ +package main + +import ( + "fmt" + "os/exec" + "strings" +) + +var IEEESA = Vendor{ + Name: "IEEE-SA", + GetURL: func(id string) string { return fmt.Sprintf("http://standards.ieee.org/findstds/standard/%s.html", id) }, + GetName: func(id string, url string) string { + d, _ := exec.Command("nokogiri", url, "-e", `puts $_.css("meta[name=\"des\"]").first["content"]`).Output() + return strings.TrimSuffix(string(d), "\n") + }, +} + +var IEEEXplore = Vendor{ + Name: "IEEE Xplore", + GetURL: func(id string) string { return fmt.Sprintf("http://ieeexplore.ieee.org/servlet/opac?punumber=%s", id) }, + GetName: func(id string, url string) string { + d, _ := exec.Command("sh", "-c", `curl -sL "$1"|grep -o '"standardNumber":"[^"]*"'|cut -d'"' -f4`, "--", url).Output() + return strings.TrimSuffix(string(d), "\n") + }, +} + +var TOG = Vendor{ + Name: "The Open Group", + GetURL: func(id string) string { return fmt.Sprintf("https://www2.opengroup.org/ogsys/catalog/%s", id) }, + GetName: func(id string, url string) string { return id }, +} + +var TOGOnline = Vendor{ + Name: "online", + GetURL: func(id string) string { return fmt.Sprintf("http://pubs.opengroup.org/onlinepubs/%s/", id) }, + GetName: func(id string, url string) string { return url }, +} + +var ISO = Vendor{ + Name: "ISO", + GetURL: func(id string) string { + return fmt.Sprintf("http://www.iso.org/iso/home/store/catalogue_tc/catalogue_detail.htm?csnumber=%s", id) + }, + GetName: func(id string, url string) string { + d, _ := exec.Command("nokogiri", url, "-e", `puts $_.css("[itemprop=\"name\"]").first.text`).Output() + return strings.TrimSuffix(string(d), "\n") + }, +} + +var Vendors = []Vendor{IEEESA, TOG, ISO} + +var Editions = []Edition{ + {Name: "POSIX-2001 (Issue 6)", Docs: []Document{ + {Vendor: IEEESA, Type: Full, ID: "1003.1-2001", Resellers: []Document{ + {Vendor: IEEEXplore, Type: Full, ID: "7683"}, + }}, + }}, + {Name: "----->XBD-2001", Docs: []Document{ + {Vendor: TOG, Type: Full, ID: "C950"}, + {Vendor: ISO, Type: Full, ID: "37312"}, + }}, + {Name: "----->XSH-2001", Docs: []Document{ + {Vendor: TOG, Type: Full, ID: "C951"}, + {Vendor: ISO, Type: Full, ID: "37313"}, + }}, + {Name: "----->XCU-2001", Docs: []Document{ + {Vendor: TOG, Type: Full, ID: "C952"}, + {Vendor: ISO, Type: Full, ID: "37314"}, + }}, + {Name: "----->XRAT-2001", Docs: []Document{ + {Vendor: TOG, Type: Full, ID: "C953"}, + {Vendor: ISO, Type: Full, ID: "37315"}, + }}, + + {Name: "POSIX-2001, 2002 Edition", Docs: []Document{ + {Vendor: IEEESA, Type: Patch, ID: "1003.1-2001-Cor_1-2002", Resellers: []Document{ + {Vendor: IEEEXplore, Type: Patch, ID: "9507"}, + }}, + {Vendor: TOG, Type: Patch, ID: "U057", Resellers: []Document{ + {Vendor: TOG, Type: Full, ID: "T031"}, + }}, + }}, + {Name: "----->XBD-2001, 2002 Edition", Docs: []Document{ + {Vendor: TOG, Type: Full, ID: "C031"}, + {Vendor: ISO, Type: Full, ID: "38789", Resellers: []Document{ + {Vendor: IEEESA, Type: Full, ID: "9945-1-2003"}, + }}, + }}, + {Name: "----->XSH-2001, 2002 Edition", Docs: []Document{ + {Vendor: TOG, Type: Full, ID: "C032"}, + {Vendor: ISO, Type: Full, ID: "38790", Resellers: []Document{ + {Vendor: IEEESA, Type: Full, ID: "9945-2-2003"}, + }}, + }}, + {Name: "----->XCU-2001, 2002 Edition", Docs: []Document{ + {Vendor: TOG, Type: Full, ID: "C033"}, + {Vendor: ISO, Type: Full, ID: "38791", Resellers: []Document{ + {Vendor: IEEESA, Type: Full, ID: "9945-3-2003"}, + }}, + }}, + {Name: "----->XRAT-2001, 2002 Edition", Docs: []Document{ + {Vendor: TOG, Type: Full, ID: "C034"}, + {Vendor: ISO, Type: Full, ID: "38792", Resellers: []Document{ + {Vendor: IEEESA, Type: Full, ID: "9945-4-2003"}, + }}, + }}, + + {Name: "POSIX-2001, 2004 Edition", Docs: []Document{ + {Vendor: IEEESA, Type: Patch, ID: "1003.1-2001-Cor_2-2004", Resellers: []Document{ + {Vendor: IEEEXplore, Type: Patch, ID: "9022"}, + {Vendor: IEEEXplore, Type: Full, ID: "9156"}, + }}, + {Vendor: TOG, Type: Patch, ID: "U059", Resellers: []Document{ + {Vendor: TOG, Type: Full, ID: "T041"}, + {Vendor: TOGOnline, Type: Full, ID: "009695399"}, + }}, + }}, + {Name: "----->XBD-2001, 2004 Edition", Docs: []Document{ + {Vendor: TOG, Type: Full, ID: "C046"}, + {Vendor: ISO, Type: Patch, ID: "40687"}, + }}, + {Name: "----->XSH-2001, 2004 Edition", Docs: []Document{ + {Vendor: TOG, Type: Full, ID: "C047"}, + {Vendor: ISO, Type: Patch, ID: "40688"}, + }}, + {Name: "----->XCU-2001, 2004 Edition", Docs: []Document{ + {Vendor: TOG, Type: Full, ID: "C048"}, + {Vendor: ISO, Type: Patch, ID: "40690"}, + }}, + {Name: "----->XRAT-2001, 2004 Edition", Docs: []Document{ + {Vendor: TOG, Type: Full, ID: "C049"}, + {Vendor: ISO, Type: Patch, ID: "40691"}, + }}, + + {Name: "POSIX-2008 (Issue 7)", Docs: []Document{ + {Vendor: TOG, Type: Full, ID: "C082", Resellers: []Document{ + {Vendor: TOGOnline, Type: Full, ID: "9699919799.2008edition"}, + }}, + + {Vendor: IEEESA, Type: Full, ID: "1003.1-2008", Resellers: []Document{ + {Vendor: IEEEXplore, Type: Full, ID: "7394900"}, + }}, + + {Vendor: ISO, Type: Full, ID: "50516", Resellers: []Document{ + {Vendor: IEEESA, Type: Full, ID: "9945-2009"}, + {Vendor: IEEEXplore, Type: Full, ID: "5393777"}, + }}, + }}, + {Name: "POSIX-2008, 2013 Edition", Docs: []Document{ + {Vendor: TOG, Type: Patch, ID: "U130", Resellers: []Document{ + {Vendor: TOG, Type: Full, ID: "C138"}, + {Vendor: TOGOnline, Type: Full, ID: "9699919799.2013edition"}, + }}, + + {Vendor: IEEESA, Type: Patch, ID: "1003.1-2008-Cor_1-2013", Resellers: []Document{ + {Vendor: IEEEXplore, Type: Patch, ID: "6482152"}, + {Vendor: IEEEXplore, Type: Full, ID: "6506089"}, + }}, + + {Vendor: ISO, Type: Patch, ID: "62005"}, + }}, + {Name: "POSIX-2008, 2016 Edition", Docs: []Document{ + {Vendor: TOG, Type: Patch, ID: "U160", Resellers: []Document{ + {Vendor: TOG, Type: Full, ID: "C165"}, + {Vendor: TOGOnline, Type: Full, ID: "9699919799.2016edition"}, + }}, + + {Vendor: IEEESA, Type: Patch, ID: "1003.1-2008-Cor_2-2016", Resellers: []Document{ + {Vendor: IEEEXplore, Type: Patch, ID: "7542096"}, + {Vendor: IEEEXplore, Type: Full, ID: "7582336"}, + }}, + }}, +} + +// SUSv2 http://pubs.opengroup.org/onlinepubs/007908799/ @@ -0,0 +1,190 @@ +package main + +import ( + "html/template" + "os" +) + +var urls = map[string]string{} +var names = map[string]string{} + +func (doc Document) URL() string { + if doc.ID == "" { + return "" + } + key := doc.Vendor.Name + "\000" + doc.ID + if _, have := urls[key]; !have { + urls[key] = doc.Vendor.GetURL(doc.ID) + } + return urls[key] +} + +func (doc Document) Name() string { + if doc.ID == "" { + var names []string + for _, full := range doc.Fulls() { + names = append(names, full.Name()) + } + switch len(names) { + case 0: + return "???" + case 1: + return names[0] + default: + // BUG(lukeshu): Handle un-IDed Documents with + // multiple IDed resellers. + panic("TODO") + } + } + key := doc.Vendor.Name + "\000" + doc.ID + if _, have := names[key]; !have { + names[key] = doc.Vendor.GetName(doc.ID, doc.URL()) + } + return names[key] +} + +func (doc Document) Fulls() []Document { + var ret []Document + for _, reseller := range doc.Resellers { + if doc.ID != "" && reseller.Vendor.Name == doc.Vendor.Name && reseller.ID == doc.ID { + continue + } + if reseller.Type == Full { + ret = append(ret, reseller) + } + } + return ret +} + +func (doc Document) Patches() []Document { + var ret []Document + for _, reseller := range doc.Resellers { + if doc.ID != "" && reseller.Vendor.Name == doc.Vendor.Name && reseller.ID == doc.ID { + continue + } + if reseller.Type == Patch { + ret = append(ret, reseller) + } + } + return ret +} + +func (doc Document) AsFull() *Document { + if doc.Vendor.Name == "" && doc.ID == "" { + return nil + } + ret := doc + ret.Resellers = ret.Fulls() + switch doc.Type { + case Full: + // Nothing to do + case Patch: + if len(ret.Resellers) == 0 { + return nil + } + ret.Type = Full + ret.ID = func() string { + var ids []string + for _, reseller := range ret.Resellers { + if reseller.Vendor.Name == doc.Vendor.Name { + ids = append(ids, reseller.ID) + } + } + switch len(ids) { + case 0: + return "" + case 1: + return ids[0] + default: + panic("wut") + } + }() + if ret.ID != "" { + ret.Resellers = ret.Fulls() + } + default: + panic("uhh") + } + return &ret +} + +func (doc Document) AsPatch() *Document { + if doc.Vendor.Name == "" && doc.ID == "" { + return nil + } + ret := doc + switch doc.Type { + case Full: + return nil + case Patch: + ret.Resellers = doc.Patches() + default: + panic("no") + } + return &ret +} + +func (ed Edition) DocsOrdered() []Document { + // This chould be O(n), but this niaeve implementation is + // O(n^2). It's OK, n is small. + s := make([]Document, len(Vendors)) + for i, vnd := range Vendors { + for _, doc := range ed.Docs { + if doc.Vendor.Name == vnd.Name { + s[i] = doc + } + } + } + return s +} + +var tmpl = `{{define "document"}}{{if .}} + {{if .URL}}<a href="{{.URL}}" title="{{.Name}}">{{.Name}}</a>{{else}}{{.Name}}{{end}} + {{range .Resellers}} + <a href="{{.URL}}" title="{{.Name}}">({{.Vendor.Name}})</a> + {{end}} +{{end}}{{end}} +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <title>POSIX Editions</title> + <style> + body { font-size: 8px; } + table { border-collapse: collapse; } + th, td { border: solid 1px black; } + tr:not(:first-child):not(:nth-child(2)) th { + font-family: monospace; + text-align: left; + } + </style> + </head> + <body> + <p>There's a typo in the "standardNumber" in IEEE + Xplore's records forfor the 2004 edition of 1003.1; + it says 2014 instead or 2004. The actual document + says 2004 though.</p> + <table> + <caption><p>POSIX: C & Shell (1997-present)</p></caption> + <tr><td rowspan=2></td>{{range .Vendors}}<th colspan=2>{{.Name}}</th>{{end}}</tr> + <tr>{{range .Vendors}}<th>Full</th><th>Patch</th>{{end}}</tr> + {{range .Editions}}<tr> + <th>{{.Name}}</th> + {{range .DocsOrdered}} + <td>{{template "document" .AsFull}}</td><td>{{template "document" .AsPatch}}</td> + {{end}} + </tr>{{end}} + </table> + </body> +</html> +` + +func main() { + err := template.Must(template.New("page").Parse(tmpl)).Execute(os.Stdout, map[string]interface{}{ + "Vendors": Vendors, + "Editions": Editions, + }) + if err != nil { + panic(err) + } +} diff --git a/types.go b/types.go new file mode 100644 index 0000000..9bb4c2d --- /dev/null +++ b/types.go @@ -0,0 +1,26 @@ +package main + +type Vendor struct { + Name string + GetURL func(id string) string + GetName func(id string, url string) string +} + +type Type int + +const ( + Full Type = 0 + Patch Type = 1 +) + +type Edition struct { + Name string + Docs []Document +} + +type Document struct { + Vendor Vendor + Type Type + ID string + Resellers []Document +} |