#!/usr/bin/ruby -s # -*- coding: euc-jp -*- # -*- Ruby -*- # Convert ~/howm/ to HTML or other formats. # Only RD format is supported unless you will give me patches. :p ############################################################# require 'cgi' def usage name = File::basename $0 print <#{CGI::escapeHTML str}! when :list items = command.shift @result += "
    \n" items.each{|i| @result += '
  1. '; put_one i; @result += "\n"} @result += "
\n" end end def wrapped_result(title) etitle = CGI::escapeHTML title <<_EOS_ #{etitle}

#{etitle}


#{@result}
Home Files Keywords _EOS_ end def write(title, file, dir) f = File::expand_path(file, dir) + '.html' mkdir_p File::dirname(f) open(f, 'w'){|io| io.puts wrapped_result(title)} end end class Book include Bundle attr_accessor :files, :base_dir def initialize(files, base_dir) @files = files @base_dir = base_dir end def first_page link_tag(@files[0]) end def write(dest_dir, formatter) index = Index::new @files, @base_dir write_each dest_dir, formatter, index write_list dest_dir, formatter index.write dest_dir, formatter end def write_list(dest_dir, formatter) formatter.newpage formatter.put [:list, @files.sort.map{|f| link_tag f # first_line = open(File::expand_path f, @base_dir){|io| io.gets.chop} # [:link, f + '.b', f + ': ' + first_line[0, $summary_length]] }] formatter.write 'Files', 'book.h', dest_dir notice ".\n" end def write_each(dest_dir, formatter, index) @files.each{|f| formatter.newpage formatter.put [:pre, interpret(expand_readlines(f), index, f)] formatter.write first_line(f), f + '.b', dest_dir # formatter.write f, f + '.b', dest_dir notice '.' } notice "\n" end def interpret(src, index, f) hit = search src, index, f cursor = 0 ret = [] while !hit.empty? h = hit.shift b, e, key = h case cursor <=> b when -1 # eat until beginning of this hit, and retry ret.push [:as_is, src[cursor...b]] hit.unshift h cursor = b when 0 # expand this hit s = src[b...e] if key == :url link = [:url, s] elsif key == :decl s =~ /#$come_from/ w = Regexp::last_match[$come_from_pos] link = CGI::escape(CGI::escape(w)) + '.i' else decl = index.decl[key] link = decl.member?(f) ? nil : decl[0] + '.b' end ret.push(link ? [:link, link, s] : [:as_is, s]) cursor = e when 1 # discard this hit end end ret.push [:as_is, src[cursor..-1]] ret end def search(src, index, f) hit = [] index.decl.each_key{|k| offsets = src.offsets k index.used.cons k, f if !offsets.empty? && !index.decl[k].member?(f) hit += offsets.map{|o| o.push k} } hit += src.offsets(%r{http://[-!@#\$%^&*()_+|=:~/?a-zA-Z0-9.,;]*[-!@#\$%^&*()_+|=:~/?a-zA-Z0-9]+}).map{|o| o.push :url} hit += src.offsets($come_from).map{|o| o.push :decl} hit.sort{|h1, h2| earlier_longer h1, h2} end def earlier_longer(h1, h2) [h1[0], - h1[1]] <=> [h2[0], - h2[1]] end end class Index include Bundle attr_accessor :files, :base_dir attr_reader :decl, :used def initialize(files, base_dir) @files = files @base_dir = base_dir @decl = HashList::new @used = HashList::new search_decl end def search_decl @files.each{|f| expand_readlines(f).scan($come_from){|hit| @decl.cons hit[0], f} } end def write(dest_dir, formatter) write_each dest_dir, formatter write_list dest_dir, formatter end def write_list(dest_dir, formatter) formatter.newpage formatter.put [ :list, @decl.keys.sort.map{|key| [:link, CGI::escape(CGI::escape(key)) + '.i', key + " (#{(@used[key]||[]).length})"] } ] formatter.write 'Keywords', 'index.h', dest_dir notice ".\n" end def write_each(dest_dir, formatter) @decl.each_key{|key| f = CGI::escape(key) + '.i' to_decl = @decl[key].map{|g| link_tag g} to_used = (@used[key] || []).map{|g| link_tag g} to_rel = related_keys(key).map{|g| [:link, @decl[g][0] + '.b', g]} # to_decl = @decl[key].map{|g| [:link, g + '.b', g]} # to_used = (@used[key] || []).map{|g| [:link, g + '.b', g]} # to_rel = related_keys(key).map{|g| [:link, @decl[g][0] + '.b', g]} formatter.newpage c = [ [:as_is, "Declared:\n"], [:list, to_decl], [:as_is, "Linked:\n"], [:list, to_used], [:as_is, "Related:\n"], [:list, to_rel], ] formatter.put *c formatter.write key, f, dest_dir notice '.' } notice "\n" end def related_keys(key) sub = included_keys key sub.map{|k| @decl.keys.select{|x| x.include? k and x != key}}.flatten.uniq.sort end def included_keys(key) @decl.keys.select{|k| key.include? k} end end ############################################################# if $list dest_dir = ARGV.shift src_dir, files = split_base(STDIN.readlines.map{|s| s.chomp}) else src_dir, dest_dir = ARGV files = ls_R src_dir end notice "#{files.length} files " b = Book::new files, src_dir i = Index::new files, src_dir notice "(#{i.decl.length} entries)\n" $home ||= b.first_page[1] + '.html' fmt = Formatter::new $home b.write dest_dir, fmt