func OpenFile(name, mode string) (*File, error) {
	var flag int
	switch strings.TrimSuffix(mode, "b") {
	case "r":
		flag = os.O_RDONLY
	case "w":
		flag = os.O_WRONLY | os.O_CREATE | os.O_TRUNC
	case "a":
		flag = os.O_WRONLY | os.O_CREATE | os.O_APPEND
	case "r+":
		flag = os.O_RDWR
	case "w+":
		flag = os.O_RDWR | os.O_CREATE | os.O_TRUNC
	case "a+":
		flag = os.O_RDWR | os.O_CREATE | os.O_APPEND
	default:
		return nil, errors.New("invalid mode")
	}
	f, err := os.OpenFile(name, flag, 0666)
	if err != nil {
		return nil, err
	}
	return NewFile(f, true), nil
}
OpenFile opens a file with the given name in the given lua mode.
package iolib
import (
	"bufio"
	"errors"
	"io"
	"io/ioutil"
	"os"
	"strings"
	rt "github.com/arnodel/golua/runtime"
)
func NewFile(file *os.File, buffered bool) *File {
	f := &File{file: file}
	if buffered {
		f.reader = bufio.NewReader(file)
		f.writer = bufio.NewWriterSize(file, 65536)
	} else {
		f.reader = &nobufReader{file}
		f.writer = &nobufWriter{file}
	}
	currentFiles[f] = struct{}{}
	return f
}
func FileArg(c *rt.GoCont, n int) (*File, *rt.Error) {
	f, ok := ValueToFile(c.Arg(n))
	if ok {
		return f, nil
	}
	return nil, rt.NewErrorF("#%d must be a file", n+1)
}
func ValueToFile(v rt.Value) (*File, bool) {
	u, ok := v.TryUserData()
	if ok {
		return u.Value().(*File), true
	}
	return nil, false
}
func TempFile() (*File, error) {
	f, err := ioutil.TempFile("", "golua")
	if err != nil {
		return nil, err
	}
	ff := NewFile(f, true)
	ff.temp = true
	return ff, nil
}
type bufReader interface {
	io.Reader
	Reset(r io.Reader)
	Buffered() int
	Discard(int) (int, error)
	ReadString(delim byte) (string, error)
}
type bufWriter interface {
	io.Writer
	Reset(w io.Writer)
	Flush() error
}
type nobufReader struct {
	io.Reader
}
var (
	_ bufReader = (*nobufReader)(nil)
	_ bufReader = (*bufio.Reader)(nil)
	_ bufWriter = (*nobufWriter)(nil)
	_ bufWriter = (*bufio.Writer)(nil)
)
func (u *nobufReader) Reset(r io.Reader) {
	u.Reader = r
}
func (u *nobufReader) Buffered() int {
	return 0
}
func (u *nobufReader) Discard(n int) (int, error) {
	if n > 0 {
		return 0, errors.New("nobufReader cannot discard")
	}
	return 0, nil
}
func (u *nobufReader) ReadString(delim byte) (string, error) {
	panic("unimplemented")
}
type nobufWriter struct {
	io.Writer
}
func (u *nobufWriter) Reset(w io.Writer) {
	u.Writer = w
}
func (u *nobufWriter) Flush() error {
	return nil
}
type File struct {
	file   *os.File
	closed bool
	reader bufReader
	writer bufWriter
	temp   bool
}
var currentFiles = map[*File]struct{}{}
func cleanupCurrentFiles() {
	for f := range currentFiles {
		switch f.file {
		case os.Stdout, os.Stderr:
			f.Flush()
		case os.Stdin:
		default:
			f.cleanup()
		}
	}
	currentFiles = map[*File]struct{}{}
}
func (f *File) release() {
	delete(currentFiles, f)
	f.cleanup()
}
func (f *File) cleanup() {
	_ = f.Close()
	if f.temp {
		_ = os.Remove(f.Name())
	}
}
func (f *File) IsClosed() bool {
	return f.closed
}
func (f *File) Close() error {
	f.closed = true
	errFlush := f.writer.Flush()
	err := f.file.Close()
	if err == nil {
		return errFlush
	}
	return err
}
func (f *File) Flush() error {
	if err := f.writer.Flush(); err != nil {
		return err
	}
	return f.file.Sync()
}