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

     1  package io
     2  
     3  import (
     4  	"io"
     5  	"io/ioutil"
     6  
     7  	"github.com/hirochachacha/plua/internal/file"
     8  	"github.com/hirochachacha/plua/object"
     9  	"github.com/hirochachacha/plua/object/fnutil"
    10  )
    11  
    12  func _read(th object.Thread, args []object.Value, f file.File, off int, doClose bool, raiseError bool) ([]object.Value, *object.RuntimeError) {
    13  	if f.IsClosed() {
    14  		return nil, object.NewRuntimeError("file is already closed")
    15  	}
    16  
    17  	ap := fnutil.NewArgParser(th, args)
    18  
    19  	if len(args) == off {
    20  		line, err := readStrippedLine(f)
    21  		if err != nil {
    22  			if doClose {
    23  				f.Close()
    24  			}
    25  			if err != io.EOF {
    26  				if raiseError {
    27  					return nil, object.NewRuntimeError(err.Error())
    28  				}
    29  				return fileResult(th, err)
    30  			}
    31  			return []object.Value{nil}, nil
    32  		}
    33  		return []object.Value{line}, nil
    34  	}
    35  
    36  	rets := make([]object.Value, 0, len(args)-off)
    37  
    38  	for i := range args[off:] {
    39  		if i64, err := ap.ToGoInt64(i + off); err == nil {
    40  			s, err := readCount(f, i64)
    41  			if err != nil {
    42  				if err == io.EOF {
    43  					if len(rets) == 0 {
    44  						if doClose {
    45  							f.Close()
    46  						}
    47  						rets = append(rets, nil)
    48  					}
    49  					return rets, nil
    50  				}
    51  				if doClose {
    52  					f.Close()
    53  				}
    54  				if raiseError {
    55  					return nil, object.NewRuntimeError(err.Error())
    56  				}
    57  				return fileResult(th, err)
    58  			}
    59  
    60  			rets = append(rets, s)
    61  
    62  			continue
    63  		}
    64  
    65  		fmt, err := ap.ToGoString(i + off)
    66  		if err != nil {
    67  			return nil, ap.TypeError(i+off, "string or integer")
    68  		}
    69  
    70  		if len(fmt) > 0 && fmt[0] == '*' {
    71  			fmt = fmt[1:]
    72  		}
    73  
    74  		var val object.Value
    75  		var e error
    76  
    77  		switch fmt {
    78  		case "n":
    79  			val, e = readNumber(f)
    80  		case "a", "all":
    81  			val, e = readAll(f)
    82  		case "l":
    83  			val, e = readStrippedLine(f)
    84  		case "L":
    85  			val, e = readLine(f)
    86  		default:
    87  			return nil, ap.ArgError(i+off, "invalid format")
    88  		}
    89  
    90  		if e != nil {
    91  			if e == io.EOF {
    92  				if len(rets) == 0 {
    93  					if doClose {
    94  						f.Close()
    95  					}
    96  					rets = append(rets, nil)
    97  				}
    98  				return rets, nil
    99  			}
   100  			if doClose {
   101  				f.Close()
   102  			}
   103  			if raiseError {
   104  				return nil, object.NewRuntimeError(e.Error())
   105  			}
   106  			return fileResult(th, e)
   107  		}
   108  
   109  		rets = append(rets, val)
   110  	}
   111  
   112  	return rets, nil
   113  }
   114  
   115  func readNumber(f file.File) (val object.Value, err error) {
   116  	return newScanner(f).scanNumber()
   117  }
   118  
   119  func readAll(f file.File) (val object.Value, err error) {
   120  	bs, err := ioutil.ReadAll(f)
   121  	if err != nil {
   122  		return nil, err
   123  	}
   124  
   125  	return object.String(bs), nil
   126  }
   127  
   128  func readStrippedLine(f file.File) (s object.Value, err error) {
   129  	line, err := f.ReadBytes('\n')
   130  	if err != nil {
   131  		if err == io.EOF {
   132  			if len(line) == 0 {
   133  				return nil, io.EOF
   134  			}
   135  			return object.String(line), nil
   136  		}
   137  		return nil, err
   138  	}
   139  
   140  	if len(line) == 0 {
   141  		return nil, io.EOF
   142  	}
   143  
   144  	return object.String(line[:len(line)-1]), nil
   145  }
   146  
   147  func readLine(f file.File) (s object.Value, err error) {
   148  	line, err := f.ReadBytes('\n')
   149  	if err != nil {
   150  		if err == io.EOF {
   151  			if len(line) == 0 {
   152  				return nil, io.EOF
   153  			}
   154  			return object.String(line), nil
   155  		}
   156  		return nil, err
   157  	}
   158  
   159  	if len(line) == 0 {
   160  		return nil, io.EOF
   161  	}
   162  
   163  	return object.String(line), nil
   164  }
   165  
   166  func readCount(f file.File, i int64) (s object.Value, err error) {
   167  	if i == 0 {
   168  		_, err := f.ReadByte()
   169  		if err != nil {
   170  			return nil, err
   171  		}
   172  
   173  		f.UnreadByte()
   174  
   175  		return object.String(""), nil
   176  	}
   177  
   178  	bs := make([]byte, i)
   179  
   180  	var n int
   181  	for {
   182  		var m int
   183  		m, err = f.Read(bs[n:])
   184  		n += m
   185  		if err != nil {
   186  			break
   187  		}
   188  		if i == int64(n) {
   189  			break
   190  		}
   191  	}
   192  
   193  	return object.String(bs[:n]), err
   194  }