#!io "Content-Type: text/plain\n\n" print Object p := method( self println self ) /* pos : 引数の位置 name : 代入されるスロットのキー (勝手に初期化) default : デフォルトの値 */ Object opt := method(pos, name, default, if (sender doString("thisMessage argAt(" .. pos .. ")")) then ( sender doString(name .. " := sender doMessage(thisMessage argAt(" .. pos .. "))") ) else ( sender setSlot(name, default) ) ) Directory glob := method( ret := List clone self items foreach(i, v, if(v name endsWithSeq("/."), continue) if(v name endsWithSeq("/.."), continue) if(v proto == Directory) then ( ret appendSeq(v glob) ) else ( ret append(v) ) ) ret ) CGI := Object clone do ( params := Nil path_info := Nil request_method := Nil query_string := Nil init := method( request_method = System getenv("REQUEST_METHOD") if (request_method == "GET") then ( self params = parse(System getenv("QUERY_STRING")) ) elseif (request_method == "HEAD") then ( self params = parse(System getenv("QUERY_STRING")) ) elseif (request_method == "POST") then ( self params = parse(File standardInput asString) ) else ( self params = Map clone ) self path_info = System getenv("PATH_INFO") self query_string = System getenv("QUERY_STRING") ) parse := method(q, params := Map clone q split(";", "&") foreach(i, pair, pair = pair split("=") key := pair first pair removeAt(0) value := self decodeUrlParam(String join(pair)) if(params hasKey(key)) then ( params at(key) push(value) ) else ( params atPut(key, List clone push(value)) ) ) params ) sanitize := method(str, str replaceSeq("&", "&") replaceSeq("<", "<") replaceSeq(">", ">") replaceSeq("\"", """) ) urlCodes := Map clone setup := method( for (i, 0, 255, code := i asString toBase(16) asUppercase if (code size == 1, code = "0" .. code) urlCodes atPut(i asCharacter, "%" .. code) ) ) setup urlPlains := Map clone do( atPut(" ", "+") atPut("*", "*") atPut("-", "-") atPut(".", ".") for (i, 48, 57, atPut(i asCharacter, i asCharacter)) for (i, 65, 90, atPut(i asCharacter, i asCharacter)) atPut("_", "_") for (i, 97, 122, atPut(i asCharacter, i asCharacter)) ) encodeUrlParam := method(sIn, sOut := Sequence clone sIn foreach(i, v, c := v asCharacter p := urlPlains at(c) sOut appendSeq(if(p, p, urlCodes at(c))) ) return sOut asString ) decodeUrlParam := method(s, urlCodes foreach(k, v, s = s replaceSeq(v, k)) return s ) ) /* Main */ Tropio := Object clone do ( dir := Nil setPath := method(dir, self dir = dir self ) convertToHTML := method(str, str = CGI sanitize (str) ret := "

" .. str replaceSeq("\n", "

\n

") .. "

" ret Sequence clone atInsertSeq(0, ret) replaceSeq("

", "") ) showEdit := method( opt(0, "id", self create) file := self read(id) body := File setPath("edit.xml") asSeq body replaceSeq("$edit", file at("body")) self showHTML("Edit" .. file at("title"), file at("title") .. "\n" .. CGI sanitize(body)) ) showRead := method( opt(0, "id", self getRandomId) file := self read(id) self showHTML(file at("title"), self convertToHTML(file at("body"))) ) showHTML := method(title, body, ret := File setPath("skin.xml") asSeq ret replaceSeq("$title", title) replaceSeq("$body", body) "Content-Type: text/html\n\n" print ret print ) read := method( opt(0, "id", self getRandomId) title := Sequence clone body := Sequence clone file := File clone setPath(dir .. "/" .. id .. ".txt") openForReading l := Nil file size while (l = file readLine, if (title == "") then ( title = l ) else ( body = body .. l .. "\n" ) ) file close body = Sequence clone atInsertSeq(0, body) Map clone do ( atPut("title", title) atPut("body", body) ) ) create := method( id := Date asNumber file := Nil while (1, file = File clone setPath(dir .. "/" .. id .. ".txt") if (file exists) then ( break ) else ( id += 1 ) ) file open close file := file path fileName file = file slice(if (file reverseFindSeq("/"), file reverseFindSeq("/") + 1, 0)) ) edit := method(id, content, file = File clone setPath(dir .. "/" .. id .. ".txt") open file write(content) file close ) getRandomId := method( files := Directory clone setPath(self dir) glob file := files at(Random value(files size)) path fileName file = file slice(if (file reverseFindSeq("/"), file reverseFindSeq("/") + 1, 0)) ) ) tropio := Tropio clone setPath("data") cgi := CGI clone cgi path_info = "/init" mode := cgi params at("mode") if (cgi path_info) then ( id := cgi path_info slice(1) if (mode == "edit") then ( "edit" p tropio showEdit(id) ) elseif (mode == "create") then ( tropio showEdit ) else ( "read" p tropio showRead(id) ) ) else ( if (mode == "create") then ( tropio showEdit ) else ( id := tropio getRandomId "HTTP/1.x 303 Found\n" print ("Location: /temp/tropio/tropio.io/" .. id .. "\n") print "Content-Type: text/html\n\n" print ) )