DFortune

Unix fortune-cookie parser written in D
git clone git://xatko.vsos.ethz.ch/DFortune.git
Log | Files | Refs

commit 2f581192e19d5ccb453d7defe3b41c00b678a372
Author: Dominik Schmidt <das1993@hotmail.com>
Date:   Sat, 18 Jul 2015 20:55:15 +0200

Initial commit & implementation

Diffstat:
dfortune.d | 173+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 173 insertions(+), 0 deletions(-)

diff --git a/dfortune.d b/dfortune.d @@ -0,0 +1,173 @@ +module dfortune; +import std.stdio; +import std.conv; +import std.bitmanip; +import std.encoding; +import std.range; +import std.random; +import core.exception; + +private auto chooseRandom(T)(T r) if( hasLength!(T) && isRandomAccessRange!(T) ){ + return r[uniform(0,r.length)]; +} + +class Fortune : RandomAccessFinite!(string){ + struct Header{ + uint version_; + uint numstr; + uint longlen; + uint shortlen; + uint flags; + char delim; + @trusted void read(File f){ + ubyte off[getOffset()]; + auto red=f.rawRead(off); + version_=bigEndianToNative!(uint,uint.sizeof)(red[0*uint.sizeof..1*uint.sizeof]); + numstr=bigEndianToNative!(uint,uint.sizeof)(red[1*uint.sizeof..2*uint.sizeof]); + longlen=bigEndianToNative!(uint,uint.sizeof)(red[2*uint.sizeof..3*uint.sizeof]); + shortlen=bigEndianToNative!(uint,uint.sizeof)(red[3*uint.sizeof..4*uint.sizeof]); + flags=bigEndianToNative!(uint,uint.sizeof)(red[4*uint.sizeof..5*uint.sizeof]); + delim=red[getOffset()-char.sizeof]; + } + @safe static size_t getOffset(){ + return 5*uint.sizeof+char.sizeof; + } + } + Header header; + string basename; + File table,content; + private EncodingScheme src; + private EncodingScheme dst; + + uint pos,end; + + @trusted this(string file){ + basename=file; + src=EncodingScheme.create("ISO-8859-1"); + dst=EncodingScheme.create(encodingName!(char)); + initialize(); + } + + @safe public void initialize(){ + open(); + table.seek(0); + header.read(table); + end=header.numstr-1; + } + + @safe public void open(){ + table.open(basename~".dat","r"); + content.open(basename,"r"); + } + + @trusted public uint getOffset(uint i){ + if(i>header.numstr){ + throw new RangeError("Range violation"); + } + table.seek(Header.getOffset()+(i+1)*4-1); + ubyte b[uint.sizeof]; + table.rawRead(b); + return bigEndianToNative!(uint,uint.sizeof)(b); + } + + @trusted public string readFortune(uint i){ + uint pos=getOffset(i); + uint end=getOffset(i+1)-3; //-3 to exclude \n%\n + content.seek(pos); + ubyte buf[]; + buf.length=end-pos; + content.rawRead(buf); + char str[]; + const(ubyte)[] derp=buf; + + while(derp.length>0){ + ubyte bufbuf[4]; + ubyte written; + written=cast(ubyte)dst.encode(src.safeDecode(derp),bufbuf); + str~=bufbuf[0..written]; + } + return cast(string)str; + } + + @safe public void close(){ + table.close(); + content.close(); + } + + @safe private Fortune clone(){ + Fortune c=new Fortune(this.basename); + + c.header=header; + c.table=table; + c.content=content; + c.src=src; + c.dst=dst; + c.pos=pos; + c.end=end; + return c; + } + @safe @property size_t length(){ + return header.numstr-pos; + } + @safe Fortune opSlice(size_t a, size_t b){ + Fortune c=clone(); + c.pos=cast(uint)a; + c.end=cast(uint)b; + return c; + } + @safe @property string back(){ + return readFortune(end); + } + @safe string moveBack(){ + return back; + } + @safe void popBack(){ + end--; + } + @trusted int opApply(int delegate(string)f){ + int ret; + while(!empty()){ + ret=f(front()); + popFront(); + if(ret){ + break; + } + } + return ret; + } + @safe string moveFront(){ + return readFortune(pos); + } + @safe @property bool empty(){ + return (pos>end); + } + @safe @property string front(){ + return moveFront(); + } + @safe void popFront(){ + pos++; + } + @trusted int opApply(int delegate(size_t,string)f){ + int ret; + size_t cnt=0; + while(!empty()){ + ret=f(cnt++, front()); + popFront(); + if(ret){ + break; + } + } + return ret; + } + @safe string moveAt(size_t i){ + pos=cast(uint)i; + return readFortune(pos); + } + @safe string opIndex(size_t i){ + return readFortune(cast(uint)i); + } + + @safe @property Fortune save(){ + return clone(); + } +}