|
1 | 1 | package lua |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "bufio" |
4 | 5 | "fmt" |
5 | 6 | "io" |
6 | 7 | "io/ioutil" |
7 | 8 | "os" |
| 9 | + "strconv" |
8 | 10 | ) |
9 | 11 |
|
10 | 12 | const fileHandle = "FILE*" |
@@ -114,14 +116,65 @@ func readNumber(l *State, f *os.File) (err error) { |
114 | 116 | return |
115 | 117 | } |
116 | 118 |
|
| 119 | +func readAll(l *State, f *os.File) error { |
| 120 | + bytes, err := ioutil.ReadAll(f) |
| 121 | + if err == nil { |
| 122 | + l.PushString(string(bytes)) |
| 123 | + } |
| 124 | + return err |
| 125 | +} |
| 126 | + |
| 127 | +func readLineHelper(l *State, f *os.File) error { |
| 128 | + originalFileOffset, err := f.Seek(0, 1) |
| 129 | + if err != nil { |
| 130 | + return err |
| 131 | + } |
| 132 | + |
| 133 | + reader := bufio.NewReader(f) |
| 134 | + bytes, err := reader.ReadBytes('\n') |
| 135 | + if err == nil { |
| 136 | + l.PushString(string(bytes)) |
| 137 | + length := int64(len(bytes)) |
| 138 | + f.Seek(originalFileOffset+length, 0) // bufio loads the entire file. This is a lazy hack to get around the problem. |
| 139 | + } |
| 140 | + return err |
| 141 | +} |
| 142 | + |
| 143 | +func readBytes(l *State, f *os.File, i int) error { |
| 144 | + buf := make([]byte, i) |
| 145 | + _, err := f.Read(buf) |
| 146 | + if err == nil { |
| 147 | + l.PushString(string(buf)) |
| 148 | + } |
| 149 | + return err |
| 150 | +} |
| 151 | + |
117 | 152 | func read(l *State, f *os.File, argIndex int) int { |
118 | 153 | resultCount := 0 |
119 | 154 | var err error |
120 | 155 | if argCount := l.Top() - 1; argCount == 0 { |
121 | | - // err = readLineHelper(l, f, true) |
| 156 | + err = readLineHelper(l, f) |
122 | 157 | resultCount = argIndex + 1 |
123 | 158 | } else { |
124 | | - // TODO |
| 159 | + if !l.CheckStack(l.Top() - 1) { |
| 160 | + Errorf(l, "too many arguments") |
| 161 | + } |
| 162 | + |
| 163 | + p := CheckString(l, l.Top()) |
| 164 | + switch p[0:2] { |
| 165 | + case "*a": |
| 166 | + err = readAll(l, f) |
| 167 | + case "*n": |
| 168 | + err = readNumber(l, f) |
| 169 | + case "*l": |
| 170 | + err = readLineHelper(l, f) |
| 171 | + default: |
| 172 | + i, err := strconv.Atoi(p) |
| 173 | + if err != nil { |
| 174 | + Errorf(l, "invalid format") |
| 175 | + } |
| 176 | + err = readBytes(l, f, i) |
| 177 | + } |
125 | 178 | } |
126 | 179 | if err != nil { |
127 | 180 | return FileResult(l, err, "") |
@@ -256,7 +309,7 @@ var fileHandleMethods = []RegistryFunction{ |
256 | 309 | {"close", close}, |
257 | 310 | {"flush", func(l *State) int { return FileResult(l, toFile(l).Sync(), "") }}, |
258 | 311 | {"lines", func(l *State) int { toFile(l); lines(l, false); return 1 }}, |
259 | | - {"read", func(l *State) int { return read(l, toFile(l), 2) }}, |
| 312 | + {"read", func(l *State) int { read(l, toFile(l), 2); return 1 }}, |
260 | 313 | {"seek", func(l *State) int { |
261 | 314 | whence := []int{os.SEEK_SET, os.SEEK_CUR, os.SEEK_END} |
262 | 315 | f := toFile(l) |
|
0 commit comments