golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/ipv6/gen.go (about)

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