~ubuntu-branches/ubuntu/saucy/dhelp/saucy-proposed

« back to all changes in this revision

Viewing changes to tmp/dhelp-ruby/lib/dhelp.rb

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson
  • Date: 2008-06-19 01:25:07 UTC
  • Revision ID: james.westby@ubuntu.com-20080619012507-adt75omul1shucde
Tags: 0.6.9ubuntu1
* Resynchronise with Debian. Remaining changes:
  - Recommends: firefox-3.0.
  - Exit zero if the bdb module is not available; this usually indicates
    that dhelp is not configured yet.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/ruby -w
2
 
 
3
 
=begin
4
 
    Ruby support library for dhelp database access
5
 
 
6
 
    Copyright (C) 2005  Esteban Manchado Vel�zquez
7
 
 
8
 
    This program is free software; you can redistribute it and/or modify
9
 
    it under the terms of the GNU General Public License as published by
10
 
    the Free Software Foundation; either version 2 of the License, or
11
 
    (at your option) any later version.
12
 
 
13
 
    This program is distributed in the hope that it will be useful,
14
 
    but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 
    GNU General Public License for more details.
17
 
 
18
 
    You should have received a copy of the GNU General Public License
19
 
    along with this program; if not, write to the Free Software
20
 
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
21
 
=end
22
 
 
23
 
require 'bdb'
24
 
 
25
 
# Dhelp-related classes
26
 
module Dhelp
27
 
    # C struct wrapper
28
 
    class CStructWrapper
29
 
        # Class methods
30
 
        class <<self
31
 
            # Get/Set the pack format
32
 
            def pack_fmt(fmt = nil)
33
 
                @fmt = fmt if fmt
34
 
                @fmt
35
 
            end
36
 
            # Get/Set the field list. It can be set as an array, or as several
37
 
            # parameters
38
 
            def field_list(*args)
39
 
                case args.size
40
 
                when 0
41
 
                    # Just get the value, do nothing
42
 
                when 1
43
 
                    first = args.first
44
 
                    @fieldList = first.kind_of?(Array) ? first : [first]
45
 
                else
46
 
                    @fieldList = args
47
 
                end
48
 
                @fieldList.map {|f| f.to_sym}
49
 
            end
50
 
        end
51
 
 
52
 
        def initialize(data)
53
 
            case data
54
 
            when String
55
 
                @data = data
56
 
            when Hash
57
 
                @data = keys.map {|f| data[f]}.pack(pack_fmt)
58
 
            else
59
 
                raise ArgumentError, "Argument must be either String or Hash"
60
 
            end
61
 
        end
62
 
 
63
 
        # Handy shortcut methods
64
 
        def keys;     self.class.field_list; end
65
 
        def pack_fmt; self.class.pack_fmt;   end
66
 
 
67
 
        def get_field(f)
68
 
            i = keys.index(f.to_sym)
69
 
            if i
70
 
                @data.unpack(pack_fmt)[i]
71
 
            else
72
 
                raise ArgumentError, "Unknown field '#{f}'"
73
 
            end
74
 
        end
75
 
 
76
 
        # Returns a Hash object with all the C struct fields
77
 
        def to_hash
78
 
            h = {}
79
 
            keys.each do |f|
80
 
                h[f] = get_field(f)
81
 
            end
82
 
            h
83
 
        end
84
 
 
85
 
        # Returns the data in C format
86
 
        def to_raw_data
87
 
            @data
88
 
        end
89
 
 
90
 
        # Catches missing methods, to get the field values
91
 
        def method_missing(meth, *args)
92
 
            if keys.include? meth.to_sym
93
 
                get_field(meth)
94
 
            else
95
 
                super
96
 
            end
97
 
        end
98
 
    end
99
 
 
100
 
 
101
 
    # Key data entry
102
 
    class KeyData < CStructWrapper
103
 
        pack_fmt    'Z100 Z100 Z100'
104
 
        field_list  %w(file dir name)
105
 
    end
106
 
 
107
 
 
108
 
    # Value data entry
109
 
    class ValueData < CStructWrapper
110
 
        pack_fmt    'Z1000'
111
 
        field_list  %w(descrip)
112
 
    end
113
 
 
114
 
 
115
 
    # Title database key data entry
116
 
    class TitleKeyData < CStructWrapper
117
 
        pack_fmt    'Z1000'
118
 
        field_list  %w(dir)
119
 
    end
120
 
 
121
 
 
122
 
    # Title database value data entry
123
 
    class TitleValueData < CStructWrapper
124
 
        pack_fmt    'Z1000'
125
 
        field_list  %w(dtitle)
126
 
    end
127
 
 
128
 
 
129
 
    # Item data entry
130
 
    class ItemData < CStructWrapper
131
 
        pack_fmt    'Z100 Z100 Z100 Z100 Z1000'
132
 
        field_list  %w(dir dtitle name file descrip)
133
 
    end
134
 
 
135
 
 
136
 
    # Dhelp database
137
 
    class Database < BDB::Btree
138
 
        STD_COMPARISON = lambda {|a,b|
139
 
                                    dataA, dataB = KeyData.new(a), KeyData.new(b)
140
 
                                    r = dataA.dir <=> dataB.dir
141
 
                                    r == 0 ? (dataA.name <=> dataB.name) : r
142
 
                                }
143
 
 
144
 
        def Database.open(flags   = BDB::RDONLY,
145
 
                          options = {},
146
 
                          mode    = 0644,
147
 
                          # name    = 'dhelpdbase',
148
 
                          name    = '/var/lib/dhelp/dbase',
149
 
                          subname = nil)
150
 
            defaultOptions = {"flags"      => 0,
151
 
                              "cachesize"  => 10000,
152
 
                              "minkeypage" => 0,
153
 
                              "psize"      => 0,
154
 
                              "compare"    => STD_COMPARISON,
155
 
                              "prefix"     => nil,
156
 
                              "lorder"     => 0}
157
 
            super(name, subname, flags, mode, defaultOptions.merge(options))
158
 
        end
159
 
 
160
 
        # Writes an ItemData object to the database
161
 
        def write(data)
162
 
            key = KeyData.new(:file => data.file, :dir => data.dir,
163
 
                              :name => data.name)
164
 
            value = ValueData.new(:descrip => data.descrip)
165
 
            put(key.to_raw_data, value.to_raw_data)
166
 
        end
167
 
 
168
 
        def del(data)
169
 
            key = KeyData.new(:file => data.file, :dir => data.dir,
170
 
                              :name => data.name)
171
 
            delete(key.to_raw_data)
172
 
        end
173
 
 
174
 
        # Hide delete method, always use the high-level one
175
 
        protected :delete
176
 
 
177
 
        # Traverse entire BD, passing each item to the block
178
 
        def each
179
 
            super do |k,v|
180
 
                key, value = KeyData.new(k), ValueData.new(v)
181
 
                # Note: missing dtitle field
182
 
                yield ItemData.new(:file    => key.file,
183
 
                                   :dir     => key.dir,
184
 
                                   :name    => key.name,
185
 
                                   :descrip => value.descrip)
186
 
            end
187
 
        end
188
 
 
189
 
        # Traverse each _item_, collecting their categories, and pass the
190
 
        # category and item list to the given block
191
 
        def each_category
192
 
            itemList        = {}
193
 
            each do |item|
194
 
                itemList[item.dir] ||= []
195
 
                itemList[item.dir] << item
196
 
            end
197
 
 
198
 
            orderedCategories = itemList.keys.sort {|a,b|
199
 
                # Order subcategories first
200
 
                case tmp = a.scan('/').size <=> b.scan('/').size
201
 
                when 0
202
 
                    a <=> b
203
 
                else
204
 
                    tmp * -1
205
 
                end
206
 
            }
207
 
            orderedCategories.each do |cat|
208
 
                yield cat, itemList[cat].sort {|a,b| a.name <=> b.name}
209
 
            end
210
 
        end
211
 
    end
212
 
 
213
 
 
214
 
    # Dhelp titles database
215
 
    class TitleDatabase < BDB::Hash
216
 
        def TitleDatabase.open(flags   = BDB::RDONLY,
217
 
                                options = {},
218
 
                                mode    = 0644,
219
 
                                name    = '/var/lib/dhelp/titles',
220
 
                                # name    = 'dhelptitles',
221
 
                                subname = nil)
222
 
            defaultOptions = {"ffactor"   => 8,
223
 
                              "nelem"     => 1,
224
 
                              "cachesize" => 5000,
225
 
                              "hash"      => nil,
226
 
                              "lorder"    => 0}
227
 
            super(name, subname, flags, mode, defaultOptions.merge(options))
228
 
        end
229
 
 
230
 
        # Traverse entire BD, passing each item to the block
231
 
        def each
232
 
            super do |k,v|
233
 
                key, value = KeyData.new(k), ValueData.new(v)
234
 
                # Note: missing dtitle field
235
 
                yield ItemData.new(:file    => key.file,
236
 
                                   :dir     => key.dir,
237
 
                                   :name    => key.name,
238
 
                                   :descrip => value.descrip)
239
 
            end
240
 
        end
241
 
 
242
 
        def title_for(dir)
243
 
            valueData = get(TitleKeyData.new(:dir => dir).to_raw_data)
244
 
            valueData ? TitleValueData.new(valueData).dtitle : nil
245
 
        end
246
 
 
247
 
        # Writes an ItemData object to the database
248
 
        def write(data)
249
 
            key = TitleKeyData.new(:dir => data.dir)
250
 
            value = TitleValueData.new(:dtitle => data.dtitle)
251
 
            put(key.to_raw_data, value.to_raw_data)
252
 
        end
253
 
    end
254
 
end