OLD | NEW |
(Empty) | |
| 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 |
| 6 package main |
| 7 |
| 8 import ( |
| 9 "bytes" |
| 10 "fmt" |
| 11 "go/ast" |
| 12 "go/printer" |
| 13 "go/token" |
| 14 "os" |
| 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\n", strings.Join(os.Args, " ")) |
| 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 comm
ent: %s\n", c.Text) |
| 47 continue |
| 48 } |
| 49 override["_Ctype_"+strings.TrimSpace(s[:i])] = strings.T
rimSpace(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.(*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 printer.Fprint(&buf, fset, f.AST) |
| 114 |
| 115 return buf.String() |
| 116 } |
| 117 |
| 118 // cdefs returns the output for -cdefs mode. |
| 119 // The easiest way to do this is to translate the godefs Go to C. |
| 120 func (p *Package) cdefs(f *File, srcfile string) string { |
| 121 godefsOutput := p.godefs(f, srcfile) |
| 122 |
| 123 lines := strings.Split(godefsOutput, "\n") |
| 124 lines[0] = "// Created by cgo -cdefs - DO NOT EDIT" |
| 125 |
| 126 for i, line := range lines { |
| 127 lines[i] = strings.TrimSpace(line) |
| 128 } |
| 129 |
| 130 var out bytes.Buffer |
| 131 printf := func(format string, args ...interface{}) { fmt.Fprintf(&out, f
ormat, args...) } |
| 132 |
| 133 didTypedef := false |
| 134 for i := 0; i < len(lines); i++ { |
| 135 line := lines[i] |
| 136 |
| 137 // Delete |
| 138 // package x |
| 139 if strings.HasPrefix(line, "package ") { |
| 140 continue |
| 141 } |
| 142 |
| 143 // Convert |
| 144 // const ( |
| 145 // A = 1 |
| 146 // B = 2 |
| 147 // ) |
| 148 // |
| 149 // to |
| 150 // |
| 151 // enum { |
| 152 // A = 1, |
| 153 // B = 2, |
| 154 // }; |
| 155 if line == "const (" { |
| 156 printf("enum {\n") |
| 157 for i++; i < len(lines) && lines[i] != ")"; i++ { |
| 158 line = lines[i] |
| 159 if line != "" { |
| 160 printf("\t%s,", line) |
| 161 } |
| 162 printf("\n") |
| 163 } |
| 164 printf("};\n") |
| 165 continue |
| 166 } |
| 167 |
| 168 // Convert |
| 169 // const A = 1 |
| 170 // to |
| 171 // enum { A = 1 }; |
| 172 if strings.HasPrefix(line, "const ") { |
| 173 printf("enum { %s };\n", line[len("const "):]) |
| 174 continue |
| 175 } |
| 176 |
| 177 // On first type definition, typedef all the structs |
| 178 // in case there are dependencies between them. |
| 179 if !didTypedef && strings.HasPrefix(line, "type ") { |
| 180 didTypedef = true |
| 181 for _, line := range lines { |
| 182 line = strings.TrimSpace(line) |
| 183 if strings.HasPrefix(line, "type ") && strings.H
asSuffix(line, " struct {") { |
| 184 s := line[len("type ") : len(line)-len("
struct {")] |
| 185 printf("typedef struct %s %s;\n", s, s) |
| 186 } |
| 187 } |
| 188 printf("\n") |
| 189 printf("#pragma pack on\n") |
| 190 printf("\n") |
| 191 } |
| 192 |
| 193 // Convert |
| 194 // type T struct { |
| 195 // X int64 |
| 196 // Y *int32 |
| 197 // Z [4]byte |
| 198 // } |
| 199 // |
| 200 // to |
| 201 // |
| 202 // struct T { |
| 203 // int64 X; |
| 204 // int32 *Y; |
| 205 // byte Z[4]; |
| 206 // } |
| 207 if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, "
struct {") { |
| 208 s := line[len("type ") : len(line)-len(" struct {")] |
| 209 printf("struct %s {\n", s) |
| 210 for i++; i < len(lines) && lines[i] != "}"; i++ { |
| 211 line := lines[i] |
| 212 if line != "" { |
| 213 f := strings.Fields(line) |
| 214 if len(f) != 2 { |
| 215 fmt.Fprintf(os.Stderr, "cgo: can
not parse struct field: %s\n", line) |
| 216 nerrors++ |
| 217 continue |
| 218 } |
| 219 printf("\t%s;", cdecl(f[0], f[1])) |
| 220 } |
| 221 printf("\n") |
| 222 } |
| 223 printf("};\n") |
| 224 continue |
| 225 } |
| 226 |
| 227 // Convert |
| 228 // type T int |
| 229 // to |
| 230 // typedef int T; |
| 231 if strings.HasPrefix(line, "type ") { |
| 232 f := strings.Fields(line[len("type "):]) |
| 233 if len(f) != 2 { |
| 234 fmt.Fprintf(os.Stderr, "cgo: cannot parse type d
efinition: %s\n", line) |
| 235 nerrors++ |
| 236 continue |
| 237 } |
| 238 printf("typedef\t%s;\n", cdecl(f[0], f[1])) |
| 239 continue |
| 240 } |
| 241 |
| 242 printf("%s\n", line) |
| 243 } |
| 244 |
| 245 if didTypedef { |
| 246 printf("\n") |
| 247 printf("#pragma pack off\n") |
| 248 } |
| 249 |
| 250 return out.String() |
| 251 } |
| 252 |
| 253 // cdecl returns the C declaration for the given Go name and type. |
| 254 // It only handles the specific cases necessary for converting godefs output. |
| 255 func cdecl(name, typ string) string { |
| 256 // X *[0]byte -> X *void |
| 257 if strings.HasPrefix(typ, "*[0]") { |
| 258 typ = "*void" |
| 259 } |
| 260 // X *byte -> *X byte |
| 261 if strings.HasPrefix(typ, "*") { |
| 262 name = "*" + name |
| 263 typ = typ[1:] |
| 264 } |
| 265 // X [4]byte -> X[4] byte |
| 266 if strings.HasPrefix(typ, "[") { |
| 267 i := strings.Index(typ, "]") + 1 |
| 268 name = name + typ[:i] |
| 269 typ = typ[i:] |
| 270 } |
| 271 // X T -> T X |
| 272 return typ + "\t" + name |
| 273 } |
| 274 |
| 275 var gofmtBuf bytes.Buffer |
| 276 |
| 277 // gofmt returns the gofmt-formatted string for an AST node. |
| 278 func gofmt(n interface{}) string { |
| 279 gofmtBuf.Reset() |
| 280 err := printer.Fprint(&gofmtBuf, fset, n) |
| 281 if err != nil { |
| 282 return "<" + err.Error() + ">" |
| 283 } |
| 284 return gofmtBuf.String() |
| 285 } |
OLD | NEW |