github.com/razvanm/vanadium-go-1.3@v0.0.0-20160721203343-4a65068e5915/src/cmd/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 "strings" 15 ) 16 17 // godefs returns the output for -godefs mode. 18 func (p *Package) godefs(f *File, srcfile string) string { 19 var buf bytes.Buffer 20 21 fmt.Fprintf(&buf, "// Created by cgo -godefs - DO NOT EDIT\n") 22 fmt.Fprintf(&buf, "// %s\n", strings.Join(os.Args, " ")) 23 fmt.Fprintf(&buf, "\n") 24 25 override := make(map[string]string) 26 27 // Allow source file to specify override mappings. 28 // For example, the socket data structures refer 29 // to in_addr and in_addr6 structs but we want to be 30 // able to treat them as byte arrays, so the godefs 31 // inputs in package syscall say 32 // 33 // // +godefs map struct_in_addr [4]byte 34 // // +godefs map struct_in_addr6 [16]byte 35 // 36 for _, g := range f.Comments { 37 for _, c := range g.List { 38 i := strings.Index(c.Text, "+godefs map") 39 if i < 0 { 40 continue 41 } 42 s := strings.TrimSpace(c.Text[i+len("+godefs map"):]) 43 i = strings.Index(s, " ") 44 if i < 0 { 45 fmt.Fprintf(os.Stderr, "invalid +godefs map comment: %s\n", c.Text) 46 continue 47 } 48 override["_Ctype_"+strings.TrimSpace(s[:i])] = strings.TrimSpace(s[i:]) 49 } 50 } 51 for _, n := range f.Name { 52 if s := override[n.Go]; s != "" { 53 override[n.Mangle] = s 54 } 55 } 56 57 // Otherwise, if the source file says type T C.whatever, 58 // use "T" as the mangling of C.whatever, 59 // except in the definition (handled at end of function). 60 refName := make(map[*ast.Expr]*Name) 61 for _, r := range f.Ref { 62 refName[r.Expr] = r.Name 63 } 64 for _, d := range f.AST.Decls { 65 d, ok := d.(*ast.GenDecl) 66 if !ok || d.Tok != token.TYPE { 67 continue 68 } 69 for _, s := range d.Specs { 70 s := s.(*ast.TypeSpec) 71 n := refName[&s.Type] 72 if n != nil && n.Mangle != "" { 73 override[n.Mangle] = s.Name.Name 74 } 75 } 76 } 77 78 // Extend overrides using typedefs: 79 // If we know that C.xxx should format as T 80 // and xxx is a typedef for yyy, make C.yyy format as T. 81 for typ, def := range typedef { 82 if new := override[typ]; new != "" { 83 if id, ok := def.Go.(*ast.Ident); ok { 84 override[id.Name] = new 85 } 86 } 87 } 88 89 // Apply overrides. 90 for old, new := range override { 91 if id := goIdent[old]; id != nil { 92 id.Name = new 93 } 94 } 95 96 // Any names still using the _C syntax are not going to compile, 97 // although in general we don't know whether they all made it 98 // into the file, so we can't warn here. 99 // 100 // The most common case is union types, which begin with 101 // _Ctype_union and for which typedef[name] is a Go byte 102 // array of the appropriate size (such as [4]byte). 103 // Substitute those union types with byte arrays. 104 for name, id := range goIdent { 105 if id.Name == name && strings.Contains(name, "_Ctype_union") { 106 if def := typedef[name]; def != nil { 107 id.Name = gofmt(def) 108 } 109 } 110 } 111 112 conf.Fprint(&buf, fset, f.AST) 113 114 return buf.String() 115 } 116 117 // cdefs returns the output for -cdefs mode. 118 // The easiest way to do this is to translate the godefs Go to C. 119 func (p *Package) cdefs(f *File, srcfile string) string { 120 godefsOutput := p.godefs(f, srcfile) 121 122 lines := strings.Split(godefsOutput, "\n") 123 lines[0] = "// Created by cgo -cdefs - DO NOT EDIT" 124 125 for i, line := range lines { 126 lines[i] = strings.TrimSpace(line) 127 } 128 129 var out bytes.Buffer 130 printf := func(format string, args ...interface{}) { fmt.Fprintf(&out, format, args...) } 131 132 didTypedef := false 133 for i := 0; i < len(lines); i++ { 134 line := lines[i] 135 136 // Delete 137 // package x 138 if strings.HasPrefix(line, "package ") { 139 continue 140 } 141 142 // Convert 143 // const ( 144 // A = 1 145 // B = 2 146 // ) 147 // 148 // to 149 // 150 // enum { 151 // A = 1, 152 // B = 2, 153 // }; 154 if line == "const (" { 155 printf("enum {\n") 156 for i++; i < len(lines) && lines[i] != ")"; i++ { 157 line = lines[i] 158 if line != "" { 159 printf("\t%s,", line) 160 } 161 printf("\n") 162 } 163 printf("};\n") 164 continue 165 } 166 167 // Convert 168 // const A = 1 169 // to 170 // enum { A = 1 }; 171 if strings.HasPrefix(line, "const ") { 172 printf("enum { %s };\n", line[len("const "):]) 173 continue 174 } 175 176 // On first type definition, typedef all the structs 177 // in case there are dependencies between them. 178 if !didTypedef && strings.HasPrefix(line, "type ") { 179 didTypedef = true 180 for _, line := range lines { 181 line = strings.TrimSpace(line) 182 if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") { 183 s := strings.TrimSuffix(strings.TrimPrefix(line, "type "), " struct {") 184 printf("typedef struct %s %s;\n", s, s) 185 } 186 } 187 printf("\n") 188 printf("#pragma pack on\n") 189 printf("\n") 190 } 191 192 // Convert 193 // type T struct { 194 // X int64 195 // Y *int32 196 // Z [4]byte 197 // } 198 // 199 // to 200 // 201 // struct T { 202 // int64 X; 203 // int32 *Y; 204 // byte Z[4]; 205 // } 206 if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") { 207 if len(lines) > i+1 && lines[i+1] == "}" { 208 // do not output empty struct 209 i++ 210 continue 211 } 212 s := line[len("type ") : len(line)-len(" struct {")] 213 printf("struct %s {\n", s) 214 for i++; i < len(lines) && lines[i] != "}"; i++ { 215 line := lines[i] 216 if line != "" { 217 f := strings.Fields(line) 218 if len(f) != 2 { 219 fmt.Fprintf(os.Stderr, "cgo: cannot parse struct field: %s\n", line) 220 nerrors++ 221 continue 222 } 223 printf("\t%s;", cdecl(f[0], f[1])) 224 } 225 printf("\n") 226 } 227 printf("};\n") 228 continue 229 } 230 231 // Convert 232 // type T int 233 // to 234 // typedef int T; 235 if strings.HasPrefix(line, "type ") { 236 f := strings.Fields(line[len("type "):]) 237 if len(f) != 2 { 238 fmt.Fprintf(os.Stderr, "cgo: cannot parse type definition: %s\n", line) 239 nerrors++ 240 continue 241 } 242 printf("typedef\t%s;\n", cdecl(f[0], f[1])) 243 continue 244 } 245 246 printf("%s\n", line) 247 } 248 249 if didTypedef { 250 printf("\n") 251 printf("#pragma pack off\n") 252 } 253 254 return out.String() 255 } 256 257 // cdecl returns the C declaration for the given Go name and type. 258 // It only handles the specific cases necessary for converting godefs output. 259 func cdecl(name, typ string) string { 260 // X *[0]byte -> X *void 261 if strings.HasPrefix(typ, "*[0]") { 262 typ = "*void" 263 } 264 // X [4]byte -> X[4] byte 265 for strings.HasPrefix(typ, "[") { 266 i := strings.Index(typ, "]") + 1 267 name = name + typ[:i] 268 typ = typ[i:] 269 } 270 // X *byte -> *X byte 271 for strings.HasPrefix(typ, "*") { 272 name = "*" + name 273 typ = typ[1:] 274 } 275 // X T -> T X 276 // Handle the special case: 'unsafe.Pointer' is 'void *' 277 if typ == "unsafe.Pointer" { 278 typ = "void" 279 name = "*" + name 280 } 281 return typ + "\t" + name 282 } 283 284 var gofmtBuf bytes.Buffer 285 286 // gofmt returns the gofmt-formatted string for an AST node. 287 func gofmt(n interface{}) string { 288 gofmtBuf.Reset() 289 err := printer.Fprint(&gofmtBuf, fset, n) 290 if err != nil { 291 return "<" + err.Error() + ">" 292 } 293 return gofmtBuf.String() 294 }