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  }