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
5package main
6
7import (
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.
19func (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
118var gofmtBuf bytes.Buffer
119
120// gofmt returns the gofmt-formatted string for an AST node.
121func 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}
129