τau / bufio /

bufio.tau

source
/Users/niconex/Documents/tau/stdlib/bufio/bufio.tau
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}