gen.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. // Copyright 2013 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // +build ignore
  5. //go:generate go run gen.go
  6. // This program generates internet protocol constants and tables by
  7. // reading IANA protocol registries.
  8. package main
  9. import (
  10. "bytes"
  11. "encoding/xml"
  12. "fmt"
  13. "go/format"
  14. "io"
  15. "io/ioutil"
  16. "net/http"
  17. "os"
  18. "strconv"
  19. "strings"
  20. )
  21. var registries = []struct {
  22. url string
  23. parse func(io.Writer, io.Reader) error
  24. }{
  25. {
  26. "http://www.iana.org/assignments/icmp-parameters/icmp-parameters.xml",
  27. parseICMPv4Parameters,
  28. },
  29. }
  30. func main() {
  31. var bb bytes.Buffer
  32. fmt.Fprintf(&bb, "// go generate gen.go\n")
  33. fmt.Fprintf(&bb, "// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n\n")
  34. fmt.Fprintf(&bb, "package ipv4\n\n")
  35. for _, r := range registries {
  36. resp, err := http.Get(r.url)
  37. if err != nil {
  38. fmt.Fprintln(os.Stderr, err)
  39. os.Exit(1)
  40. }
  41. defer resp.Body.Close()
  42. if resp.StatusCode != http.StatusOK {
  43. fmt.Fprintf(os.Stderr, "got HTTP status code %v for %v\n", resp.StatusCode, r.url)
  44. os.Exit(1)
  45. }
  46. if err := r.parse(&bb, resp.Body); err != nil {
  47. fmt.Fprintln(os.Stderr, err)
  48. os.Exit(1)
  49. }
  50. fmt.Fprintf(&bb, "\n")
  51. }
  52. b, err := format.Source(bb.Bytes())
  53. if err != nil {
  54. fmt.Fprintln(os.Stderr, err)
  55. os.Exit(1)
  56. }
  57. if err := ioutil.WriteFile("iana.go", b, 0644); err != nil {
  58. fmt.Fprintln(os.Stderr, err)
  59. os.Exit(1)
  60. }
  61. }
  62. func parseICMPv4Parameters(w io.Writer, r io.Reader) error {
  63. dec := xml.NewDecoder(r)
  64. var icp icmpv4Parameters
  65. if err := dec.Decode(&icp); err != nil {
  66. return err
  67. }
  68. prs := icp.escape()
  69. fmt.Fprintf(w, "// %s, Updated: %s\n", icp.Title, icp.Updated)
  70. fmt.Fprintf(w, "const (\n")
  71. for _, pr := range prs {
  72. if pr.Descr == "" {
  73. continue
  74. }
  75. fmt.Fprintf(w, "ICMPType%s ICMPType = %d", pr.Descr, pr.Value)
  76. fmt.Fprintf(w, "// %s\n", pr.OrigDescr)
  77. }
  78. fmt.Fprintf(w, ")\n\n")
  79. fmt.Fprintf(w, "// %s, Updated: %s\n", icp.Title, icp.Updated)
  80. fmt.Fprintf(w, "var icmpTypes = map[ICMPType]string{\n")
  81. for _, pr := range prs {
  82. if pr.Descr == "" {
  83. continue
  84. }
  85. fmt.Fprintf(w, "%d: %q,\n", pr.Value, strings.ToLower(pr.OrigDescr))
  86. }
  87. fmt.Fprintf(w, "}\n")
  88. return nil
  89. }
  90. type icmpv4Parameters struct {
  91. XMLName xml.Name `xml:"registry"`
  92. Title string `xml:"title"`
  93. Updated string `xml:"updated"`
  94. Registries []struct {
  95. Title string `xml:"title"`
  96. Records []struct {
  97. Value string `xml:"value"`
  98. Descr string `xml:"description"`
  99. } `xml:"record"`
  100. } `xml:"registry"`
  101. }
  102. type canonICMPv4ParamRecord struct {
  103. OrigDescr string
  104. Descr string
  105. Value int
  106. }
  107. func (icp *icmpv4Parameters) escape() []canonICMPv4ParamRecord {
  108. id := -1
  109. for i, r := range icp.Registries {
  110. if strings.Contains(r.Title, "Type") || strings.Contains(r.Title, "type") {
  111. id = i
  112. break
  113. }
  114. }
  115. if id < 0 {
  116. return nil
  117. }
  118. prs := make([]canonICMPv4ParamRecord, len(icp.Registries[id].Records))
  119. sr := strings.NewReplacer(
  120. "Messages", "",
  121. "Message", "",
  122. "ICMP", "",
  123. "+", "P",
  124. "-", "",
  125. "/", "",
  126. ".", "",
  127. " ", "",
  128. )
  129. for i, pr := range icp.Registries[id].Records {
  130. if strings.Contains(pr.Descr, "Reserved") ||
  131. strings.Contains(pr.Descr, "Unassigned") ||
  132. strings.Contains(pr.Descr, "Deprecated") ||
  133. strings.Contains(pr.Descr, "Experiment") ||
  134. strings.Contains(pr.Descr, "experiment") {
  135. continue
  136. }
  137. ss := strings.Split(pr.Descr, "\n")
  138. if len(ss) > 1 {
  139. prs[i].Descr = strings.Join(ss, " ")
  140. } else {
  141. prs[i].Descr = ss[0]
  142. }
  143. s := strings.TrimSpace(prs[i].Descr)
  144. prs[i].OrigDescr = s
  145. prs[i].Descr = sr.Replace(s)
  146. prs[i].Value, _ = strconv.Atoi(pr.Value)
  147. }
  148. return prs
  149. }