github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/internal/file/rwfile.go (about) 1 package file 2 3 import ( 4 "bufio" 5 "bytes" 6 "errors" 7 "os" 8 "strings" 9 ) 10 11 type state int 12 13 const ( 14 seek state = iota 15 read 16 write 17 ) 18 19 type file struct { 20 *os.File 21 br *bufio.Reader 22 bw *bufio.Writer 23 off int64 24 mode int 25 state state // previous action type 26 closed bool 27 std bool 28 } 29 30 func (f *file) IsClosed() bool { 31 return f.closed 32 } 33 34 func (f *file) Close() error { 35 if f.std { 36 return errors.New("cannot close standard file") 37 } 38 39 if err := f.bw.Flush(); err != nil { 40 return err 41 } 42 43 if err := f.File.Close(); err != nil { 44 return err 45 } 46 47 f.closed = true 48 49 return nil 50 } 51 52 func (f *file) Write(p []byte) (nn int, err error) { 53 if f.state == read { 54 _, err = f.Seek(f.off, 0) 55 if err != nil { 56 return 57 } 58 59 f.br.Reset(f.File) 60 } 61 62 switch f.mode { 63 case IONBF: 64 nn, err = f.File.Write(p) 65 f.off += int64(nn) 66 if err != nil { 67 return 68 } 69 case IOFBF: 70 nn, err = f.bw.Write(p) 71 f.off += int64(nn) 72 if err != nil { 73 return 74 } 75 case IOLBF: 76 i := bytes.LastIndexByte(p, '\n') 77 if i == -1 { 78 nn, err = f.bw.Write(p) 79 f.off += int64(nn) 80 if err != nil { 81 return 82 } 83 } else { 84 nn, err = f.bw.Write(p[:i+1]) 85 f.off += int64(nn) 86 if err != nil { 87 return 88 } 89 err = f.bw.Flush() 90 if err != nil { 91 return 92 } 93 94 nn, err = f.bw.Write(p[i+1:]) 95 f.off += int64(nn) 96 if err != nil { 97 return 98 } 99 } 100 } 101 102 f.state = write 103 104 return 105 } 106 107 func (f *file) WriteString(s string) (nn int, err error) { 108 if f.state == read { 109 _, err = f.Seek(f.off, 0) 110 if err != nil { 111 return 112 } 113 114 f.br.Reset(f.File) 115 } 116 117 switch f.mode { 118 case IONBF: 119 nn, err = f.File.WriteString(s) 120 f.off += int64(nn) 121 if err != nil { 122 return 123 } 124 case IOFBF: 125 nn, err = f.bw.WriteString(s) 126 f.off += int64(nn) 127 if err != nil { 128 return 129 } 130 case IOLBF: 131 i := strings.LastIndexByte(s, '\n') 132 if i == -1 { 133 nn, err = f.bw.WriteString(s) 134 f.off += int64(nn) 135 if err != nil { 136 return 137 } 138 } else { 139 nn, err = f.bw.WriteString(s[:i+1]) 140 f.off += int64(nn) 141 if err != nil { 142 return 143 } 144 err = f.bw.Flush() 145 if err != nil { 146 return 147 } 148 149 nn, err = f.bw.WriteString(s[i+1:]) 150 f.off += int64(nn) 151 if err != nil { 152 return 153 } 154 } 155 } 156 157 f.state = write 158 159 return 160 } 161 162 func (f *file) Flush() error { 163 return f.bw.Flush() 164 } 165 166 func (f *file) UnreadByte() (err error) { 167 if f.state == write { 168 err = f.bw.Flush() 169 if err != nil { 170 return 171 } 172 } 173 174 err = f.br.UnreadByte() 175 if err == nil { 176 f.off-- 177 } 178 179 f.state = read 180 181 return 182 } 183 184 func (f *file) ReadByte() (c byte, err error) { 185 if f.state == write { 186 err = f.bw.Flush() 187 if err != nil { 188 return 189 } 190 } 191 192 c, err = f.br.ReadByte() 193 if err == nil { 194 f.off++ 195 } 196 197 f.state = read 198 199 return 200 } 201 202 func (f *file) Read(p []byte) (n int, err error) { 203 if f.state == write { 204 err = f.bw.Flush() 205 if err != nil { 206 return 207 } 208 } 209 210 n, err = f.br.Read(p) 211 f.off += int64(n) 212 if err != nil { 213 return 214 } 215 216 f.state = read 217 218 return 219 } 220 221 func (f *file) ReadBytes(delim byte) (line []byte, err error) { 222 if f.state == write { 223 err = f.bw.Flush() 224 if err != nil { 225 return 226 } 227 228 f.br.Reset(f.File) 229 } 230 231 line, err = f.br.ReadBytes(delim) 232 f.off += int64(len(line)) 233 if err != nil { 234 return 235 } 236 237 f.state = read 238 239 return 240 } 241 242 func (f *file) Seek(offset int64, whence int) (n int64, err error) { 243 if f.state == write { 244 if err := f.bw.Flush(); err != nil { 245 return 0, err 246 } 247 } 248 249 switch whence { 250 case 0: 251 if f.off <= offset && offset <= f.off+int64(f.br.Buffered()) { 252 f.br.Discard(int(offset - f.off)) 253 f.off = offset 254 } else { 255 f.off, err = f.File.Seek(offset, 0) 256 f.br.Reset(f.File) 257 } 258 case 1: 259 if 0 <= offset && offset <= int64(f.br.Buffered()) { 260 f.br.Discard(int(offset)) 261 f.off += offset 262 } else { 263 f.off, err = f.File.Seek(f.off+offset, 1) 264 f.br.Reset(f.File) 265 } 266 case 2: 267 f.off, err = f.File.Seek(offset, 2) 268 f.br.Reset(f.File) 269 } 270 271 n = f.off 272 273 if err != nil { 274 return 275 } 276 277 f.state = seek 278 279 return 280 } 281 282 func (f *file) Setvbuf(mode int, size int) (err error) { 283 switch f.state { 284 case read: 285 _, err = f.Seek(f.off, 0) 286 if err != nil { 287 return 288 } 289 case write: 290 err = f.bw.Flush() 291 if err != nil { 292 return err 293 } 294 } 295 296 f.mode = mode 297 f.state = seek 298 299 if size > 0 { 300 f.br = bufio.NewReaderSize(f.File, size) 301 f.bw = bufio.NewWriterSize(f.File, size) 302 } 303 304 return 305 }