1 # Copyright (C) 2002-2004 Kouichirou Eto, All rights reserved.
6 require "chise/rbchise"
10 class DBS # collection of DBs. not yet
13 class ADB < BDB::Hash # A DataBase.
19 # p ["at_exit", @filename, @modified]
21 # p ["close", @filename, @modified]
22 self.close #これがないと、うまくデータベースがセーブされないのです。
27 def self.open_create(filename)
28 ADB.open(filename, nil, BDB::CREATE | BDB::EXCL) #上書きはしない
33 if key.char_length == 1
34 return "?"+key #Stringだったら引く前に?を足す
37 #key = key.to_s if key.is_a?(Numeric) #NumberだったらStringにする。
38 #ここで && key ! =~ /^\?/ をいれると、?自身を検索できなくなってしまう。
44 return v.to_i if v =~ /^\d+$/ #数字だったらここで変換しておく
45 return v.sub(/^\?/, "") if v =~ /^\?/ #冒頭の?は取り除く
46 return $1 if v =~ /^"(.+)"$/ #最初と最後に"がついていたら、取り除く
47 #p ["get", v, t, key, db]
48 #return parse_sexp(v) if v =~ /^\(.+\)$/ #最初と最後が()の時は、S式にparseする
52 def myget(key) #keyキーを引いて返す
54 v = get(key) #存在しなかったらnilを返すことになる
58 def myput(key, v) #keyにvをいれる
65 class DB # abstract class for DataBase
66 # translate file name for deal with Windows file system.
67 def self.unix_to_win(unix_path)
68 win = unix_path.gsub(/</, "(")
69 win = win.gsub(/>/, ")")
70 win = win.gsub(/\*/, "+")
71 win = win.gsub(/\?/, "!")
75 def self.win_to_unix(win_path)
76 unix = win_path.gsub(/\)/, ">")
77 unix = unix.gsub(/\(/, "<")
78 unix = unix.gsub(/\!/, "?")
79 unix = unix.gsub(/\+/, "*")
84 return @pre + DB.unix_to_win(t) + @post if CHISE.windows?
85 return @pre + t + @post
88 def get_dirname(t) File.dirname(get_filename(t)) end
93 keys.each {|key| open_db(key) }
99 next if ! File.file?(f)
105 t = DB.win_to_unix(f)
106 t.sub!(%r|^#{@pre}|, "")
107 t.sub!(%r|#{@post}$|, "") if @post != ""
115 return nil if db.nil?
121 return nil if get(t) #すでにopenしていたら再openはしない。
123 bdb = ADB.open(get_filename(t), nil, 0)
124 @dbs[t] = bdb if bdb != nil
126 p ["open error", get_filename(t)]; return nil
131 def make_db(t, h=nil) #tという名前でhという中身のデータベースを作る
132 return nil if get(t) #すでにある場合はreturn
133 Dir.mkdir(get_dirname(t)) unless FileTest.exist?(get_dirname(t))
136 db = ADB.open_create(get_filename(t)) #上書きはしない
139 k = "?"+k if k.is_a?(String)
145 p ["make error", get_filename(t)]; return nil
150 def make_db_no_question_mark(t, h=nil) #tという名前でhという中身のデータベースを作る
151 return nil if get(t) #すでにある場合はreturn
152 Dir.mkdir(get_dirname(t)) unless FileTest.exist?(get_dirname(t))
155 db = ADB.open_create(get_filename(t)) #上書きはしない
158 # k = "?"+k if k.is_a?(String)
164 p ["make error", get_filename(t)]; return nil
169 def remove_db(t) #tという名前のデータベースを消去する
176 File.unlink(get_filename(t)) if FileTest.file?(get_filename(t))
178 p ["unlink error", get_filename(t)]; return nil
181 Dir.rmdir(dn) if FileTest.directory?(dn) && Dir.entries(dn).length <= 2 #空directoryだったら消す
186 return s.to_i if s =~ /^\d+$/
193 file = get_filename(t)
194 open("#{file}.txt", "w"){|out|
195 # out.binmode.sync = true
197 ar.map! {|k, v| [to_num(k), to_num(v)] }
199 out.printf("%s\t%s\n", k, v)
205 def each_db() @dbs.to_a.sort.each {|t, db| yield(t, db) } end
206 def dump_all() each_db {|t, db| dump_db(t) } end
207 def close_all() each_db {|t, db| db.close } end
208 def keys() @dbs.keys end
211 return unless block_given?
217 k.sub!(/^\?/, "") if k =~ /^\?/ #冒頭の?は取り除く
218 vv = get(t, k) #p ["each", t, k, v, vv]
224 return unless block_given?
228 ar.map! {|k, v| [to_num(k), to_num(v)] }
230 k.sub!(/^\?/, "") if k =~ /^\?/ #冒頭の?は取り除く
231 vv = get(t, k) #p ["each", t, k, v, vv]
236 def get(t, key=nil) #tというデータベースのkeyキーを引いて返す
238 return db if key.nil?
243 def put(t, key, v) #tというデータベースのkeyにvをいれる
250 db.myput(key, v) #putする
254 class CharDB < DB # An Attribute DataBase. Key is in UTF8-MCS.
259 dir = Config.instance.db_dir
260 @glob, @pre, @post = "#{dir}/system-char-id/*", "#{dir}/system-char-id/", ""
264 def get_all(u8) #全データベースのu8キーを引いてHashにまとめて返す
268 atrs[t] = v if v != nil
274 class CodesysDB < DB # A CodeSystem DataBase.
279 dir = Config.instance.db_dir
280 @glob, @pre, @post = "#{dir}/*/system-char-id", "#{dir}/", "/system-char-id"
284 #def keys() @dbs.keys.sort end #どんなCodesysの情報を持っているかの一覧
285 def keys() @dbs.keys end #どんなCodesysの情報を持っているかの一覧
290 return Codesys.new(t)
298 @dbs = CodesysDB.instance
301 def keys() #どんなコードポイントの情報を持っているかの一覧
302 ks = @dbs.get(@name).keys
303 # if @name =~ /jisx0208/ #特別処理
304 # n = @dbs.get("=jis-x0208").keys
305 # # p ["keys", @name, ks, n]
308 ks.map! {|k| to_num(k) }
313 v = @dbs.get(@name, key)
315 # if @name =~ /jisx0208/ #jisx0208が含まれている場合だけ特別処理する
316 # return @dbs.get("=jis-x0208", key)
322 return unless block_given?
328 k.sub!(/^\?/, "") if k =~ /^\?/ #冒頭の?は取り除く
329 vv = @dbs.get(@name, k) #p ["each", t, k, v, vv]
335 return unless block_given?
339 ar.map! {|k, v| [to_num(k), to_num(v)] }
341 k.sub!(/^\?/, "") if k =~ /^\?/ #冒頭の?は取り除く
342 vv = @dbs.get(@name, k) #p ["each", t, k, v, vv]
350 db = CodesysDB.instance
351 @common = db.get_codesys("=jis-x0208")
352 @newest = db.get_codesys("japanese-jisx0208-1990")
355 char = @common.get(code)
356 return char unless char.nil?
357 char = @newest.get(code)
358 return char unless char.nil?
363 class DBS_Management # DataBase file management
364 OBSOLETE_ATTRIBUTES = "
396 ancient-char-of-shinjigen-1
397 original-ideograph-of
398 original-char-of-shinjigen-1
399 simplified-ideograph-of
401 vulgar-char-of-shinjigen-1
404 variant-of-shinjigen-1
410 dir = Config.instance.db_dir
411 @odir = dir+"/system-char-id/obsolete" #直打ちしている。
414 def move_obsolete_files # move obsolete BDB files to obsolete directory
417 Dir.mkdir(@odir) unless FileTest.directory? @odir
418 OBSOLETE_ATTRIBUTES.each {|attr|
420 filename = db.get_filename(attr)
421 move_to_obsolete(filename)
422 move_to_obsolete(filename+".txt")
426 def move_to_obsolete(file)
427 cmd = "mv \"#{file}\" #{@odir}"