cgo: various bug fixes

* remember #defined names, so that C.stdout can refer
  to the real name (on OS X) __stdoutp.
* better handling of #defined constant expressions
* allow n, err = C.strtol("asdf", 0, 123) to get errno as os.Error
* write all output files to current directory
* don't require gcc output if there was no input

Fixes #533.
Fixes #709.
Fixes #756.

R=r
CC=dho, golang-dev, iant
https://golang.org/cl/1734047
diff --git a/misc/cgo/stdio/Makefile b/misc/cgo/stdio/Makefile
index 2e3d466..a0093ff 100644
--- a/misc/cgo/stdio/Makefile
+++ b/misc/cgo/stdio/Makefile
@@ -6,7 +6,9 @@
 
 TARG=stdio
 CGOFILES=\
-	file.go
+	align.go\
+	file.go\
+	test.go\
 
 CLEANFILES+=hello fib chain run.out
 
diff --git a/misc/cgo/stdio/align.go b/misc/cgo/stdio/align.go
new file mode 100644
index 0000000..6cdfd90
--- /dev/null
+++ b/misc/cgo/stdio/align.go
@@ -0,0 +1,78 @@
+package stdio
+
+/*
+#include <stdio.h>
+
+typedef unsigned char Uint8;
+typedef unsigned short Uint16;
+
+typedef enum {
+ MOD1 = 0x0000,
+ MODX = 0x8000
+} SDLMod;
+
+typedef enum {
+ A = 1,
+ B = 322,
+ SDLK_LAST
+} SDLKey;
+
+typedef struct SDL_keysym {
+	Uint8 scancode;
+	SDLKey sym;
+	SDLMod mod;
+	Uint16 unicode;
+} SDL_keysym;
+
+typedef struct SDL_KeyboardEvent {
+	Uint8 typ;
+	Uint8 which;
+	Uint8 state;
+	SDL_keysym keysym;
+} SDL_KeyboardEvent;
+
+void makeEvent(SDL_KeyboardEvent *event) {
+ unsigned char *p;
+ int i;
+
+ p = (unsigned char*)event;
+ for (i=0; i<sizeof *event; i++) {
+   p[i] = i;
+ }
+}
+
+int same(SDL_KeyboardEvent* e, Uint8 typ, Uint8 which, Uint8 state, Uint8 scan, SDLKey sym, SDLMod mod, Uint16 uni) {
+  return e->typ == typ && e->which == which && e->state == state && e->keysym.scancode == scan && e->keysym.sym == sym && e->keysym.mod == mod && e->keysym.unicode == uni;
+}
+
+void cTest(SDL_KeyboardEvent *event) {
+ printf("C: %#x %#x %#x %#x %#x %#x %#x\n", event->typ, event->which, event->state,
+   event->keysym.scancode, event->keysym.sym, event->keysym.mod, event->keysym.unicode);
+ fflush(stdout);
+}
+
+*/
+import "C"
+
+import (
+	"fmt"
+	"syscall"
+)
+
+func TestAlign() {
+	if syscall.ARCH == "amd64" {
+		// alignment is known to be broken on amd64.
+		// http://code.google.com/p/go/issues/detail?id=609
+		return
+	}
+	var evt C.SDL_KeyboardEvent
+	C.makeEvent(&evt)
+	if C.same(&evt, evt.typ, evt.which, evt.state, evt.keysym.scancode, evt.keysym.sym, evt.keysym.mod, evt.keysym.unicode) == 0 {
+		fmt.Println("*** bad alignment")
+		C.cTest(&evt)
+		fmt.Printf("Go: %#x %#x %#x %#x %#x %#x %#x\n",
+			evt.typ, evt.which, evt.state, evt.keysym.scancode,
+			evt.keysym.sym, evt.keysym.mod, evt.keysym.unicode)
+		fmt.Println(evt)
+	}
+}
diff --git a/misc/cgo/stdio/chain.go b/misc/cgo/stdio/chain.go
index dd5e015..c2b1050 100644
--- a/misc/cgo/stdio/chain.go
+++ b/misc/cgo/stdio/chain.go
@@ -22,7 +22,7 @@
 	runtime.LockOSThread()
 	for {
 		v := <-right
-		stdio.Puts(strconv.Itoa(v))
+		stdio.Stdout.WriteString(strconv.Itoa(v) + "\n")
 		left <- 1+v
 	}
 }
@@ -38,6 +38,6 @@
 	for i := 0; i < R; i++ {
 		right <- 0
 		x := <-leftmost
-		stdio.Puts(strconv.Itoa(x))
+		stdio.Stdout.WriteString(strconv.Itoa(x) + "\n")
 	}
 }
diff --git a/misc/cgo/stdio/fib.go b/misc/cgo/stdio/fib.go
index 63ae049..c02e31f 100644
--- a/misc/cgo/stdio/fib.go
+++ b/misc/cgo/stdio/fib.go
@@ -26,7 +26,7 @@
 	}
 	for {
 		j := <-c
-		stdio.Puts(strconv.Itoa64(j))
+		stdio.Stdout.WriteString(strconv.Itoa64(j) + "\n")
 		out <- j
 		<-out
 		i += j
diff --git a/misc/cgo/stdio/file.go b/misc/cgo/stdio/file.go
index 7d1f222..1f461f2 100644
--- a/misc/cgo/stdio/file.go
+++ b/misc/cgo/stdio/file.go
@@ -10,33 +10,31 @@
 
 package stdio
 
-// TODO(rsc): Remove fflushstdout when C.fflush(C.stdout) works in cgo.
-
 /*
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/stat.h>
+#include <errno.h>
 
-void fflushstdout(void) { fflush(stdout); }
+char* greeting = "hello, world";
 */
 import "C"
 import "unsafe"
 
-/*
 type File C.FILE
 
 var Stdout = (*File)(C.stdout)
 var Stderr = (*File)(C.stderr)
 
 func (f *File) WriteString(s string) {
-	p := C.CString(s);
-	C.fputs(p, (*C.FILE)(f));
-	C.free(p);
-}
-*/
-
-func Puts(s string) {
 	p := C.CString(s)
-	C.puts(p)
+	C.fputs(p, (*C.FILE)(f))
 	C.free(unsafe.Pointer(p))
-	C.fflushstdout()
+	f.Flush()
 }
+
+func (f *File) Flush() {
+	C.fflush((*C.FILE)(f))
+}
+
+var Greeting = C.GoString(C.greeting)
diff --git a/misc/cgo/stdio/hello.go b/misc/cgo/stdio/hello.go
index 47f9de0..9cb6e68 100644
--- a/misc/cgo/stdio/hello.go
+++ b/misc/cgo/stdio/hello.go
@@ -4,9 +4,26 @@
 
 package main
 
-import "stdio"
+import (
+	"os"
+	"stdio"
+)
 
 func main() {
-	//	stdio.Stdout.WriteString("hello, world\n");
-	stdio.Puts("hello, world")
+	stdio.Stdout.WriteString(stdio.Greeting + "\n")
+
+	l := stdio.Atol("123")
+	if l != 123 {
+		println("Atol 123: ", l)
+		panic("bad atol")
+	}
+
+	n, err := stdio.Strtol("asdf", 123)
+	if n != 0 || err != os.EINVAL {
+		println("Strtol: ", n, err)
+		panic("bad atoi2")
+	}
+
+	stdio.TestAlign()
+	stdio.TestEnum()
 }
diff --git a/misc/cgo/stdio/test.go b/misc/cgo/stdio/test.go
new file mode 100644
index 0000000..490eb93
--- /dev/null
+++ b/misc/cgo/stdio/test.go
@@ -0,0 +1,91 @@
+// Copyright 2010 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.
+
+// This file contains test cases for cgo.
+
+package stdio
+
+/*
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#define SHIFT(x, y)  ((x)<<(y))
+#define KILO SHIFT(1, 10)
+
+enum {
+	Enum1 = 1,
+	Enum2 = 2,
+};
+*/
+import "C"
+import (
+	"os"
+	"unsafe"
+)
+
+const EINVAL = C.EINVAL /* test #define */
+
+var KILO = C.KILO
+
+func Size(name string) (int64, os.Error) {
+	var st C.struct_stat
+	p := C.CString(name)
+	_, err := C.stat(p, &st)
+	C.free(unsafe.Pointer(p))
+	if err != nil {
+		return 0, err
+	}
+	return int64(C.ulong(st.st_size)), nil
+}
+
+func Strtol(s string, base int) (int, os.Error) {
+	p := C.CString(s)
+	n, err := C.strtol(p, nil, C.int(base))
+	C.free(unsafe.Pointer(p))
+	return int(n), err
+}
+
+func Atol(s string) int {
+	p := C.CString(s)
+	n := C.atol(p)
+	C.free(unsafe.Pointer(p))
+	return int(n)
+}
+
+func TestEnum() {
+	if C.Enum1 != 1 || C.Enum2 != 2 {
+		println("bad enum", C.Enum1, C.Enum2)
+	}
+}
+
+func TestAtol() {
+	l := Atol("123")
+	if l != 123 {
+		println("Atol 123: ", l)
+		panic("bad atol")
+	}
+}
+
+func TestErrno() {
+	n, err := Strtol("asdf", 123)
+	if n != 0 || err != os.EINVAL {
+		println("Strtol: ", n, err)
+		panic("bad atoi2")
+	}
+}
+
+var (
+	uint  = (C.uint)(0)
+	ulong C.ulong
+	char  C.char
+)
+
+func Test() {
+	TestAlign()
+	TestAtol()
+	TestEnum()
+	TestErrno()
+}