// Diki 0.07 ( http://www.kmonos.net/alang/dee/diki/ ) // // presnted by k.inaba under NYSL. // import std.string; import std.conv : toInt; import std.regexp : RegExp, sub; //========================================================================= // Main //========================================================================= void main() { auto w = new WikiPage( env("PATH_INFO"), // ページ名 new Data("diki_db"), // データ保存するディレクトリ new View("http://"~env("SERVER_NAME")~env("SCRIPT_NAME")) // CGIスクリプトのURI ); if( env("REQUEST_METHOD") == "POST" ) { auto e = readStdIn(env("CONTENT_LENGTH").toInt())[2..$].uri_decode(); if( e.length > 0 ) w.write(e); // POSTデータがあればwrite else w.remove(); // POSTデータがなければremove } else if( env("QUERY_STRING") == "" ) w.read(); // QUERYが空ならread else w.edit(); // なんかあればedit } //========================================================================= // General Utilities //========================================================================= /// 環境変数 import std.c.stdlib; string env( string var ) { char* e = getenv( var.toStringz() ); return e ? toString(e) : ""; } /// URI エンコード/デコード import std.uri; string uri_encode( string s ) { return s.encode().replace("+","%2B").replace(" ","+" ); } string uri_decode( string s ) { return s.replace("+"," ").replace("%2B","+").decodeComponent(); } /// HTMLエスケープ string text( string s ) { return s.replace("&","&").replace("<","<").replace(">",">").replace("\"","""); } /// 標準入出力 import std.cstream; void p( string s ) { dout.writeLine(s); } string readStdIn( uint size ) { ubyte[] buf = new ubyte[size]; int x=0, y=1; for( ; x` ); p( `` ); p( `` ); p( ` ` ~(edit ? "Editing :: " : "") ~ text(page) ~ `` ); p( ` ` ); if(edit) p( ` ` ); p( `` ); if(edit) { p( `
` ); p( `` ); p( `
` ); } else render_lines( page, db[page].splitlines(), db ); p( `` ); } void redirect_to( string page ) { p( `Status: ` ~ `303 See Other` ); p( `Location: ` ~ page_uri(page) ); p( `` ); } private: string page_uri(string p) { return self_path ~ uri_encode(p); } void render_lines( string page, string[] lines, Data db ) { // 閉じてないpreタグがあったら閉じるようにラップした一行出力 bool in_pre = false; void p( string s ) { if( in_pre ) {.p(``); in_pre=false;} .p(s); } scope(exit) p(``); // aタグ生成 (url と name はエスケープ済み文字列を渡すこと) string a( string url, string name ) { return `` ~name~ ``; } // メインループ foreach( str; lines ) { bool hr() { if( 0 != str.find("----") ) return false; p( `
` ); return true; } bool heading() { int N = RegExp("[^\\*]").find(str); if( N<1 || 6`~text(str[N..$])~`` ); return true; } bool ls() { if( str.length<3 || str[0..3]!="#ls" ) return false; RegExp r = new RegExp(str[3..$].strip()); p( `` ); return true; } bool pre() { if( !in_pre && str!="" ) { p("
"); in_pre=true; }

				string gen( RegExp r )
				{
					string nam = r.match(1);
					string url = r.match(3) ? r.match(3) : nam;

					if( url.find("http://")==0 || url.find("https://")==0 || url.find("ftp://")==0 )
						return a(url, nam);
					else if( url=="EDIT" )
						return a(page_uri(db.as_pagename(page))~`?e`, nam);
					else if( url=="TURL" )
						return a("http://tinyurl.com/create.php?url="~page_uri(db.as_pagename(page)), nam);
					else
						return a(page_uri(db.as_pagename(url)), nam);
				}
				.p( text(str).sub(`\[\[([^\|]+)(\|(.+))?\]\]`, &gen, `g`) );
					// ToDo : [[]]の中身がescapeされるのがちょっとなあ...
				return true;
			}

			heading() || hr() || ls() || pre();
		}
	}
}