| // 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. | |
| ` |