On Thu, Aug 11, 2005 at 02:14:14PM +0400, Denis Ovsienko wrote: > > > > 2. Соотв. цепляться к http мы будем через СGI. > > > Брали бы вы PHP и действительно не изобретали велосипед. > > php не может того что может alterator. Кроме того, в данном > > случае мы сами в состоянии сгенерить тот html который нам > > нужен и php тут совершенно ни чем помочь не может. > При всём уважении к господам проектировщикам после таких > комментариев я вынужден умыть руки, хотя web-морды под Linux > пишу с 1999 года.
Денис, php -- это слишком много ненужных фич (и кода) здесь. Я тоже веб-морды под фрюниксами где-то с тех же лет делал. :) Вон чего пооставалось даже: home:/var/ftp/pub/Linux/utils/web> l | hands -rw-rw-r-- 1 mike mike 61670 Mar 23 1999 boa-0.92q.tar.gz -rw-rw-r-- 1 mike mike 19737 Mar 26 2000 htmsysinfo-1.5.tar.gz -rw-rw-r-- 1 mike mike 98366 Oct 23 1999 thttpd-2.04.tar.gz (там где-то была и сишная cgi-библиотека, но это дело сильно не понравилось) PS 2 inger: во, в аттаче -- мелкая standalone wiki на Ruby. В качестве примера сервера/CGI. -- ---- WBR, Michael Shigorin <[EMAIL PROTECTED]> ------ Linux.Kiev http://www.linux.kiev.ua/
#!/usr/bin/ruby # a tiny Ruby wiki require 'socket' require 'trace' require 'cgi' Host = ARGV[0] Port = ARGV[1].to_i() RecentChangeCount = 20 $art = '<img src="http://www.greencheese.org/penBird.gif" border=0>' # $art = '<img src="icon.gif">' def openServer printf("Opening server on host %s, port %i\n", Host, Port) server = TCPServer.new( Host, Port ) puts "Opened" return server end # TODO minor edits # search -> graph -> don't render half a graph # put the wiki source on a page # hallow SearchMe # case sensitivity despite DOS # clean up the title tag of a clicker - no formatting, easy word-wrap # more recent changes # Search at top # TreeOfLife # don't croak over regex search syntax errors # searches also hit info # X(oh this hurts)ML file format # Don't keep a lock on any file after page paint time # user id in date stamp system # use string squeeze somewhere ;-) # a little more assert_match around here # alt tags inside graphs # put the info in the alt-tag of the title # make RecentChanges a real page, like NerveCenter # tooltip for a RemoteLink should be its complete URL # escape properly inside info edit areas # dunn: # stash pages as html # escape properly inside text edit areas # put the focus into the edit field # wildcards in the searches #### # put the change synopsis into the title tag of a clicker # Split a remote link into Local:remote # let => make text get very big # let [] change text background to orange # ability to expand the target half of a RemoteLink >inside< the redirection url $mimeTypes = { 'jpg' => 'image/jpg', 'gif' => 'image/gif', 'png' => 'image/png', 'html' => 'text/html', 'pdf' => 'application/pdf' } $response = { 200 => "HTTP/1.0 200 Okay\nServer: ws30\nContent-type: %s\n\n", 301 => "HTTP/1.0 301 Moved\nServer: ws30\nContent-type: text/plain\n\nLocation: %s\n\nmoved", 404 => "HTTP/1.0 404 Not Found\nServer: ws30\nContent-type: text/plain\n\n\n%s not found", } LocalLink = '\\b([A-Z][a-z]+){2,}\\b' # the heart of Wikidom... ;-) def writeFile name, guts File.open(name, 'w') do |f| f.write(guts) end end def getRequest stream method = nil uri = nil contentLength = 0 while 1 do line = stream.readline() if line.strip().length() == 0 then break elsif method == nil then method, uri, protocol = line.split(' ') end if /^content-length: /.match(line.downcase()) then contentLength = line.split(': ')[1].strip.to_i() end end warning = '' if method == 'POST' then line = stream.read(contentLength) substance = decodeURL(line) title = uri.slice(1..-1) fileName = wiki(title) timeStampThen = substance['timestamp'] timeStampNow = '0' timeStampNow = File.mtime(fileName).tv_sec.to_s() if File.exist?(fileName) minorEdit = substance['MinorEdit'] if timeStampThen < timeStampNow then warning = 'Someone has changed this page. ' + 'To recover your content, ' + '<li>hit Back' + '<li>copy your text into an editor' + '<li>hit Refresh' + '<li>merge your changes with the page\'s current text' + '<li>hit Save again<hr>' else # TODO replace all this fun with XML! modTime = if File.exist?(fileName) then File.mtime(fileName) else Time.now() - 60*60*24*256 end writeFile(fileName, substance['text']) writeFile(info(title), substance['synopsis']) if minorEdit == 'on' then File.utime( modTime, modTime, fileName) end # toast every page backup that might have an incorrect notion of this page getWikiPageList.each do |page| contents = readFile(page) if contents =~ /\btitle\b/ then html_file = page.slice(0...-5) html_file += '.html' puts "unlinking #{html_file}" File.unlink(html_file) if File.exists? html_file end end end end return uri, warning end def info tag return tag + '.info' end # TODO replace split(\n) with each_line # TODO clone PerlStringTest.exe in Ruby def listDirectory uri return 'directory none of your business' end def headerStuff title, onload = '' return '<head><title>' + title + "</title></head>\n" + '<body text="black" bgcolor="white"' + onload + '>' + '<h1> <a href="/NerveCenter">' + $art + '</a> ' + '<a href="/?search=' + title + '">' + title + '</a></h1>' end def getSynopsisFile(title) synopsis = '' infoFile = info(title) if File.exist?(infoFile) then # TODO merge duplication synopsis = File.open(infoFile).read() end return synopsis end def getSynopsis(title) return ' ' + formatWiki(getSynopsisFile(title)) + ' ' end ['em', 'th', 'tr', 'td'].each do |thing| eval( "def #{thing}(q,spec = '');" + " return '<#{thing} ' + spec + '>' + q + \"</#{thing}>\";" + "end" ) end def createLink urlage, contents = '', leap = '' title = '' contents = urlage if contents == '' if leap == '' then synopsis = getSynopsisFile(contents) if synopsis != '' then title = ' title="' + synopsis + '"' end end return "<a #{leap}href=\"#{urlage}\"#{title}>#{contents}</a>" end def formatFile(title, contents, extra = '') return '<form method="GET" action="/">' + headerStuff(title) + '<table width="85%">' + tr( td( '<table width="100%" cellpadding=6 border=1>' + tr(td(formatWiki(contents) + "\n" + extra + "\n")) + "</table>\n", 'colspan=3' ) ) + tr( td(' <a href="edit=' + title + '">EditPage</a>') + td(getSynopsis(title)) + td( createLink('RegexSearch') + ': <input type="edit" name="search"> ', 'align="right"' ) ) + '</table></form></body>' end def readFile path File.open(path, 'rb') do |f| return f.read() end end def getPage title readStyleSheet() path = wiki(title) html_file = title + '.html' # TODO fix me! if File.exists?(html_file) and File.mtime(html_file).tv_sec >= File.mtime(path).tv_sec and File.size(html_file) > 0 and false then return readFile(html_file) end File.open( path ) do |f| # TODO begin/rescue here extra = '' extra = getNerveCenter() if title == 'NerveCenter' extra = getUnrequitedLinks() if title == 'WikiUnrequitedLinks' contents = formatFile(title, f.read(), extra) writeFile(html_file, contents) return contents end end # ContractiveDelegation aids testage ;-) def getUnrequitedLinks html = '' unLinks = [] # this is brutally slow, but correct & easy to code # TODO - use the HTML backup, as soon as it is healthy getWikiPageList(). each do |page| if page != 'WikiUnrequitedLinks.wiki' then words = getPage(page[0..-6]) # <a href="edit=SnoOpy">?</a> unLinks += words.scan(/\<a href="edit=([^"]+)">\?\<\/a>/) end end unLinks.flatten! unLinks.sort! unLinks.uniq! unLinks.each do |link| if link != 'RecentChanges' then # TODO yank this html += '<a target="_blank" href="/?search=' + link + '">search</a> - ' html += link + createLink('edit=' + link, '?') html += '<br>' end end return html end def wiki title return title + '.wiki' end def editFile title path = wiki(title) guts = '' if File.file?(path) then File.open( path ) do |f| # TODO begin/rescue here guts = f.read() end else guts = sprintf('Describe %s here.', title) end timeStamp = '0' timeStamp = File.mtime(path).tv_sec.to_s() if File.exist?(path) onload = ' onload="document.f.text.focus()"' return headerStuff(title, onload) + '<form name="f" method="POST" action="' + title + '">' + '<textarea name="text" style="width:85%" rows=20 cols=80 wrap="virtual">' + cleanContents(guts) + '</textarea><br>' + "\n" + 'Change Synopsis: <input name="synopsis" type="edit" size=80 value="' + getSynopsisFile(title) + '"> ' + createLink('MinorEdit') + ' <input type="checkbox" name="MinorEdit"> ' + '<input type="hidden" name="timestamp" value = "' + timeStamp + '">' + '<input type="submit" value = "Save">' + '</body>' end def cleanContents guts # TODO merge me with the other HTML filter? return guts.gsub(/&/, '&'). gsub(/</, '<'). gsub(/>/, '>') end def getContent uri, warning puts 'fetching:', uri # TODO add the client addy if uri == '/RecentChanges' then return [ 200, 'text/html', recentChanges() ] else # begin title = uri.slice(1..-1) title = 'FrontPage' if title == '' if uri.slice(1..5) == 'edit=' then return [ 200, 'text/html', editFile(title.slice(5..-1)) ] end if uri.slice(1..8) == '?search=' then token = title.slice(8..-1) sample = CGI::unescape(token) return [ 200, 'text/html', search(sample) ] end path = wiki(title) if File.file?( path ) then return [ 200, 'text/html', warning + getPage( title ) ] else fileName = '.' + uri puts 'filename', fileName.inspect() return [ 200, 'image/png', readFile(fileName) ] if File.file?(fileName) end return [ 404, uri ] end # TODO actually call the sendResponse here? end # def getMime uri # type = $mimeTypes[ uri.split('.')[-1]] # type = 'text/plain' if type == nil # return type # end def sendResponse stream, content $responseType = $response[content[0]] content.push("") response = sprintf($responseType, content[1] ) stream.write( response ) stream.write( content[2] ) stream.write( "\n" ) end $style = [] def readStyleSheet sheet = 'WikiStyleSheet.wiki' $style = [] if File.exists?(sheet) and File.size(sheet) > 0 then # TODO write a function fileIsRelevant contents = readFile(sheet) contents = contents.split("\n") contents.each do |line| if line[0] == '['[0] then begin gsubber = eval(line) gsubber[0] = Regexp.new(/(\<[^>]*>)|(#{gsubber[0].source()})/) $style.push(gsubber) rescue puts $! puts line.inspect() end end end end end def decodeURL post result = {} post.split('&').each do |token| token = CGI::unescape(token) key, value = token.split(/=/, 2) result[key] = value end return result end # TODO deal with <>& inside urlage # TODO pre tags def runGraphViz graphName, graphLines dotName = graphName + '.dot' mapName = graphName + '.map' pngName = graphName + '.png' writeFile(dotName, graphLines) # TODO sample the errors and report them in the returned page (as a graph? ;-) tossErr = '' tossErr = ' 2>/dev/null' if RUBY_PLATFORM =~ /linux/ system ("dot -Tcmap #{dotName} -o #{mapName}" + tossErr) map = readFile(mapName) map = yield(map) if block_given? system ("dot -Tpng #{dotName} -o #{pngName}" + tossErr) mapHtml = '' if map != '' then mapHtml = ' usemap="#' + mapName + '"><map name="' + mapName + '">' + map + '</map' end return "<img src=\"#{pngName}\" border=0#{mapHtml}>" end class WikiFormatter def initialize @depth = @ulOwed = 0 @graphName = '' @graphLines = '' @inGraph = false @inPre = false end def cleanForHTML str standard = [ ['&','&'], ['<','<'], ['>','>'], [/'''(.*?)'''/, '<strong>\\1</strong>' ], [/''(.*?)''/, '<em>\\1</em>' ], [/^----+/, '<hr>'], ] standard.each do |wiki, html| str.gsub!(wiki, html) end # TODO there has to be a smaller but sicker way to do this str = formatLinks(str) $style.each do |wiki, html| str.gsub!(wiki) do |quip| if quip[0] == '<'[0] or quip == '' then quip else html.gsub(/\\1/, $+) end end end return str end def tagListDepth navel got = /^([ ]+)\*(.*)$/.match(navel) pre = got[1] post = got[2] post.strip! nuDepth = pre.length() preStr = '' if nuDepth == @depth then preStr += '</li><li>' elsif nuDepth > @depth then (0...(nuDepth - @depth)).each do preStr += '<ul><li>' @ulOwed += 1 end else preStr = downLevels(@depth - nuDepth) preStr += '<li>' end @depth = nuDepth return "#{preStr}#{cleanForHTML(post)}\n" end GraphCode = '^(digraph|graph)\\s+([a-zA-Z])+' def beginGraph line if [EMAIL PROTECTED] and line =~ /#{GraphCode}\s*{\s*$/ then @graphName = /#{GraphCode}/.match(line)[0] @graphName = @graphName.split(' ')[1] @graphLines += line + "\n" @inGraph = true return true end return false end attr_reader :graphName, :graphLines # TODO hide these again def finishGraph @inGraph = false @graphLines += "}\n" return runGraphViz(@graphName, @graphLines) end def formatLine line nuSource = '' if beginGraph(line) then nil elsif @inGraph then if line =~ /^}/ then nuSource += finishGraph() line = line.slice(1..-1) nuSource += cleanForHTML(line) + "\n" else @graphLines += line + "\n" end else if /^([ ]+)\*/.match(line) then line = tagListDepth(line) else if @ulOwed > 0 then preStr = downLevels(@ulOwed) # line = preStr + cleanForHTML(line) + "\n" line += "\n" nuSource += preStr end if line =~ /^\s/ then if @inPre then line = cleanForHTML(line) else @inPre = true line = '<pre>' + cleanForHTML(line) end line += "\n" elsif @inPre then @inPre = false line = '</pre>' + cleanForHTML(line) else line = cleanForHTML(line) + "\n" end end nuSource += line end return nuSource end def format source initialize() nuSource = '' source.split("\n").each do |line| if (line == "" or line == "\r") and [EMAIL PROTECTED] then nuSource += "<p>\n" else nuSource += formatLine(line) end end if @inPre then nuSource += '</pre>' end nuSource += downLevels(@ulOwed) return nuSource end def downLevels down preStr = '' while down > 0 do preStr += '</li></ul>' @ulOwed -= 1 @depth -= 1 down -= 1 end return preStr end Uri = '[.a-zA-Z0-9\/\-@&?=:_;~+!#$%^*()\[\]{}]+' HypertextProtocols = 'http|https' LinkingProtocols = 'mailto|ftp' # screw gopher: ;-) Protocols = '(' + HypertextProtocols + '|' + LinkingProtocols + ')' RemoteLink = '(?!RemoteLink:)' + LocalLink + ':(' + Uri + ')?' Links = /#{Protocols}:#{Uri}|#{RemoteLink}|#{LocalLink}/ HypertextMatch = /^(#{HypertextProtocols})$/ def outerLink urlage, contents return createLink(urlage, contents, 'target="_blank" ') end def interpretLink name start = name.split(':')[0] if start =~ /^(#{Protocols})$/ then ext = name.split('.')[-1].downcase() if start =~ HypertextMatch and ext =~ /^(png|jpg|jpeg|gif)$/ then return outerLink(name, "<img src=\"#{name}\" border=0>") else if start =~ HypertextMatch then return outerLink(name, name) end return createLink(name, name) end elsif name =~ /^#{RemoteLink}$/ then linkHTML = name plink, uri = splitFirstColon(name) file = wiki(plink) if File.file?(file) then File.open(file) do |f| line = f.readline() line.strip! base, rest = splitFirstColon(line) if base == 'RemoteLink' then urlage = sprintf(rest, uri) urlage += uri if urlage.size() == rest.size() return "<a href=\"#{plink}\">#{plink}</a>:" + "<a target=\"_blank\" href=\"#{urlage}\">#{uri}</a>" else linkHTML = formatWiki(plink).strip() + ':' linkHTML += formatWiki(uri).strip() if uri != nil end end else linkHTML = plink + createLink('edit=' + plink, '?') # TODO OAOO return (linkHTML + ':' + uri) end else if (name == 'RecentChanges' or File.file?(wiki(name))) then return createLink(name, name) else return name + createLink('edit=' + name, '?') end end return linkHTML end def formatLinks source source.gsub!(Links) do |name| interpretLink(name) end # puts source.inspect() return source # ! ;-) end def splitFirstColon str return str.split(':', 2) end end def formatWiki source aFormatter = WikiFormatter.new result = aFormatter.format(source) # puts result.inspect() return result end # method object design pattern... $greenBar = true def listHeader title, predicate, middle = '' $greenBar = true return headerStuff(title) + '<table border="0">' + tr( th(em('Page' ), 'align="center"') + th(em(middle ), 'align="center"') + th(em(predicate), 'align="center"') ) end def foundObject tag, line, middle = '' color = if $greenBar then 'bgcolor="LightCyan"' else '' end $greenBar = !$greenBar return tr( td( '<a href="/' + tag + '">' + tag + "</a> </td>", 'valign="top"' ) + td(middle, 'valign="top"') + td(line, 'valign="top"'), color ) + "\n" end # TODO write a package that makes Ruby restart itself if it detects a source change # TODO write a package that makes Perl restart itself if it detects a source change # TODO write a package that makes Python restart itself if it detects a source change # TODO write a package that makes C++ restart itself if it detects a source change # TODO notice any patterns? def baseName(f) return f.split('.')[0] end def searchFile f, tag, sample File.open(f) do |handle| handle.readlines().each do |line| if line =~ /#{sample}/i then return foundObject(tag, formatWiki(line)) end end end return '' end def getWikiPageList return Dir.glob("*.wiki") end def search sample result = listHeader('Search', 'Citation') matches = 0 # TODO merge with recentChanges ;-) getWikiPageList().sort{ |a,b| a <=> b }. each do |f| # observe this system checks the file contents # first, then the name. This improves the odds we have # something in the citation column # TODO option to grep every line in a page, not just the first hit tag = baseName(f) got = searchFile(f, tag, sample) if got == '' and tag =~ /#{sample}/i then got = foundObject(tag, '') end result += got matches += 1 if got != '' end result += '</table>' if matches == 0 then result += '<p>' + em('no matches for `') + formatWiki(sample).strip() + em('\'...') end # TODO shouldn't have to strip after formatWiki return result + '</body></html>' end def getUniqWikiWords page # this looks horribly inefficient, but we are only working over 20 # files here, and the file system must have them buffered... contents = readFile(page) # TODO merge with LocalLink wikiWords = contents.scan(/ [^:] ( \b (?: [A-Z][a-z]+ ){2,} \b )/x) return wikiWords.flatten.uniq end def populateAltTags map # fix yet another issue with GraphViz return map. gsub(/ alt="[A-Za-z]*" /) do |name| page = name.slice(6...-2) info = getSynopsisFile(page) info = cleanContents(info) sprintf(" alt=\"%s\" ", info) end end def getNerveCenter recentChanges = getRecentChangePages() graph = generateNerveCenter(recentChanges) # writeFile 'NerveCenter.dot', graph return runGraphViz('NerveCenter', graph) do |map| populateAltTags(map) end # execute-around pattern end def generateNerveCenter recentChanges graph = "graph nerveCenter {\n" \ " rankdir = LR;\n" \ " ratio = compress;\n" \ " bgcolor = \"gray85\";\n" \ " node [shape = box, style=filled, fillcolor=white, color=white, height = \"0.1\"];\n" \ " size = \"8,11\";\n" \ # " label = \"Nerve Center\";\n" recentChanges.each do |page| contents = readFile(page) page = page.slice(0...-5) graph += page + " [URL=\"http:" + page + "\"];\n" # TODO merge with LocalLink wikiWords = contents.scan(/((?:[A-Z][a-z]+){2,})/) wikiWords.uniq.each do |words| word = words[0] if word != page and recentChanges.include?(wiki(word)) and ! graph.include?(word + ' -- ' + page) then graph += page + ' -- ' + word + " [dir=" if getUniqWikiWords(wiki(word)).include? page then graph += "both" else graph += "forward" end graph += "];\n" end end end return graph + '}' end def getRecentChangePages() return getWikiPageList().sort{ |a,b| File.mtime(b) <=> File.mtime(a) }. slice(0...RecentChangeCount) end def recentChanges result = listHeader('RecentChanges', 'Time', 'Change Synopsis') lastDay = nil lastMon = nil lastYear = nil getRecentChangePages(). each{ |f| tag = baseName(f) # 9:15 pm Sat 30 Nov 2002 # PST %Z tyme = File.mtime(f) format = '%I:%M <font size=1>%p</font>' if lastDay != tyme.day or lastMon != tyme.mon or lastYear != tyme.year then format += ' %a %d %b %Y' end strTime = tyme.strftime(format) lastDay = tyme.day lastMon = tyme.mon lastYear = tyme.year synopsis = getSynopsis(tag) result += foundObject(tag, strTime, synopsis) # 1 more arg and we're an object } return result + '</table></body></html>' end # TODO pin the encoding to US/EN (or FR/FR) def serve server = openServer() begin while 1 do stream, client = server.accept() uri, warning = getRequest( stream ) sendResponse( stream, getContent( uri, warning ) ) stream.close() end rescue puts $! puts 'shutting down...' end server.close() end # $art = '<img src = "http://babelfish.altavista.com/static/images/babelfish/systran_big_logo.gif" border=0>' # $art = 'yo' serve() if __FILE__ == $0
pgpj0dCFYUlGs.pgp
Description: PGP signature
_______________________________________________ Devel-conf mailing list [email protected] https://lists.altlinux.ru/mailman/listinfo/devel-conf
