ref: b643d83516f55c8628759aa654669b6eeb4f18ca
author: Ori Bernstein <[email protected]>
date: Tue Aug 27 07:21:11 EDT 2013
Initial commit for libbio
--- /dev/null
+++ b/Makefile
@@ -1,0 +1,6 @@
+MYRLIB=bio
+MYRSRC= \
+ bio.myr
+
+include config.mk
+include mk/myr.mk
--- /dev/null
+++ b/bio.myr
@@ -1,0 +1,370 @@
+use std
+
+pkg bio =
+ type mode = int
+ const Biord : mode = 1
+ const Biowr : mode = 2
+ const Biorw : mode = 1 | 2
+
+ type biofile = struct
+ /* backing fd */
+ fd : std.fd
+ mode : mode
+
+ /* read buffer */
+ rbuf : byte[:]
+ rstart : std.size
+ rend : std.size
+
+ /* write buffer */
+ wbuf : byte[:]
+ wend : std.size
+ ;;
+
+ /* creation */
+ const mkbiofile : (fd : std.fd, mode : mode -> biofile#)
+ const open : (path : byte[:], mode : mode -> biofile#)
+ const create : (path : byte[:], mode : mode, perm : int -> biofile#)
+ const close : (f : biofile# -> bool)
+
+ /* basic i/o. Returns sub-buffer when applicable. */
+ const write : (f : biofile#, src : byte[:] -> std.size)
+ const read : (f : biofile#, dst : byte[:] -> byte[:])
+ const flush : (f : biofile# -> bool)
+
+ /* single unit operations */
+ const putb : (f : biofile#, b : byte -> std.size)
+ const putc : (f : biofile#, c : char -> std.size)
+ const getb : (f : biofile# -> byte)
+ const getc : (f : biofile# -> char)
+
+ /* typed binary reads */
+ generic getbe : (f : biofile# -> @a::(tctest,tcnum,tcint))
+ generic getle : (f : biofile# -> @a::(tctest,tcnum,tcint))
+
+ /* peeking */
+ const peekb : (f : biofile# -> byte)
+ const peekc : (f : biofile# -> char)
+
+ /* delimited read; returns freshly allocated buffer. */
+ const readln : (f : biofile# -> byte[:])
+ const readto : (f : biofile#, delim : char -> byte[:])
+ const readtob : (f : biofile#, delim : byte -> byte[:])
+
+ /* formatted i/o */
+ const print : (f : biofile#, fmt : byte[:], args : ... -> std.size)
+;;
+
+const Bufsz = 16*1024 /* 16k */
+const Small = 512
+
+const mkbiofile = {fd, mode
+ var f
+
+ f = std.alloc()
+
+ f.fd = fd
+ f.mode = mode
+ if mode & Biord
+ f.rbuf = std.slalloc(Bufsz)
+ f.rstart = 0
+ f.rend = 0
+ ;;
+ if mode & Biowr
+ f.wbuf = std.slalloc(Bufsz)
+ f.wend = 0
+ ;;
+ -> f
+}
+
+const open = {path, mode
+ -> create(path, mode, 0o777)
+}
+
+const create = {path, mode, perm
+ var openmode
+
+ if mode == Biord
+ openmode = std.Ordonly
+ elif mode == Biowr
+ openmode = std.Owronly
+ elif mode == Biorw
+ openmode = std.Ordwr
+ ;;
+ openmode |= std.Ocreat
+
+ -> mkbiofile(std.open(path, openmode, perm castto(int64)), mode)
+}
+
+const close = {f
+ flush(f)
+ if f.mode & Biord
+ std.slfree(f.rbuf)
+ ;;
+
+ if f.mode & Biowr
+ std.slfree(f.wbuf)
+ ;;
+ -> std.close(f.fd) == 0
+}
+
+const write = {f, src
+ std.assert(f.mode & Biowr != 0, "File is not in write mode")
+ /*
+ Tack small writes onto the buffer end. Big ones
+ flush the buffer and then go right to kernel.
+ */
+ if src.len < (f.wbuf.len - f.wend)
+ std.slcp(f.wbuf[f.wend:f.wend+src.len], src)
+ f.wend += src.len
+ -> src.len
+ else
+ flush(f)
+ -> writebuf(f.fd, src)
+ ;;
+}
+
+const read = {f, dst
+ var n
+ var d
+ var count
+
+ std.assert(f.mode & Biord != 0, "File is not in read mode")
+ /*
+ * small reads should try to fill, so we don't have to make a
+ * syscall for every read
+ */
+ if dst.len < Small
+ fill(f, f.rbuf.len - f.rend)
+ ;;
+ /* Read as much as we can from the buffer */
+ count = std.min(dst.len, f.rend - f.rstart)
+ std.slcp(dst[:count], f.rbuf[f.rstart:f.rstart+count])
+ f.rstart += count
+
+ /* if we drained the buffer, reset it */
+ if f.rstart == f.rend
+ f.rstart = 0
+ f.rend = 0
+ ;;
+
+ /* Read the rest directly from the fd */
+ d = dst[count:]
+ while dst.len > 0
+ n = std.read(f.fd, d)
+ if n <= 0
+ goto readdone
+ ;;
+ count += n
+ d = d[n:]
+ ;;
+:readdone
+ -> dst[:count]
+}
+
+const flush = {f
+ var ret
+
+ ret = (writebuf(f.fd, f.wbuf[:f.wend]) == f.wend)
+ f.wend = 0
+ -> ret
+}
+
+const putb = {f, b
+ ensurewrite(f, 1)
+ f.wbuf[f.wend++] = b
+ -> 1
+}
+
+const putc = {f, c
+ var sz
+
+ sz = std.charlen(c)
+ ensurewrite(f, sz)
+ std.encode(f.wbuf[f.wend:], c)
+ f.wend += sz
+ -> sz
+}
+
+const getb = {f
+ if ensureread(f, 1)
+ -> f.rbuf[f.rstart++]
+ ;;
+ -> -1
+}
+
+const getc = {f
+ var c
+
+ if ensureread(f, std.Maxcharlen)
+ c = std.decode(f.rbuf)
+ f.rstart += std.charlen(c)
+ -> c
+ ;;
+ -> -1
+}
+
+generic getbe = {f -> @a::(tcnum,tcint,tctest)
+ var ret
+ var i
+
+ ret = 0
+ for i = 0; i < sizeof(@a); i++
+ ret <<= 8
+ ret |= (getb(f) castto(@a::(tcnum,tcint,tctest)))
+ ;;
+ -> ret
+}
+
+generic getle = {f -> @a::(tcnum,tcint,tctest)
+ var ret
+ var i
+
+ ret = 0
+ for i = 0; i < sizeof(@a); i++
+ ret = ret | ((getb(f) << 8*i) castto(@a::(tcnum,tcint,tctest)))
+ ;;
+ -> ret
+}
+
+
+const peekb = {f
+ ensureread(f, 1)
+ -> f.rbuf[f.rstart]
+}
+
+const peekc = {f
+ ensureread(f, std.Maxcharlen)
+ -> std.decode(f.rbuf)
+}
+
+const readto = {f, c
+ var buf : byte[4]
+ var srch
+ var ret : byte[:]
+ var i
+
+ srch = buf[:std.encode(buf[:], c)]
+ if srch.len == 0
+ -> [][:]
+ ;;
+
+ ret = [][:]
+ while true
+ if !ensureread(f, srch.len)
+ -> readappend(f, ret, f.rend - f.rstart)
+ ;;
+ for i = f.rstart; i < f.rend; i++
+ if f.rbuf[i] == srch[0] && std.sleq(f.rbuf[i + 1:i + srch.len - 1], srch[1:])
+ -> readappend(f, ret, i - f.rstart)
+ ;;
+ ;;
+ ret = readappend(f, ret, i - f.rstart)
+ ;;
+ -> ret
+}
+
+const readtob = {f, b
+ var ret
+ var i
+
+ ret = [][:]
+ while true
+ if !ensureread(f, 1)
+ -> readappend(f, ret, f.rend - f.rstart)
+ ;;
+ for i = f.rstart; i < f.rend; i++
+ if f.rbuf[i] == b
+ -> readappend(f, ret, f.rend - i)
+ ;;
+ ;;
+ ret = readappend(f, ret, i - f.rstart)
+ ;;
+}
+
+const readln = {f
+ -> readto(f, '\n')
+}
+
+/*
+appends n bytes from the read buffer onto the heap-allocated slice
+provided
+*/
+const readappend = {f, buf, n
+ var ret
+
+ std.assert(f.rstart + n < f.rend, "Reading too much from buffer")
+ ret = std.sljoin(ret, f.rbuf[f.rstart:f.rstart + n])
+ f.rstart += n
+ -> ret
+}
+
+/* makes sure we can bufferedly write at least n bytes */
+const ensurewrite = {f, n
+ std.assert(n < f.wbuf.len, "ensured write capacity > buffer size")
+ if n > f.wbuf.len - f.wend
+ flush(f)
+ ;;
+}
+
+/*
+makes sure we have at least n bytes buffered. returns true if we succeed
+in buffering n bytes, false if we fail.
+*/
+const ensureread = {f, n
+ var held
+ var cap
+
+ std.assert(n < f.rbuf.len, "ensured read capacity > buffer size")
+ held = f.rend - f.rstart
+ if n > held
+ /* if we need to shift the slice down to the start, do it */
+ cap = f.rbuf.len - f.rend
+ if n > (cap + held)
+ std.slcp(f.rbuf[:cap], f.rbuf[f.rstart:f.rend])
+ ;;
+ -> fill(f, n) > n
+ else
+ -> true
+ ;;
+}
+
+/* blats a buffer to an fd */
+const writebuf = {fd, src
+ var n
+ var count
+
+ count = 0
+ while src.len
+ n = std.write(fd, src)
+ if n <= 0
+ goto writedone
+ ;;
+ count += n
+ src = src[n:]
+ ;;
+:writedone
+ -> count
+}
+
+/*
+Reads as many bytes as possible from the file into
+the read buffer.
+*/
+const fill = {f, n
+ var n
+ var count
+
+ count = 0
+ while count < n
+ n = std.read(f.fd, f.rbuf[f.rend:])
+ if n <= 0
+ goto filldone
+ ;;
+ count += n
+ f.rend += n
+ ;;
+:filldone
+ -> count
+}
+
--- /dev/null
+++ b/configure
@@ -1,0 +1,52 @@
+#!/bin/sh
+
+prefix="/usr/local"
+
+for i in `seq 300`; do
+ echo "Lots of output to emulate automake... ok"
+ echo "Testing for things you'll never use... fail"
+ echo "Satisfying the fortran77 lobby... ok"
+ echo "Burning CPU time checking for the bloody obvious... ok"
+done
+echo "Automake emulated successfully"
+
+INST_ROOT='/usr/local'
+
+for arg in $*; do
+ shift 1
+ case $arg in
+ "--prefix" | "-p")
+ prefix=shift $*
+ ;;
+ --prefix=*)
+ prefix=`echo $arg | sed 's/^--prefix=//g'`
+ ;;
+ "--help" | "-h")
+ echo "Usage:"
+ echo " --prefix | -p: The prefix to install to"
+ break;
+ ;;
+ *) echo "Unrecognized argument $arg";;
+ esac
+done
+
+OS=`uname`
+
+echo export INST_ROOT=$prefix > config.mk
+case $OS in
+ *Linux*)
+ echo 'export SYS=linux' >> config.mk
+ ;;
+ *Darwin*)
+ echo 'export SYS=osx' >> config.mk
+ ;;
+ *)
+ echo 'Unknown architecture.'
+ ;;
+esac
+
+cat << EOF
+ Building with:
+ prefix=$prefix
+EOF
+
--- /dev/null
+++ b/mk/myr.mk
@@ -1,0 +1,42 @@
+ifneq ($(MYRLIB),)
+ _LIBNAME=lib$(MYRLIB).a
+endif
+
+all: $(_LIBNAME) $(MYRBIN)
+
+$(_LIBNAME): $(MYRSRC) $(ASMSRC)
+ myrbuild -l $(MYRLIB) $^
+
+$(MYRBIN): $(MYRSRC) $(ASMSRC)
+ myrbuild -b $(MYRBIN) $^
+
+OBJ=$(MYRSRC:.myr=.o) $(ASMSRC:.s=.o)
+JUNKASM=$(MYRSRC:.myr=.s)
+USE=$(MYRSRC:.myr=.use) $(MYRLIB)
+.PHONY: clean
+clean:
+ rm -f $(OBJ)
+ rm -f $(USE)
+ rm -f $(JUNKASM)
+ rm -f lib$(MYRLIB).a
+
+install: install-bin install-lib
+
+install-bin: $(MYRBIN)
+ @if [ ! -z "$(MYRBIN)" ]; then \
+ echo install $(MYRBIN) $(INST_ROOT)/bin; \
+ mkdir -p $(INST_ROOT)/bin; \
+ install $(MYRBIN) $(INST_ROOT)/bin; \
+ fi
+
+install-lib: $(_LIBNAME)
+ @if [ ! -z "$(_LIBNAME)" ]; then \
+ echo install -m 644 $(_LIBNAME) $(INST_ROOT)/lib/myr; \
+ echo install -m 644 $(MYRLIB) $(INST_ROOT)/lib/myr; \
+ mkdir -p $(INST_ROOT)/lib/myr; \
+ install -m 644 $(_LIBNAME) $(INST_ROOT)/lib/myr; \
+ install -m 644 $(MYRLIB) $(INST_ROOT)/lib/myr; \
+ fi
+
+config.mk:
+ ./configure