From ca074ce38774499d6e1b47799450f6ab30a06d6c Mon Sep 17 00:00:00 2001 From: Dietrich Epp Date: Tue, 15 Mar 2022 14:31:12 -0400 Subject: [PATCH] Write conversion from script and region to charmap The generation tool creates a GetCharmap function in C which takes the script and region as input and returns the charmap index. --- gen/main.go | 7 ++- gen/scriptmap.go | 133 +++++++++++++++++++++++++++++++++++++++++++++++ src/.gitignore | 1 + 3 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 gen/scriptmap.go create mode 100644 src/.gitignore diff --git a/gen/main.go b/gen/main.go index e06aded..e66ab9c 100644 --- a/gen/main.go +++ b/gen/main.go @@ -7,6 +7,8 @@ import ( "path/filepath" ) +const header = "/* This file is automatically generated. */\n" + var ( flagDumpSequences bool flagDumpTransitions bool @@ -37,7 +39,10 @@ func mainE() error { if err != nil { return err } - _ = d + m := genMap(&d) + if err := writeMap(&d, m, "src/getcharmap.c"); err != nil { + return err + } return nil } diff --git a/gen/scriptmap.go b/gen/scriptmap.go new file mode 100644 index 0000000..b44c545 --- /dev/null +++ b/gen/scriptmap.go @@ -0,0 +1,133 @@ +package main + +import ( + "bufio" + "fmt" + "os" + "os/exec" + "sort" +) + +type regionmap struct { + regions []int + charmap int +} + +type regionmaps []regionmap + +func (s regionmaps) Len() int { return len(s) } +func (s regionmaps) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s regionmaps) Less(i, j int) bool { + x := s[i] + y := s[j] + switch { + case len(y.regions) == 0: + return true + case len(x.regions) == 0: + return false + default: + return x.regions[0] < y.regions[0] + } +} + +type scriptmap struct { + script int + regions []regionmap +} + +type scriptmaps []*scriptmap + +func (s scriptmaps) Len() int { return len(s) } +func (s scriptmaps) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s scriptmaps) Less(i, j int) bool { return s[i].script < s[j].script } + +// genMap generates a map from scripts and regions to charmaps. +func genMap(d *scriptdata) []*scriptmap { + m := make(map[int]*scriptmap) + var r []*scriptmap + for i, cm := range d.charmaps { + s := m[cm.script] + if s == nil { + s = &scriptmap{script: cm.script} + m[cm.script] = s + r = append(r, s) + } + var rgs []int + if len(cm.regions) != 0 { + rgs = make([]int, len(cm.regions)) + copy(rgs, cm.regions) + sort.Ints(rgs) + } + s.regions = append(s.regions, regionmap{ + regions: cm.regions, + charmap: i, + }) + } + for _, s := range r { + sort.Sort(regionmaps(s.regions)) + } + sort.Sort(scriptmaps(r)) + return r +} + +// writeMap writes out a C function that returns the correct character map for a +// given script and region. +func writeMap(d *scriptdata, m []*scriptmap, filename string) error { + fmt.Fprintln(os.Stderr, "Writing:", filename) + + fp, err := os.Create(filename) + if err != nil { + return err + } + defer fp.Close() + w := bufio.NewWriter(fp) + + w.WriteString(header) + w.WriteString( + "int GetCharmap(int script, int region) {\n" + + "switch (script) {\n") + for _, s := range m { + fmt.Fprintf(w, "case %d: /* %s */\n", s.script, d.scripts.values[s.script]) + if len(s.regions) == 1 && len(s.regions[0].regions) == 0 { + r := s.regions[0] + fmt.Fprintf(w, "return %d; /* %s */\n", r.charmap, d.charmaps[r.charmap].name) + } else { + w.WriteString("switch (region) {\n") + var hasdefault bool + for _, r := range s.regions { + if len(r.regions) == 0 { + w.WriteString("default:\n") + hasdefault = true + } else { + for _, rg := range r.regions { + fmt.Fprintf(w, "case %d: /* %s */\n", rg, d.regions.values[rg]) + } + } + fmt.Fprintf(w, "return %d; /* %s */\n", r.charmap, d.charmaps[r.charmap].name) + } + if !hasdefault { + w.WriteString("default:\nreturn -1;\n") + } + w.WriteString("}\n") + } + } + w.WriteString( + "default:\n" + + "return -1;\n" + + "}\n" + + "}\n") + + if err := w.Flush(); err != nil { + return err + } + if err := fp.Close(); err != nil { + return err + } + + cmd := exec.Command("clang-format", "-i", filename) + if err := cmd.Run(); err != nil { + fmt.Fprintln(os.Stderr, "Warning: clang-format failed:", err) + } + + return nil +} diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..24c33a0 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1 @@ +/getcharmap.c