// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Cgo; see gmp.go for an overview.

// TODO(rsc):
//	Emit correct line number annotations.
//	Make 6g understand the annotations.

package main

import (
	"fmt";
	"go/ast";
	"os";
)

func usage() {
	fmt.Fprint(os.Stderr, "usage: cgo [compiler options] file.go\n");
}

var ptrSizeMap = map[string]int64{
	"386": 4,
	"amd64": 8,
	"arm": 4,
}

var expandName = map[string]string{
	"schar": "signed char",
	"uchar": "unsigned char",
	"ushort": "unsigned short",
	"uint": "unsigned int",
	"ulong": "unsigned long",
	"longlong": "long long",
	"ulonglong": "unsigned long long",
}

func main() {
	args := os.Args;
	if len(args) < 2 {
		usage();
		os.Exit(2);
	}
	gccOptions := args[1 : len(args)-1];
	input := args[len(args)-1];

	arch := os.Getenv("GOARCH");
	if arch == "" {
		fatal("$GOARCH is not set");
	}
	ptrSize, ok := ptrSizeMap[arch];
	if !ok {
		fatal("unknown architecture %s", arch);
	}

	p := openProg(input);
	for _, cref := range p.Crefs {
		// Convert C.ulong to C.unsigned long, etc.
		if expand, ok := expandName[cref.Name]; ok {
			cref.Name = expand;
		}
	}

	p.PtrSize = ptrSize;
	p.Preamble = p.Preamble + "\n" + builtinProlog;
	p.GccOptions = gccOptions;
	p.loadDebugInfo();
	p.Vardef = make(map[string]*Type);
	p.Funcdef = make(map[string]*FuncType);

	for _, cref := range p.Crefs {
		switch cref.Context {
		case "call":
			if !cref.TypeName {
				// Is an actual function call.
				*cref.Expr = &ast.Ident{Value: "_C_" + cref.Name};
				p.Funcdef[cref.Name] = cref.FuncType;
				break;
			}
			*cref.Expr = cref.Type.Go;
		case "expr":
			if cref.TypeName {
				error((*cref.Expr).Pos(), "type C.%s used as expression", cref.Name);
			}
			// Reference to C variable.
			// We declare a pointer and arrange to have it filled in.
			*cref.Expr = &ast.StarExpr{X: &ast.Ident{Value: "_C_" + cref.Name}};
			p.Vardef[cref.Name] = cref.Type;
		case "type":
			if !cref.TypeName {
				error((*cref.Expr).Pos(), "expression C.%s used as type", cref.Name);
			}
			*cref.Expr = cref.Type.Go;
		}
	}
	if nerrors > 0 {
		os.Exit(2);
	}

	p.PackagePath = p.Package;
	p.writeOutput(input);
}
