shithub: mc

Download patch

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