blob: 72b27300c79b9b0c7291daea54abe9b0abf5efdb [file] [log] [blame]
// 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.
`