summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/windowsconstgen.go233
1 files changed, 0 insertions, 233 deletions
diff --git a/tools/windowsconstgen.go b/tools/windowsconstgen.go
deleted file mode 100644
index 37cdd22..0000000
--- a/tools/windowsconstgen.go
+++ /dev/null
@@ -1,233 +0,0 @@
-// 24 may 2014
-package main
-
-import (
- "fmt"
- "os"
- "strings"
- "go/token"
- "go/ast"
- "go/parser"
- "sort"
- "io/ioutil"
- "path/filepath"
- "os/exec"
-)
-
-func getPackage(path string) (pkg *ast.Package) {
- fileset := token.NewFileSet() // parser.ParseDir() actually writes to this; not sure why it doesn't return one instead
- filter := func(i os.FileInfo) bool {
- return strings.HasSuffix(i.Name(), "_windows.go")
- }
- pkgs, err := parser.ParseDir(fileset, path, filter, parser.AllErrors)
- if err != nil {
- panic(err)
- }
- if len(pkgs) != 1 {
- panic("more than one package found")
- }
- for k, _ := range pkgs { // get the sole key
- pkg = pkgs[k]
- }
- return pkg
-}
-
-type walker struct {
- desired func(string) bool
-}
-
-var known = map[string]string{}
-var unknown = map[string]struct{}{}
-
-func (w *walker) Visit(node ast.Node) ast.Visitor {
- if n, ok := node.(*ast.Ident); ok {
- if w.desired(n.Name) {
- if n.Obj != nil {
- delete(unknown, n.Name)
- kind := n.Obj.Kind.String()
- if known[n.Name] != "" && known[n.Name] != kind {
- panic(n.Name + "(" + kind + ") already known to be a " + known[n.Name])
- }
- known[n.Name] = kind
- } else if _, ok := known[n.Name]; !ok { // only if not known
- unknown[n.Name] = struct{}{}
- }
- }
- }
- return w
-}
-
-func gatherNames(pkg *ast.Package) {
- desired := func(name string) bool {
- if strings.HasPrefix(name, "_") && len(name) > 1 {
- return !strings.ContainsAny(name,
- "abcdefghijklmnopqrstuvwxyz")
- }
- return false
- }
- for _, f := range pkg.Files {
- for _, d := range f.Decls {
- ast.Walk(&walker{desired}, d)
- }
- }
-}
-
-// some constants confuse cgo into thinking they're external symbols for some reason
-// fortunately all these constants are pointers
-// TODO debug cgo
-var hacknames = map[string]string{
- "_INVALID_HANDLE_VALUE": "x_INVALID_HANDLE_VALUE",
- "_NULL": "x_NULL",
- "_IDI_APPLICATION": "x_IDI_APPLICATION",
- "_IDC_ARROW": "x_IDC_ARROW",
- "_HWND_MESSAGE": "x_HWND_MESSAGE",
-}
-
-func hacknamesPreamble() string {
- if len(hacknames) == 0 {
- return ""
- }
- // keep sorted for git
- hn := make([]string, 0, len(hacknames))
- for origname, _ := range hacknames {
- hn = append(hn, origname)
- }
- sort.Strings(hn)
- s := "// /* because cgo has issues with these */\n"
- s += "// #include <stdint.h>\n"
- for _, origname := range hn {
- s += "// uintptr_t " + hacknames[origname] + " = (uintptr_t) (" +
- origname[1:] + ");\n" // strip leading _
- }
- return s
-}
-
-func preamble(pkg string) string {
- return "// autogenerated by windowsconstgen; do not edit\n" +
- "package " + pkg + "\n\n" // two newlines to please go fmt
-}
-
-// for backwards compatibiilty reasons, Windows defines GetWindowLongPtr()/SetWindowLongPtr() as a macro which expands to GetWindowLong()/SetWindowLong() on 32-bit systems
-// we'll just simulate that here
-var gwlpNames = map[string]string{
- "386": "etWindowLongW",
- "amd64": "etWindowLongPtrW",
-}
-
-func printConst(f *os.File, goconst string, winconst string) {
- fmt.Fprintf(f, " fmt.Println(\"const %s =\", C.%s)\n", goconst, winconst)
-}
-
-func printBlankLine(f *os.File) {
- fmt.Fprintf(f, " fmt.Println()\n")
-}
-
-func printGWLPName(f *os.File, which string, char string, targetarch string) {
- fmt.Fprintf(f, " fmt.Println(\"var %s = user32.NewProc(\\\"%s\\\")\")\n",
- which, char + gwlpNames[targetarch])
-}
-
-func main() {
- if len(os.Args) < 3 {
- panic("usage: " + os.Args[0] + " path goarch [go-command-options...]")
- }
- pkgpath := os.Args[1]
- targetarch := os.Args[2]
- if _, ok := gwlpNames[targetarch]; !ok {
- panic("unknown target windows/" + targetarch)
- }
- goopts := os.Args[3:] // valid if len(os.Args) == 3; in that case this will just be a slice of length zero
-
- pkg := getPackage(pkgpath)
- gatherNames(pkg)
-
- // if we still have some known, I didn't clean things up completely
- knowns := ""
- for ident, kind := range known {
- if kind != "var" && kind != "const" {
- continue
- }
- knowns += "\n" + ident + " (" + kind + ")"
- }
- if knowns != "" {
- panic("error: the following are still known!" + knowns) // has a newline already
- }
-
- // keep sorted for git
- consts := make([]string, 0, len(unknown))
- for ident, _ := range unknown {
- if hackname, ok := hacknames[ident]; ok {
- consts = append(consts, hackname)
- continue
- }
- consts = append(consts, ident)
- }
- sort.Strings(consts)
-
- // thanks to james4k in irc.freenode.net/#go-nuts
- tmpdir, err := ioutil.TempDir("", "windowsconstgen")
- if err != nil {
- panic(err)
- }
- genoutname := filepath.Join(tmpdir, "gen.go")
- f, err := os.Create(genoutname)
- if err != nil {
- panic(err)
- }
- fmt.Fprintf(f, "%s" +
- "import \"fmt\"\n" +
- "// #include <windows.h>\n" +
- "// #include <commctrl.h>\n" +
- "%s" +
- "import \"C\"\n" +
- "func main() {\n" +
- " fmt.Print(%q)\n",
- preamble("main"), hacknamesPreamble(), preamble("ui"))
- for _, ident := range consts {
- if ident[0] == 'x' {
- // hack name; strip the leading x (but not the _ after it) from the constant name but keep the value name unchanged
- printConst(f, ident[1:], ident)
- continue
- }
- // not a hack name; strip the leading _ from the value name but keep the constant name unchanged
- printConst(f, ident, ident[1:])
- }
- printBlankLine(f) // to please go fmt
- // and now for _getWindowLongPtr/_setWindowLongPtr
- printGWLPName(f, "_getWindowLongPtr", "G", targetarch)
- printGWLPName(f, "_setWindowLongPtr", "S", targetarch)
- fmt.Fprintf(f, "}\n")
- f.Close()
-
- cmd := exec.Command("go", "run")
- cmd.Args = append(cmd.Args, goopts...) // valid if len(goopts) == 0; in that case this will just be a no-op
- cmd.Args = append(cmd.Args, genoutname)
- f, err = os.Create(filepath.Join(pkgpath, "zconstants_windows_" + targetarch + ".go"))
- if err != nil {
- panic(err)
- }
- defer f.Close()
- cmd.Stdout = f
- cmd.Stderr = os.Stderr
- // we need to preserve the environment EXCEPT FOR the variables we're overriding
- // thanks to raggi and smw in irc.freenode.net/#go-nuts
- for _, ev := range os.Environ() {
- if strings.HasPrefix(ev, "GOOS=") ||
- strings.HasPrefix(ev, "GOARCH=") ||
- strings.HasPrefix(ev, "CGO_ENABLED=") {
- continue
- }
- cmd.Env = append(cmd.Env, ev)
- }
- cmd.Env = append(cmd.Env,
- "GOOS=windows",
- "GOARCH=" + targetarch,
- "CGO_ENABLED=1") // needed as it's not set by default in cross-compiles
- err = cmd.Run()
- if err != nil {
- // TODO find a way to get the exit code
- os.Exit(1)
- }
-
- // TODO remove the temporary directory
-}