1
2
3
4
5
6
7
8
9
10
11
12 package main
13
14 import (
15 "bytes"
16 "encoding/xml"
17 "fmt"
18 "go/format"
19 "io"
20 "net/http"
21 "os"
22 "os/exec"
23 "runtime"
24 "strconv"
25 "strings"
26 )
27
28 func main() {
29 if err := genzsys(); err != nil {
30 fmt.Fprintln(os.Stderr, err)
31 os.Exit(1)
32 }
33 if err := geniana(); err != nil {
34 fmt.Fprintln(os.Stderr, err)
35 os.Exit(1)
36 }
37 }
38
39 func genzsys() error {
40 defs := "defs_" + runtime.GOOS + ".go"
41 f, err := os.Open(defs)
42 if err != nil {
43 if os.IsNotExist(err) {
44 return nil
45 }
46 return err
47 }
48 f.Close()
49 cmd := exec.Command("go", "tool", "cgo", "-godefs", defs)
50 b, err := cmd.Output()
51 if err != nil {
52 return err
53 }
54 b, err = format.Source(b)
55 if err != nil {
56 return err
57 }
58 zsys := "zsys_" + runtime.GOOS + ".go"
59 switch runtime.GOOS {
60 case "freebsd", "linux":
61 zsys = "zsys_" + runtime.GOOS + "_" + runtime.GOARCH + ".go"
62 }
63 if err := os.WriteFile(zsys, b, 0644); err != nil {
64 return err
65 }
66 return nil
67 }
68
69 var registries = []struct {
70 url string
71 parse func(io.Writer, io.Reader) error
72 }{
73 {
74 "https://www.iana.org/assignments/icmp-parameters/icmp-parameters.xml",
75 parseICMPv4Parameters,
76 },
77 }
78
79 func geniana() error {
80 var bb bytes.Buffer
81 fmt.Fprintf(&bb, "// go generate gen.go\n")
82 fmt.Fprintf(&bb, "// Code generated by the command above; DO NOT EDIT.\n\n")
83 fmt.Fprintf(&bb, "package ipv4\n\n")
84 for _, r := range registries {
85 resp, err := http.Get(r.url)
86 if err != nil {
87 return err
88 }
89 defer resp.Body.Close()
90 if resp.StatusCode != http.StatusOK {
91 return fmt.Errorf("got HTTP status code %v for %v\n", resp.StatusCode, r.url)
92 }
93 if err := r.parse(&bb, resp.Body); err != nil {
94 return err
95 }
96 fmt.Fprintf(&bb, "\n")
97 }
98 b, err := format.Source(bb.Bytes())
99 if err != nil {
100 return err
101 }
102 if err := os.WriteFile("iana.go", b, 0644); err != nil {
103 return err
104 }
105 return nil
106 }
107
108 func parseICMPv4Parameters(w io.Writer, r io.Reader) error {
109 dec := xml.NewDecoder(r)
110 var icp icmpv4Parameters
111 if err := dec.Decode(&icp); err != nil {
112 return err
113 }
114 prs := icp.escape()
115 fmt.Fprintf(w, "// %s, Updated: %s\n", icp.Title, icp.Updated)
116 fmt.Fprintf(w, "const (\n")
117 for _, pr := range prs {
118 if pr.Descr == "" {
119 continue
120 }
121 fmt.Fprintf(w, "ICMPType%s ICMPType = %d", pr.Descr, pr.Value)
122 fmt.Fprintf(w, "// %s\n", pr.OrigDescr)
123 }
124 fmt.Fprintf(w, ")\n\n")
125 fmt.Fprintf(w, "// %s, Updated: %s\n", icp.Title, icp.Updated)
126 fmt.Fprintf(w, "var icmpTypes = map[ICMPType]string{\n")
127 for _, pr := range prs {
128 if pr.Descr == "" {
129 continue
130 }
131 fmt.Fprintf(w, "%d: %q,\n", pr.Value, strings.ToLower(pr.OrigDescr))
132 }
133 fmt.Fprintf(w, "}\n")
134 return nil
135 }
136
137 type icmpv4Parameters struct {
138 XMLName xml.Name `xml:"registry"`
139 Title string `xml:"title"`
140 Updated string `xml:"updated"`
141 Registries []struct {
142 Title string `xml:"title"`
143 Records []struct {
144 Value string `xml:"value"`
145 Descr string `xml:"description"`
146 } `xml:"record"`
147 } `xml:"registry"`
148 }
149
150 type canonICMPv4ParamRecord struct {
151 OrigDescr string
152 Descr string
153 Value int
154 }
155
156 func (icp *icmpv4Parameters) escape() []canonICMPv4ParamRecord {
157 id := -1
158 for i, r := range icp.Registries {
159 if strings.Contains(r.Title, "Type") || strings.Contains(r.Title, "type") {
160 id = i
161 break
162 }
163 }
164 if id < 0 {
165 return nil
166 }
167 prs := make([]canonICMPv4ParamRecord, len(icp.Registries[id].Records))
168 sr := strings.NewReplacer(
169 "Messages", "",
170 "Message", "",
171 "ICMP", "",
172 "+", "P",
173 "-", "",
174 "/", "",
175 ".", "",
176 " ", "",
177 )
178 for i, pr := range icp.Registries[id].Records {
179 if strings.Contains(pr.Descr, "Reserved") ||
180 strings.Contains(pr.Descr, "Unassigned") ||
181 strings.Contains(pr.Descr, "Deprecated") ||
182 strings.Contains(pr.Descr, "Experiment") ||
183 strings.Contains(pr.Descr, "experiment") {
184 continue
185 }
186 ss := strings.Split(pr.Descr, "\n")
187 if len(ss) > 1 {
188 prs[i].Descr = strings.Join(ss, " ")
189 } else {
190 prs[i].Descr = ss[0]
191 }
192 s := strings.TrimSpace(prs[i].Descr)
193 prs[i].OrigDescr = s
194 prs[i].Descr = sr.Replace(s)
195 prs[i].Value, _ = strconv.Atoi(pr.Value)
196 }
197 return prs
198 }
199
View as plain text