github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/stdlib/io/file.go (about)

     1  package io
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hirochachacha/plua/internal/file"
     7  	"github.com/hirochachacha/plua/internal/version"
     8  	"github.com/hirochachacha/plua/object"
     9  	"github.com/hirochachacha/plua/object/fnutil"
    10  )
    11  
    12  func toFile(ap *fnutil.ArgParser, n int) (file.File, *object.RuntimeError) {
    13  	ud, err := ap.ToFullUserdata(n)
    14  	if err != nil {
    15  		return nil, ap.TypeError(n, "FILE*")
    16  	}
    17  
    18  	f, ok := ud.Value.(file.File)
    19  	if !ok {
    20  		return nil, ap.TypeError(n, "FILE*")
    21  	}
    22  
    23  	if f.IsClosed() {
    24  		return nil, object.NewRuntimeError("attempt to use a closed file")
    25  	}
    26  
    27  	return f, nil
    28  }
    29  
    30  func fclose(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
    31  	ap := fnutil.NewArgParser(th, args)
    32  
    33  	f, err := toFile(ap, 0)
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  
    38  	return fileResult(th, f.Close())
    39  }
    40  
    41  func fflush(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
    42  	ap := fnutil.NewArgParser(th, args)
    43  
    44  	f, err := toFile(ap, 0)
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  
    49  	return fileResult(th, f.Flush())
    50  }
    51  
    52  func flines(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
    53  	ap := fnutil.NewArgParser(th, args)
    54  
    55  	f, err := toFile(ap, 0)
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  
    60  	if len(args)-1 > version.MAXARGLINE {
    61  		return nil, object.NewRuntimeError("too many arguments")
    62  	}
    63  
    64  	fnargs := append([]object.Value{}, args...)
    65  
    66  	retfn := func(_ object.Thread, _ ...object.Value) ([]object.Value, *object.RuntimeError) {
    67  		return _read(th, fnargs, f, 1, false, true)
    68  	}
    69  
    70  	return []object.Value{object.GoFunction(retfn)}, nil
    71  }
    72  
    73  func fread(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
    74  	ap := fnutil.NewArgParser(th, args)
    75  
    76  	f, err := toFile(ap, 0)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  
    81  	return _read(th, args, f, 1, false, false)
    82  }
    83  
    84  func fseek(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
    85  	ap := fnutil.NewArgParser(th, args)
    86  
    87  	f, err := toFile(ap, 0)
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  
    92  	whence, err := ap.OptGoString(1, "cur")
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  
    97  	offset, err := ap.OptGoInt64(2, 0)
    98  	if err != nil {
    99  		return nil, err
   100  	}
   101  
   102  	var n int64
   103  	var e error
   104  
   105  	switch whence {
   106  	case "set":
   107  		n, e = f.Seek(offset, 0)
   108  	case "cur":
   109  		n, e = f.Seek(offset, 1)
   110  	case "end":
   111  		n, e = f.Seek(offset, 2)
   112  	default:
   113  		return nil, ap.OptionError(1, whence)
   114  	}
   115  
   116  	if e != nil {
   117  		return fileResult(th, e)
   118  	}
   119  
   120  	return []object.Value{object.Integer(n)}, nil
   121  }
   122  
   123  func fsetvbuf(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   124  	ap := fnutil.NewArgParser(th, args)
   125  
   126  	f, err := toFile(ap, 0)
   127  	if err != nil {
   128  		return nil, err
   129  	}
   130  
   131  	mode, err := ap.ToGoString(1)
   132  	if err != nil {
   133  		return nil, err
   134  	}
   135  
   136  	size, err := ap.OptGoInt(2, 0)
   137  	if err != nil {
   138  		return nil, err
   139  	}
   140  
   141  	var e error
   142  
   143  	switch mode {
   144  	case "no":
   145  		e = f.Setvbuf(file.IONBF, size)
   146  	case "line":
   147  		e = f.Setvbuf(file.IOLBF, size)
   148  	case "full":
   149  		e = f.Setvbuf(file.IOFBF, size)
   150  	default:
   151  		return nil, ap.OptionError(1, mode)
   152  	}
   153  
   154  	return fileResult(th, e)
   155  }
   156  
   157  func fwrite(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   158  	ap := fnutil.NewArgParser(th, args)
   159  
   160  	f, err := toFile(ap, 0)
   161  	if err != nil {
   162  		return nil, err
   163  	}
   164  
   165  	for i := range args[1:] {
   166  		s, err := ap.ToGoString(i + 1)
   167  		if err != nil {
   168  			return nil, err
   169  		}
   170  
   171  		_, e := f.WriteString(s)
   172  		if e != nil {
   173  			return fileResult(th, e)
   174  		}
   175  	}
   176  
   177  	return []object.Value{args[0]}, nil
   178  }
   179  
   180  func ftostring(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   181  	ap := fnutil.NewArgParser(th, args)
   182  
   183  	ud, err := ap.ToFullUserdata(0)
   184  	if err != nil {
   185  		return nil, ap.TypeError(0, "FILE*")
   186  	}
   187  
   188  	f, ok := ud.Value.(file.File)
   189  	if !ok {
   190  		return nil, ap.TypeError(0, "FILE*")
   191  	}
   192  
   193  	if f.IsClosed() {
   194  		return []object.Value{object.String("file (closed)")}, nil
   195  	}
   196  
   197  	return []object.Value{object.String(fmt.Sprintf("file (%p)", f))}, nil
   198  }