Skip to content

Commit 80b1cb8

Browse files
author
Jessica Xie
committed
implement the read function
1 parent 05ce435 commit 80b1cb8

8 files changed

Lines changed: 160 additions & 3 deletions

File tree

fixtures/io.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
A banana contains 75% water.
2+
The most consumed fruit in America is the banana
3+
Bananas are a good source of vitamin C, potassium and fiber.
4+
Fresh apples float because they contain 25% air.
5+
Bananas contain no fat, cholesterol or sodium.

fixtures/number.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
12345

fixtures/read_all.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
file = io.open("fixtures/io.txt", "r")
2+
print(file:read("*a"))
3+
file:close()

fixtures/read_bytes.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
file = io.open("fixtures/io.txt", "r")
2+
print(file:read(20))
3+
file:close()

fixtures/read_lines.lua

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
file = io.open("fixtures/io.txt", "r")
2+
print(file:read("*l"))
3+
print(file:read("*l"))
4+
file:close()

fixtures/read_number.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
file = io.open("fixtures/number.txt", "r")
2+
print(file:read("*n"))
3+
file:close()

io.go

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package lua
22

33
import (
4+
"bufio"
45
"fmt"
56
"io"
67
"io/ioutil"
78
"os"
9+
"strconv"
810
)
911

1012
const fileHandle = "FILE*"
@@ -114,14 +116,65 @@ func readNumber(l *State, f *os.File) (err error) {
114116
return
115117
}
116118

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+
117152
func read(l *State, f *os.File, argIndex int) int {
118153
resultCount := 0
119154
var err error
120155
if argCount := l.Top() - 1; argCount == 0 {
121-
// err = readLineHelper(l, f, true)
156+
err = readLineHelper(l, f)
122157
resultCount = argIndex + 1
123158
} 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+
}
125178
}
126179
if err != nil {
127180
return FileResult(l, err, "")
@@ -256,7 +309,7 @@ var fileHandleMethods = []RegistryFunction{
256309
{"close", close},
257310
{"flush", func(l *State) int { return FileResult(l, toFile(l).Sync(), "") }},
258311
{"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 }},
260313
{"seek", func(l *State) int {
261314
whence := []int{os.SEEK_SET, os.SEEK_CUR, os.SEEK_END}
262315
f := toFile(l)

io_test.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package lua
2+
3+
import (
4+
"fmt"
5+
"io/ioutil"
6+
"os"
7+
"strings"
8+
"testing"
9+
)
10+
11+
// TODO: add missing tests
12+
13+
func TestReadAll(t *testing.T) {
14+
l := NewState()
15+
OpenLibraries(l)
16+
output := captureOutput(func() {
17+
DoFile(l, "fixtures/read_all.lua")
18+
})
19+
20+
expected := `A banana contains 75% water.
21+
The most consumed fruit in America is the banana
22+
Bananas are a good source of vitamin C, potassium and fiber.
23+
Fresh apples float because they contain 25% air.
24+
Bananas contain no fat, cholesterol or sodium.`
25+
26+
if strings.Trim(output, "\n") != expected {
27+
t.Errorf("Expecting:\n%s\nbut received:\n%s\n", expected, output)
28+
}
29+
}
30+
31+
func TestReadLines(t *testing.T) {
32+
l := NewState()
33+
OpenLibraries(l)
34+
output := captureOutput(func() {
35+
DoFile(l, "fixtures/read_lines.lua")
36+
})
37+
38+
expected := `A banana contains 75% water.
39+
40+
The most consumed fruit in America is the banana`
41+
42+
if strings.Trim(output, "\n") != expected {
43+
t.Errorf("Expecting:\n%s\nbut received:\n%s\n", expected, output)
44+
}
45+
}
46+
47+
func TestReadNumber(t *testing.T) {
48+
l := NewState()
49+
OpenLibraries(l)
50+
output := captureOutput(func() {
51+
DoFile(l, "fixtures/read_number.lua")
52+
})
53+
54+
expected := "12345"
55+
if strings.Trim(output, "\n") != expected {
56+
t.Errorf("Expecting:\n%s\nbut received:\n%s\n", expected, output)
57+
}
58+
}
59+
60+
func TestReadBytes(t *testing.T) {
61+
l := NewState()
62+
OpenLibraries(l)
63+
output := captureOutput(func() {
64+
DoFile(l, "fixtures/read_bytes.lua")
65+
})
66+
67+
expected := "A banana contains 75"
68+
if strings.Trim(output, "\n") != expected {
69+
t.Errorf("Expecting:\n%s\nbut received:\n%s\n", expected, output)
70+
}
71+
}
72+
73+
func captureOutput(f func()) string {
74+
rescueStdout := os.Stdout
75+
r, w, _ := os.Pipe()
76+
os.Stdout = w
77+
78+
f()
79+
80+
w.Close()
81+
out, _ := ioutil.ReadAll(r)
82+
fmt.Println(string(out))
83+
os.Stdout = rescueStdout
84+
return string(out)
85+
}

0 commit comments

Comments
 (0)