1# bufio - buffered reading and writing.2#3# A reader here is what io calls a reader, anything with a Read(n): files,4# connections, buffers. Reading a line at a time straight from a file would5# mean one system call per byte, which is what this module is for.67io = import("io")89defaultSize = 40961011# NewReader wraps r so that it can be read a line or a byte at a time.12NewReader = fn(r, size) {13 if !io.IsReader(r) {14 return error("bufio: NewReader wants a reader, got {type(r)}")15 }16 if size == null || size < 1 {17 size = defaultSize18 }1920 b = new()21 b.buf = bytes(0)22 b.eof = false2324 # fill reads one more chunk from the underlying reader, and reports25 # whether anything came in.26 b.fill = fn() {27 if b.eof {28 return false29 }3031 if failed(chunk = r.Read(size)) {32 b.err = chunk33 b.eof = true34 return false35 }36 if len(chunk) == 0 {37 b.eof = true38 return false39 }4041 b.buf = b.buf + chunk42 return true43 }4445 # Read returns up to n bytes, from the buffer first.46 b.Read = fn(n) {47 if n == null {48 n = size49 }50 for len(b.buf) < n && b.fill() {51 }5253 if n > len(b.buf) {54 n = len(b.buf)55 }56 out = slice(b.buf, 0, n)57 b.buf = slice(b.buf, n, len(b.buf))58 return out59 }6061 # ReadByte returns the next byte as an integer, or null at end of input.62 b.ReadByte = fn() {63 if len(b.buf) == 0 && !b.fill() {64 return null65 }6667 out = b.buf[0]68 b.buf = slice(b.buf, 1, len(b.buf))69 return out70 }7172 # ReadLine returns the next line without its newline, or null when there73 # is nothing left. A last line without a newline is still a line.74 b.ReadLine = fn() {75 for {76 i = 077 for i < len(b.buf) {78 if b.buf[i] == 10 {79 line = slice(b.buf, 0, i)80 b.buf = slice(b.buf, i + 1, len(b.buf))81 return string(trimCR(line))82 }83 ++i84 }8586 if !b.fill() {87 if len(b.buf) == 0 {88 return null89 }90 line = b.buf91 b.buf = bytes(0)92 return string(trimCR(line))93 }94 }95 }9697 # ReadAll returns everything left.98 b.ReadAll = fn() {99 for b.fill() {100 }101 out = b.buf102 b.buf = bytes(0)103 return out104 }105106 return b107}108109# trimCR drops the carriage return a Windows line ends with.110trimCR = fn(line) {111 if len(line) > 0 && line[len(line) - 1] == 13 {112 return slice(line, 0, len(line) - 1)113 }114 return line115}116117# NewScanner returns something to walk the lines of r with:118#119# s = bufio.NewScanner(f)120# for s.Scan() {121# println(s.Text())122# }123NewScanner = fn(r) {124 if failed(rd = NewReader(r, null)) {125 return rd126 }127128 s = new()129 s.text = ""130131 # Scan reads the next line and reports whether there was one.132 s.Scan = fn() {133 line = rd.ReadLine()134 if line == null {135 return false136 }137 s.text = line138 return true139 }140141 s.Text = fn() { s.text }142 s.Bytes = fn() { bytes(s.text) }143 s.Err = fn() { rd.err }144145 return s146}147148# NewWriter wraps w so that small writes are put together into big ones.149# Nothing reaches w until the buffer is full or Flush is called.150NewWriter = fn(w, size) {151 if !io.IsWriter(w) {152 return error("bufio: NewWriter wants a writer, got {type(w)}")153 }154 if size == null || size < 1 {155 size = defaultSize156 }157158 b = new()159 b.buf = bytes(0)160161 b.Flush = fn() {162 if len(b.buf) == 0 {163 return 0164 }165166 if failed(n = w.Write(b.buf)) {167 return n168 }169 b.buf = bytes(0)170 return n171 }172173 b.Write = fn(data) {174 if type(data) != "bytes" {175 if failed(data = bytes(string(data))) {176 return data177 }178 }179180 b.buf = b.buf + data181 if len(b.buf) >= size {182 if failed(err = b.Flush()) {183 return err184 }185 }186 return len(data)187 }188189 b.WriteString = fn(s) { b.Write(s) }190 b.WriteLine = fn(s) { b.Write(s + "\n") }191192 return b193}