File: howmkara

package info (click to toggle)
howm 1.5.6-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,340 kB
  • sloc: lisp: 8,752; sh: 3,558; ruby: 996; makefile: 98; python: 47
file content (360 lines) | stat: -rwxr-xr-x 9,118 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
#!/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 <<EOU
#{name}: howm  HTML 
Фʸ򥨥
ɤ󥯤Ѵ
إåȥեåĤ
()
  #{name} ~/howm/ ~/converted/
  ls ~/howm/*/*/*7-*.txt | #{name} -list ~/converted/
  grep -rl 'ۤ' ~/howm/ | #{name} -list ~/converted/
(ץ)
  -list                      եΥꥹȤɸϤɤ
  -exclude='^[.]|CVS'        оݳΥեɽǻ
  -home='index.html'         HomeפΥ
  -silent ޤ -s          Ľɽ򤷤ʤ
  -help ޤ -h            Υåɽ
  (-debug                    ǥХåѽ)
EOU
end

argv_len = $list ? 1 : 2
if ($help || $h || ARGV.length != argv_len)
  usage
  exit 0
end

#############################################################

$exclude ||= "^[.\#]|CVS|~$"
$silent ||= $s
$summary_length ||= 70
$come_from ||= "<<< *(.+)$"
$come_from_pos ||= 1

#############################################################

def notice(str)
  STDERR.print str if !$silent
end

def ls_R(dir)
  a = Array::new
  Dir::open(dir){|d| d.each{|f| a.push f}}  # map doesn't work??
  b = Array::new
  a.each{|f|
    next if f =~ /#$exclude/
    path = File::expand_path f, dir
    b.push f if FileTest::file? path
    b += ls_R(path).map{|g| "#{f}/#{g}"} if FileTest::directory? path
  }
  return b
end

# FixMe :-(
def mkdir_p(path)
  parent = File::dirname path
  return true if parent == path  # root dir
  mkdir_p parent
  if !FileTest::exist? path
    Dir::mkdir path
  end
end

# FixMe :-(
def split_base(file_list)
  fs = file_list.map{|f| File::expand_path f}
  ds = fs.map{|f| File::dirname f}
  common = ds[0] || ''
  ds.each{|d|
    while common != d
      if common.length <= d.length
        d = File::dirname d
      else
        common = File::dirname common
      end
    end
  }
  rs = fs.map{|f| f[(common.length + 1)..-1]}  # +1 for '/'
  return [common, rs]
end

class HashList < Hash
  def cons(key, val)
    self[key] ||= Array::new
    self[key].push val
  end
end

# class Array
#   def flatten
#     ret = []
#     self.each{|x| ret += x}
#     ret
#   end
# end

class String
  def offsets(pattern)
    a = Array::new
    pos = 0
    # necessary for use of last_match. sigh...
    pattern = Regexp::new(Regexp::quote(pattern)) if pattern.is_a? String
    while (i = index pattern, pos)
      a.push Regexp.last_match.offset(0)
      pos = i + 1
    end
    return a
  end
end

module Bundle
  def expand_readlines(f)
    open(File::expand_path(f, base_dir), 'r'){|io| io.readlines.join}
#     open(File::expand_path(f, base_dir), 'r'){|io| io.read}  # for ruby-1.7?
  end
  def first_line(f)
    open(File::expand_path(f, base_dir), 'r'){|io| io.gets.chop}
  end
  def link_tag(f)  # Clean me. ٤Ƥ֤ΤϤä.
    fline = first_line f
    [:link, f + '.b', f + ': ' + fline[0, $summary_length]]
  end
end

#############################################################

class Formatter
  attr_accessor :home
  def initialize(home = nil)
    @home = home
  end
  def newpage
    @result = ''
  end
  def put(*com)
    com.each{|c| put_one c}
  end
  def put_one(command)
    type = command.shift
    case type
    when :pre
      items = command.shift
      @result += "<pre>\n"
      put *items
      @result += "</pre>\n"
    when :as_is
      @result += CGI::escapeHTML(command.shift)
    when :link
      link, str = command
      url = link.is_a?(String) ? link + '.html' : link[1]
      @result += %!<a href="#{url}">#{CGI::escapeHTML str}</a>!
    when :list
      items = command.shift
      @result += "<ol>\n"
      items.each{|i| @result += ' <li>'; put_one i; @result += "\n"}
      @result += "</ol>\n"
    end
  end
  def wrapped_result(title)
    etitle = CGI::escapeHTML title
    <<_EOS_
<html>
<head><title>#{etitle}</title></head>
<body>
<h1>#{etitle}</h1>
<hr>
#{@result}
<hr>
<a href="#{@home}">Home</a>
<a href="book.h.html">Files</a>
<a href="index.h.html">Keywords</a>
</body>
</html>
_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