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();
+ }
+}