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 }