// Copyright 2024 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build ignore // This is based on the implementation of src/cmd/internal/obj/stringer.go. // This is a mini version of the stringer tool customized for the Cnames // table in the architecture support for obj. package main import ( "bufio" "flag" "fmt" "log" "os" "regexp" "strings" ) var ( input = flag.String("i", "", "input file name") output = flag.String("o", "", "output file name") pkg = flag.String("p", "", "package name") ) var cnameExp = regexp.MustCompile(`^\tC_([A-Za-z0-9_]+)`) func main() { flag.Parse() if *input == "" || *output == "" || *pkg == "" { flag.Usage() os.Exit(2) } start := "" switch *pkg { case "arm64": start = "var cnames7 = []string{\n\t\"\", // C_NONE starts from 1\n" case "loong64", "mips": start = "var cnames0 = []string{\n" case "ppc64": start = "var cnames9 = []string{\n" case "s390x": start = "var cnamesz = []string{\n" default: fmt.Printf("Only supports generating Cnames for arm64,loong64,mips,ppc64,s390x.") os.Exit(0) } in, err := os.Open(*input) if err != nil { log.Fatal(err) } fd, err := os.Create(*output) if err != nil { log.Fatal(err) } out := bufio.NewWriter(fd) closeOut := func() { if err = out.Flush(); err != nil { log.Fatal(err) } if err = fd.Close(); err != nil { log.Fatal(err) } } defer closeOut() on := false s := bufio.NewScanner(in) for s.Scan() { line := s.Text() if !on { // First relevant line contains "C_NONE = iota". // If we find it, delete the "=" so we don't stop immediately. const first = "C_NONE" if !strings.Contains(line, first) { continue } const suffix = "= iota" index := strings.Index(line, suffix) if index < 0 { continue } line = line[:index] // It's on. Start with the header. fmt.Fprintf(out, header, *input, *output, *pkg, *pkg) fmt.Fprintf(out, start) on = true } // Strip comments so their text won't defeat our heuristic. index := strings.Index(line, "//") if index > 0 { line = line[:index] } index = strings.Index(line, "/*") if index > 0 { comments := line[index:] if !strings.Contains(comments, "*/") { log.Fatalf("invalid comment: %s\n", comments) } line = line[:index] } // Termination condition: Any line with an = changes the sequence, // so stop there, and stop at a closing brace. if strings.HasPrefix(line, "}") || strings.ContainsRune(line, '=') { break } sub := cnameExp.FindStringSubmatch(line) if len(sub) < 2 { continue } else { fmt.Fprintf(out, "\t%q,\n", sub[1]) } } fmt.Fprintln(out, "}") if s.Err() != nil { log.Fatal(err) } } const header = `// Code generated by mkcnames -i %s -o %s -p %s; DO NOT EDIT. package %s // This order should be strictly consistent to that in a.out.go. `