root/lang/ruby/ffhist/mork.rb @ 30649

Revision 7194, 4.7 kB (checked in by akio0911, 6 years ago)

lang/ruby/ffhist add

Line 
1#!ruby -Ku
2=begin
3Mork フォーマットパーサ
4
5Mork とかいう Mozilla につかわれているクソフォーマットを
6Ruby でパースする
7
8# mork.rb
9# See modifiers http://coderepos.org/share/log/lang/ruby/misc/mork.rb
10#
11# Based on http://www.jwz.org/hacks/mork.pl
12# Copyright © 2004 Jamie Zawinski <jwz@jwz.org>
13#
14# Permission to use, copy, modify, distribute, and sell this software and its
15# documentation for any purpose is hereby granted without fee, provided that
16# the above copyright notice appear in all copies and that both that
17# copyright notice and this permission notice appear in supporting
18# documentation.  No representations are made about the suitability of this
19# software for any purpose.  It is provided "as is" without express or
20# implied warranty.
21#
22# Created:  3-Mar-2004 by Jamie Zawinski, Anonymous, and Jacob Post.
23=end
24
25require "strscan"
26
27class Mork
28        RE = {
29                :comment => %r|//.*\n|,
30                :key_table => %r/  < \s* <             # "< <"
31                                  \( a=c \) >          # "(a=c)>"
32                                  (?> ([^>]*) ) > \s*  # Grab anything that's not ">"
33                                /mx,
34
35                :value_table => %r/ < ( .*?\) )> \s* /mx,
36
37                :table => %r/ \{ -?        # "{" or "{-"
38                             [\da-f]+ :    # hex, ":"
39                             (?> .*?\{ )   # Eat up to a {...
40                            ((?> .*?\} )   # and then the closing }...
41                             (?> .*?\} ))  # Finally, grab the table section
42                         \s* /mix,
43
44                :row => %r/ ( (?> \[ [^\]]* \]  # "["..."]"
45                                  \s*)+ )      # Perhaps repeated many times
46                          /mx,
47
48                :section_begin => %r/ \@\$\$\{    # "@$${"
49                                      ([\dA-F]+)  # hex
50                                      \{\@ \s*    # "{@"
51                                   /mix,
52                :section_end => nil # variable
53        }
54
55        def initialize(str, age=nil)
56                @str = str
57                @since = age ? Time.now - age : 0
58                @age = age
59        end
60
61        def parse_key_table(key_table)
62                key_table.gsub!(%r|\s+//.*$|, "")
63                pairs = key_table.split(/\(([^\)]+)\)/)
64                pairs.each do |pair|
65                        next unless pair =~ /\S/m
66                        _, key, val = *pair.match(/([\dA-F]*)[\t\n ]*=[\t\n ]*(.*)/i);
67
68                        raise "Unparsable" unless val
69
70                        @key_table[key] = val
71                end
72
73        end
74
75        def parse_value_table(val_part)
76                return unless val_part
77
78                pairs = val_part.split(/\(([^\)]+)\)/)
79                pairs.each do |pair|
80                        next unless pair =~ /\S/m
81                        _, key, val = *pair.match(/([\dA-F]*)[\t\n ]*=[\t\n ]*(.*)/i);
82
83                        unless val
84                                $stderr.puts "Unparsable"
85                                next
86                        end
87
88                        if val.gsub!(/\$([\dA-F]{2})/) { $1.hex.chr }
89                                val = val.unpack("S*").pack("U*")
90                        end
91
92                        @val_table[key] = val
93                end
94        end
95
96        def parse_table(table_part)
97                table_part.gsub!(/\s+/, "")
98                re = %r/[^\[]*   \[  # find a "["
99                      ( [^\]]+ ) \]  # capture up to "]"
100                       /x
101                table_part.scan(re) do |m,|
102                        hash = {}
103                        id, *cells = m.split(/[()]+/)
104                        next unless cells
105                        id.gsub!(/^-/, "")
106                        id.gsub!(/:.*/, "")
107
108                        if @row_hash[id]
109                                hash = @row_hash[id]
110                        else
111                                hash = {
112                                        "ID" => id,
113                                        "LastVisitDate" => 0,
114                                }
115                        end
116
117                        cells.each do |cell|
118                                next unless cell
119
120                                _, keyi, which, vali = *cell.match(
121                                        /^\^ ([-\dA-F]+)
122                                        ([\^=])
123                                        (.*)
124                                        $/xi)
125
126                                unless vali
127                                        $stderr.puts "Unparsable"
128                                        next
129                                end
130
131                                key = @key_table[keyi]
132                                next unless key
133
134                                val = (which == "=") ? vali : @val_table[vali]
135
136                                hash[key] = val
137                        end
138
139                        @block.call(hash)
140
141                        @row_hash[id] = hash
142                end
143        end
144        alias parse_row parse_table
145
146        def parse_section_begin(section)
147                @section = section
148                @re[:section_end] = %r/\@\$\$\}#{section}\}\@\s*/s;
149        end
150
151        def parse_section_end(e)
152                @re[:section_end] = nil
153                @section = "top level"
154        end
155
156        def parse_comment(e)
157                # Nice boat.
158        end
159
160        def parse(&block)
161                @block = block
162                @block = proc {} unless @block
163                @str.gsub!(/\r\n/, "\n")
164                @str.gsub!(/\r/, "\n")
165                @str.gsub!(/\\\\/, "$5C")
166                @str.gsub!(/\\\)/, "$29")
167                @str.gsub!(/\\\n/, "")
168
169                @s = StringScanner.new(@str)
170                @section = "top level"
171                @re = RE.dup
172                @row_hash = {}
173                @key_table = {}
174                @val_table = {}
175                until @s.eos?
176                        [:key_table, :value_table, :table, :row, :section_begin, :section_end, :comment].each do |k|
177                                next unless @re[k]
178                                if @s.scan(@re[k])
179                                        self.send("parse_#{k}", @s[1])
180                                        break
181                                end
182                        end
183                end
184                @row_hash
185        end
186end
187
188
189if $0 == __FILE__
190        profile_dir =
191                case RUBY_PLATFORM
192                when /darwin/
193                        "~/Library/Application Support/Firefox/Profiles"
194                when /win/
195                        "~/Application Data/Mozilla/Firefox/Profiles"
196                when
197                        "~/.mozilla/firefox"
198                end
199
200
201        require "pp"
202        require "pathname"
203        histfiles = Pathname.glob(File.expand_path("*/history.dat", profile_dir))
204        puts histfiles
205
206#       history = File.read(histfiles.first)
207#       pp Mork.new(history).parse
208       
209#       pp histfiles.inject([]) {|r,i|
210#               r.concat Mork.new(i.read).parse.map {|k,v|
211#                       v["URL"]
212#               }
213#       }
214
215        histfiles.each do |i|
216                Mork.new(i.read).parse do |hash|
217                        pp hash
218                end
219        end
220end
221
Note: See TracBrowser for help on using the browser.