github.com/nvi-inc/fsgo@v0.2.1/versions/utils/cgo/godefs.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "bytes" 9 "fmt" 10 "go/ast" 11 "go/printer" 12 "go/token" 13 "os" 14 "path/filepath" 15 "strings" 16 ) 17 18 // godefs returns the output for -godefs mode. 19 func (p *Package) godefs(f *File, srcfile string) string { 20 var buf bytes.Buffer 21 22 fmt.Fprintf(&buf, "// Created by cgo -godefs - DO NOT EDIT\n") 23 fmt.Fprintf(&buf, "// %s %s\n", filepath.Base(os.Args[0]), strings.Join(os.Args[1:], " ")) 24 fmt.Fprintf(&buf, "\n") 25 26 override := make(map[string]string) 27 28 // Allow source file to specify override mappings. 29 // For example, the socket data structures refer 30 // to in_addr and in_addr6 structs but we want to be 31 // able to treat them as byte arrays, so the godefs 32 // inputs in package syscall say 33 // 34 // // +godefs map struct_in_addr [4]byte 35 // // +godefs map struct_in_addr6 [16]byte 36 // 37 for _, g := range f.Comments { 38 for _, c := range g.List { 39 i := strings.Index(c.Text, "+godefs map") 40 if i < 0 { 41 continue 42 } 43 s := strings.TrimSpace(c.Text[i+len("+godefs map"):]) 44 i = strings.Index(s, " ") 45 if i < 0 { 46 fmt.Fprintf(os.Stderr, "invalid +godefs map comment: %s\n", c.Text) 47 continue 48 } 49 override["_Ctype_"+strings.TrimSpace(s[:i])] = strings.TrimSpace(s[i:]) 50 } 51 } 52 for _, n := range f.Name { 53 if s := override[n.Go]; s != "" { 54 override[n.Mangle] = s 55 } 56 } 57 58 // Otherwise, if the source file says type T C.whatever, 59 // use "T" as the mangling of C.whatever, 60 // except in the definition (handled at end of function). 61 refName := make(map[*ast.Expr]*Name) 62 for _, r := range f.Ref { 63 refName[r.Expr] = r.Name 64 } 65 for _, d := range f.AST.Decls { 66 d, ok := d.(*ast.GenDecl) 67 if !ok || d.Tok != token.TYPE { 68 continue 69 } 70 for _, s := range d.Specs { 71 s := s.(*ast.TypeSpec) 72 n := refName[&s.Type] 73 if n != nil && n.Mangle != "" { 74 override[n.Mangle] = s.Name.Name 75 } 76 } 77 } 78 79 // Extend overrides using typedefs: 80 // If we know that C.xxx should format as T 81 // and xxx is a typedef for yyy, make C.yyy format as T. 82 for typ, def := range typedef { 83 if new := override[typ]; new != "" { 84 if id, ok := def.Go.(*ast.Ident); ok { 85 override[id.Name] = new 86 } 87 } 88 } 89 90 // Apply overrides. 91 for old, new := range override { 92 if id := goIdent[old]; id != nil { 93 id.Name = new 94 } 95 } 96 97 // Any names still using the _C syntax are not going to compile, 98 // although in general we don't know whether they all made it 99 // into the file, so we can't warn here. 100 // 101 // The most common case is union types, which begin with 102 // _Ctype_union and for which typedef[name] is a Go byte 103 // array of the appropriate size (such as [4]byte). 104 // Substitute those union types with byte arrays. 105 for name, id := range goIdent { 106 if id.Name == name && strings.Contains(name, "_Ctype_union") { 107 if def := typedef[name]; def != nil { 108 id.Name = gofmt(def) 109 } 110 } 111 } 112 113 conf.Fprint(&buf, fset, f.AST) 114 115 return buf.String() 116 } 117 118 var gofmtBuf bytes.Buffer 119 120 // gofmt returns the gofmt-formatted string for an AST node. 121 func gofmt(n interface{}) string { 122 gofmtBuf.Reset() 123 err := printer.Fprint(&gofmtBuf, fset, n) 124 if err != nil { 125 return "<" + err.Error() + ">" 126 } 127 return gofmtBuf.String() 128 }