X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=lib%2Fchise%2Fdb.rb;fp=lib%2Fchise%2Fdb.rb;h=6057770a2a36035f3e205d23b75b334462d696e3;hb=ff4a6a62c6e2c1f008a3d0d442ef54c77229ba82;hp=0000000000000000000000000000000000000000;hpb=dff64d400d3f390285e170d0920c556692ccd90e;p=chise%2Fruby.git diff --git a/lib/chise/db.rb b/lib/chise/db.rb new file mode 100755 index 0000000..6057770 --- /dev/null +++ b/lib/chise/db.rb @@ -0,0 +1,400 @@ +#!/usr/bin/env ruby +# $Id: db.rb,v 1.1 2003-11-10 08:31:26 eto Exp $ +# Copyright (C) 2002-2003 Kouichirou Eto, All rights reserved. +# This is free software with ABSOLUTELY NO WARRANTY. +# You can redistribute it and/or modify it under the terms of the GNU GPL2. + +require 'bdb' +require 'singleton' + +module CHISE + + class DBS #======================================================================複数のDBを集めたclass、未完成 + end + + class ADB < BDB::Hash #======================================================================一つのDB + def initialize(*args) + super + @filename = args[0] + @modified = false + at_exit { +# p ['at_exit', @filename, @modified] + if @modified +# p ['close', @filename, @modified] + self.close #これがないと、うまくデータベースがセーブされないのです。 + end + } + end + def self.open_create(filename) + ADB.open(filename, nil, BDB::CREATE | BDB::EXCL) #上書きはしない + end + def mykey(key) + if key.is_a?(String) + if key.char_length == 1 + return '?'+key #Stringだったら引く前に?を足す + end + end + #key = key.to_s if key.is_a?(Numeric) #NumberだったらStringにする。 + #ここで && key ! =~ /^\?/ をいれると、?自身を検索できなくなってしまう。 + return key + end + def myvalue(v) + return v if v == nil + return v.to_i if v =~ /^\d+$/ #数字だったらここで変換しておく + return v.sub(/^\?/, '') if v =~ /^\?/ #冒頭の?は取り除く + return $1 if v =~ /^"(.+)"$/ #最初と最後に"がついていたら、取り除く + #p ['get', v, t, key, db] + #return parse_sexp(v) if v =~ /^\(.+\)$/ #最初と最後が()の時は、S式にparseする + return v #それ以外って何? + end + def myget(key) #keyキーを引いて返す + key = mykey(key) + v = get(key) #存在しなかったらnilを返すことになる + return myvalue(v) + end + def myput(key, v) #keyにvをいれる + key = mykey(key) + put(key, v) #putする + @modified = true + end + end + + class DB #======================================================= データベース群のabstract class + def self.unix_to_win(unix) #Windowsファイル名制限のため、変換する + win = unix.gsub(//, ')') + win.gsub!(/\*/, '+') + win.gsub!(/\?/, '!') + return win + end + def self.win_to_unix(win) + unix = win.gsub(%r|\)|, '>') + unix.gsub!(%r|\(|, '<') + unix.gsub!(%r|!|, '?') + unix.gsub!(%r|\+|, '*') + return unix + end + def get_filename(t) + return @pre + DB.unix_to_win(t) + @post if windows? + return @pre + t + @post + end + def get_dirname(t) File.dirname(get_filename(t)) end + def open_dbs() + @dbs = Hash.new + keys = find_keys() + keys.each {|key| open_db(key) } + end + def find_keys() + files = [] + Dir.glob(@glob){|f| + next if ! File.file?(f) + next if f =~ /.txt$/ + files << f + } + keys = [] + files.each {|f| + t = DB.win_to_unix(f) + t.sub!(%r|^#{@pre}|, '') + t.sub!(%r|#{@post}$|, '') if @post != "" + keys << t + } + return keys + end + def close_db(t) + db = get(t) + return nil if db.nil? + db.close + @dbs.delete(t) + end + def open_db(t) + return nil if get(t) #すでにopenしていたら再openはしない。 + begin + bdb = ADB.open(get_filename(t), nil, 0) + @dbs[t] = bdb if bdb != nil + rescue + p ["open error", get_filename(t)]; return nil + end + return true + end + def make_db(t, h=nil) #tという名前でhという中身のデータベースを作る + return nil if get(t) #すでにある場合はreturn + Dir.mkdir(get_dirname(t)) unless FileTest.exist?(get_dirname(t)) + db = nil + begin + db = ADB.open_create(get_filename(t)) #上書きはしない + if h != nil + h.each {|k, v| + k = '?'+k if k.is_a?(String) + db[k] = v + } + end + db.close + rescue + p ["make error", get_filename(t)]; return nil + end + return true + end + def make_db_no_question_mark(t, h=nil) #tという名前でhという中身のデータベースを作る + return nil if get(t) #すでにある場合はreturn + Dir.mkdir(get_dirname(t)) unless FileTest.exist?(get_dirname(t)) + db = nil + begin + db = ADB.open_create(get_filename(t)) #上書きはしない + if h != nil + h.each {|k, v| + # k = '?'+k if k.is_a?(String) + db[k] = v + } + end + db.close + rescue + p ["make error", get_filename(t)]; return nil + end + return true + end + def remove_db(t) #tという名前のデータベースを消去する + db = get(t) + if db + db.close + @dbs.delete(t) + end + begin + File.unlink(get_filename(t)) if FileTest.file?(get_filename(t)) + rescue + p ["unlink error", get_filename(t)]; return nil + end + dn = get_dirname(t) + Dir.rmdir(dn) if FileTest.directory?(dn) && Dir.entries(dn).length <= 2 #空directoryだったら消す + return true + end + def to_num(s) + return s.to_i if s =~ /^\d+$/ + return s + end + def dump_db(t) + db = get(t) + return nil unless db + file = get_filename(t) + open("#{file}.txt", "w"){|out| + # out.binmode.sync = true + ar = db.to_a + ar.map! {|k, v| [to_num(k), to_num(v)] } + ar.sort.each {|k, v| + out.printf("%s\t%s\n", k, v) + } + } + return true + end + def each_db() @dbs.to_a.sort.each {|t, db| yield(t, db) } end + def dump_all() each_db {|t, db| dump_db(t) } end + def close_all() each_db {|t, db| db.close } end + def keys() @dbs.keys end + def each(t) + return unless block_given? + db = @dbs[t] + return nil unless db + db.each {|k, v| + k = to_num(k) + v = to_num(v) + k.sub!(/^\?/, '') if k =~ /^\?/ #冒頭の?は取り除く + vv = get(t, k) #p ['each', t, k, v, vv] + yield(k, vv) + } + end + def each_sort(t) + return unless block_given? + db = @dbs[t] + return nil unless db + ar = db.to_a + ar.map! {|k, v| [to_num(k), to_num(v)] } + ar.sort.each {|k, v| + k.sub!(/^\?/, '') if k =~ /^\?/ #冒頭の?は取り除く + vv = get(t, k) #p ['each', t, k, v, vv] + yield(k, vv) + } + end + #---------------------------------------------------------------------- + def get(t, key=nil) #tというデータベースのkeyキーを引いて返す + db = @dbs[t] + return db if key.nil? + return nil unless db + return db.myget(key) + end + def put(t, key, v) #tというデータベースのkeyにvをいれる + db = @dbs[t] + if db == nil + db = make_db(t) + db = open_db(t) + db = @dbs[t] + end + db.myput(key, v) #putする + end + end + + class CharDB < DB #------------------------------------ MCS-UTF8をキーとした属性へのデータベース + include Singleton + def initialize() + super + @glob, @pre, @post = "#{DB_DIR}/system-char-id/*", "#{DB_DIR}/system-char-id/", "" + open_dbs() + end + def get_all(u8) #全データベースのu8キーを引いてHashにまとめて返す + atrs = Hash.new + @dbs.each {|t, db| + v = get(t, u8) + atrs[t] = v if v != nil + } + return atrs + end + end + + class CodesysDB < DB #---------------------------------------------------------------------- + include Singleton + def initialize() + super + @glob, @pre, @post = "#{DB_DIR}/*/system-char-id", "#{DB_DIR}/", "/system-char-id" + open_dbs() + end + #def keys() @dbs.keys.sort end #どんなCodesysの情報を持っているかの一覧 + def keys() @dbs.keys end #どんなCodesysの情報を持っているかの一覧 + def get_codesys(t) + db = get(t) + return nil unless db + return Codesys.new(t) + end + end + + class Codesys < DB #====================================================================== + def initialize(name) + # super + @name = name + @dbs = CodesysDB.instance + end + def keys() #どんなコードポイントの情報を持っているかの一覧 + ks = @dbs.get(@name).keys +# if @name =~ /jisx0208/ #特別処理 +# n = @dbs.get('=jis-x0208').keys +# # p ['keys', @name, ks, n] +# ks += n +# end + ks.map! {|k| to_num(k) } + ks + end + def get(key) + v = @dbs.get(@name, key) + return v if v +# if @name =~ /jisx0208/ #jisx0208が含まれている場合だけ特別処理する +# return @dbs.get('=jis-x0208', key) +# end + return nil + end + def each() + return unless block_given? + db = @dbs.get(@name) + return nil unless db + db.each {|k, v| + k = to_num(k) + v = to_num(v) + k.sub!(/^\?/, '') if k =~ /^\?/ #冒頭の?は取り除く + vv = @dbs.get(@name, k) #p ['each', t, k, v, vv] + yield(k, vv) + } + end + def each_sort() + return unless block_given? + db = @dbs.get(@name) + return nil unless db + ar = db.to_a + ar.map! {|k, v| [to_num(k), to_num(v)] } + ar.sort.each {|k, v| + k.sub!(/^\?/, '') if k =~ /^\?/ #冒頭の?は取り除く + vv = @dbs.get(@name, k) #p ['each', t, k, v, vv] + yield(k, vv) + } + end + end + + class JISX0208 #====================================================================== + def initialize + db = CodesysDB.instance + @common = db.get_codesys('=jis-x0208') + @newest = db.get_codesys('japanese-jisx0208-1990') + end + def get_char(code) + char = @common.get(code) + return char unless char.nil? + char = @newest.get(code) + return char unless char.nil? + return nil + end + end + + class DBS_Management #======================================================================ファイル管理 + OBSOLETE_ATTRIBUTES = " +cns-radical +cns-radical? +kangxi-radical +daikanwa-radical +unicode-radical + +cns-strokes +kangxi-strokes +daikanwa-strokes +shinjigen-1-radical +gb-original-radical +japanese-strokes +jis-strokes-a +jis-strokes-b +jisx0208-strokes +jis-x0213-strokes +jisx0213-strokes +unicode-strokes + +totalstrokes +cns-total-strokes +jis-total-strokes-b + +non-morohashi + +=>ucs* +#=>mojikyo +#=mojikyo +->identical + +ancient-ideograph-of +ancient-char-of-shinjigen-1 +original-ideograph-of +original-char-of-shinjigen-1 +simplified-ideograph-of +vulgar-ideograph-of +vulgar-char-of-shinjigen-1 +ideograph= +ideographic-variants +variant-of-shinjigen-1 + +iso-10646-comment +".split + def initialize + @odir = DB_DIR+"/system-char-id/obsolete" #直打ちしている。 + end + def move_obsolete_files # 廃止予定のbdbファイルをobsoleteディレクトリーにつっこむ + db = CharDB.instance + db.close_all + Dir.mkdir(@odir) unless FileTest.directory? @odir + OBSOLETE_ATTRIBUTES.each {|attr| + next if attr =~ /^#/ + filename = db.get_filename(attr) + move_to_obsolete(filename) + move_to_obsolete(filename+".txt") + } + end + def move_to_obsolete(file) + cmd = "mv \"#{file}\" #{@odir}" + # p cmd + system cmd + end + end + +end + +#----------------------------------------------------------------------終了