From: eto Date: Tue, 18 Mar 2003 06:22:28 +0000 (+0000) Subject: add db.rb, ids.rb, rbchise.rb X-Git-Url: http://git.chise.org/gitweb/?a=commitdiff_plain;h=87e4a6789ae4c0e811648ddeb5c11d8f0d0d9632;p=chise%2Fruby.git add db.rb, ids.rb, rbchise.rb --- diff --git a/src/db.rb b/src/db.rb new file mode 100755 index 0000000..c2b5a11 --- /dev/null +++ b/src/db.rb @@ -0,0 +1,393 @@ +#!/usr/bin/env ruby +# rbchise compatible ruby library by eto 2003-0317 + +require 'db' + +module CHISE + + class DBS #======================================================================複数のDBを集めたclass、未完成 + end + + class ADB < BDB::Hash #======================================================================一つのDB + def initialize(*args) + super + @modified = false + at_exit { + if @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 + +#----------------------------------------------------------------------終了 diff --git a/src/ids.rb b/src/ids.rb new file mode 100755 index 0000000..bb80bbe --- /dev/null +++ b/src/ids.rb @@ -0,0 +1,458 @@ +#!/usr/bin/env ruby +# rbchise compatible ruby library by eto 2003-0317 + +module CHISE + + class IDS_TEXT_DB < DB #====================================================================== + include Singleton + IDS_LIST = " +IDS-UCS-Basic.txt +#IDS-UCS-Compat-Supplement.txt +#IDS-UCS-Compat.txt +IDS-UCS-Ext-A.txt +IDS-UCS-Ext-B-1.txt +IDS-UCS-Ext-B-2.txt +IDS-UCS-Ext-B-3.txt +IDS-UCS-Ext-B-4.txt +IDS-UCS-Ext-B-5.txt +IDS-UCS-Ext-B-6.txt +IDS-JIS-X0208-1990.txt +IDS-Daikanwa-01.txt +IDS-Daikanwa-02.txt +IDS-Daikanwa-03.txt +IDS-Daikanwa-04.txt +IDS-Daikanwa-05.txt +IDS-Daikanwa-06.txt +IDS-Daikanwa-07.txt +IDS-Daikanwa-08.txt +IDS-Daikanwa-09.txt +IDS-Daikanwa-10.txt +IDS-Daikanwa-11.txt +IDS-Daikanwa-12.txt +IDS-Daikanwa-dx.txt +IDS-Daikanwa-ho.txt +IDS-CBETA.txt +".split + def initialize() + super + @ids_list = IDS_LIST + @chars = [] + @glob, @pre, @post = "#{IDS_DB_DIR}/db/*", "#{IDS_DB_DIR}/db/", "" + dir = File.dirname(@pre) + Dir.mkdir(dir) unless FileTest.exist?(dir) + open_dbs() + end + def each_file() + return unless block_given? + @ids_list.each {|file| + next if file =~ /^#/ + yield(IDS_DB_DIR+file) + } + end + def each_line(file) + open(file){|f| + while line = f.gets + next if line =~ /^;/ #コメントはとばす + line.chomp! + code, char, ids = line.split + yield(code, char, ids) + end + } + end + def dump_text_all + each_file {|file| + dir = File.dirname(file) + '/../ids-new/' + Dir.mkdir(dir) if ! FileTest.directory?(dir) + newfile = dir + File.basename(file) + p [file, newfile] + open(newfile, "w"){|out| + out.binmode.sync = true + each_line(file){|code, ch, ids| + char = Character.get(ch) + ids = char.decompose + out.print "#{code} #{ch} #{ids}\n" + } + } + } + end + def make_ids_error + each_file {|file| + dir = File.dirname(file) + '/../ids-error' + Dir.mkdir(dir) unless FileTest.exist?(dir) + errfile = dir + '/' + File.basename(file) + # p [file, errfile] + open(errfile, "w"){|out| + out.binmode.sync = true + each_line(file){|code, ch, ids| + char = Character.get(ch) + ids_error = char['ids-error'] + next if ids_error.nil? + out.print "#{code} #{ch} #{ids} #{ids_error}\n" + } + } + } + end + end + + class IDS_DB < DB #======================================================================BDB化したIDS DBを扱う + include Singleton + def initialize + @dbs = CharDB.instance + end + def make_ids_db + db = IDS_TEXT_DB.instance + db.each_file {|file| + @char_counter = 0 + @same_ids_counter = 0 + @good_ids_counter = 0 + @conflict_ids_counter = 0 + db.each_line(file){|code, ch, ids| + @char_counter += 1 + + ids = "" if ids == nil + next if ids == "" #IDSが定義されていない場合は、さっくりと無視するべしよ。 + + charimg = Character.get(ch) #実体参照である可能性がある + + next if code =~ /'$/ || code =~ /"$/ #大漢和番号のダッシュ付きは無視する + char = Character.get("&"+code+";") #code表記を元に実体参照を作って解釈する + if char.nil? || char.to_s == "" #うまく文字にならなかった + print "char == null #{char.inspect} #{code} #{ch} #{ids}\n" unless code =~ /^M-/ || code =~ /^CB/ + #大漢和、CBETA以外の場合は、エラーメッセージ。 + next + end + if char != charimg #code表記と文字が一致していない? + unless code =~ /^M-/ || code =~ /^MH-/ || code =~ /^CB/ #食い違っていて当然であるので何もしない + print "unknown char #{char.inspect} #{code} #{ch} #{ids}\n" + next #それ以外の場合はエラーメッセージをだして、次へ。 + end + end + #next if !char.has_attribute? #isolated characterはまぎれこませない。 + + ids.de_er! #実体参照を解除する + next if ids == char.to_s #もし文字とまったく一緒なら、意味が無いので情報を持たない + next if ids.char_length == 1 + + idstree = IDS_Tree.new(ids) + c = idstree.check_integrity + c = "contains self" if ids.include?(char.to_s) + if c #ちょっとでもエラーがある場合は、 + char['ids-error'] = c #エラーを記録して、データとしては保持しない + next + end + + if char['ids'].nil? || char['ids'] == "" #元々IDSが無かった場合は、 + char['ids'] = ids #普通に代入すればそれでいいです。 + @good_ids_counter += 1 + else #しかしいままでにすでにIDSが定義されていた場合は? + if char['ids'] == ids #新しいIDSと古いIDSが完全に一致するなら無視しましょう。 + @same_ids_counter += 1 + else #しかしいままでのIDSと新しいIDSが食い違った場合は? + @conflict_ids_counter += 1 + # print "conflict #{char.inspect} #{code} #{ids} #{char['ids']}\n" + end + end + } + print "#{file} #{@char_counter} #{@same_ids_counter} #{@conflict_ids_counter} #{@good_ids_counter}\n" + CharacterFactory.instance.reset() + } + @dbs.dump_db('ids-error') #テキスト化する + @dbs.dump_db('ids') #テキスト化する + end + def make_ids_reverse + h = Hash.new + @dbs.each('ids') {|k, v| + char = k.char + ids = char.decompose + h[ids] = "" if h[ids].nil? + h[ids] += k #追加する + } + h.each {|k, v| + h[k] = char_sort(v) #文字の順番を、よく使うっぽいものからの順番にする + } + h.delete_if {|k, v| #h[k]が""になる可能性もあるが、それはkeyとして入れないことにする。 + v == "" + } + print "length #{h.length}\n" + cdb = CodesysDB.instance + cdb.make_db_no_question_mark('ids', h) + cdb.open_db('ids') #これが無いと、dump_dbされません。 + cdb.dump_db('ids') + end + def char_sort(composed) + return composed if composed.char_length == 1 + ar = composed.to_a + arorg = ar.dup + ar2 = [] + ar.dup.each {|ch| + char = ch.char + if char.char_id < 0xfffff #Unicodeっぽい? + ar2 << ch + ar.delete(ch) + end + } + if 0 < ar.length + EntityReference.each_codesys{|codesys, er_prefix, keta, numtype| + ar.each {|ch| + char = ch.char + v = char[codesys] + # p [codesys, v] if v + if v #EntityReferenceの順番に準拠する。 + ar2 << ch + ar.delete(ch) + end + } + } + end + if 0 < ar.length + # p ['yokuwakaran character', ar, ar[0].inspect_all, arorg] + EntityReference.each_codesys{|codesys, er_prefix, keta, numtype| + ar.dup.each {|ch| + char = ch.char + v = char[codesys] + # p [codesys, v] if v + } + } + end + return ar2.join("") + end + def dump_ids_duplicated + open('ids-duplicated.txt', 'w'){|out| + #out.binmode + CodesysDB.instance.each('ids') {|k, v| + if v.nil? + out.print "nil #{k} #{v}\n" + next + end + n = v.char_length + next if n == 1 + out.print "#{n} #{k} #{v}" + v.each_char {|ch| + char = ch.char + out.print " #{char.inspect}" + } + out.print "\n" + } + } + end + def make_ids_aggregated + @dbs.each('ids') {|k, v| + char = k.char + ids = char.decompose + ag = ids.aggregate + char['ids-aggregated'] = ag + } + @dbs.dump_db('ids-aggregated') + end + def dump_ids_aggregated + open('ids-aggregated.txt', 'w'){|out| + #out.binmode + @dbs.each('ids') {|k, v| + char = k.char + ids = char['ids'] + ag = char['ids-aggregated'] + out.print "#{char.to_s} #{ag} #{ids}\n" if ids != ag + } + } + end + def make_ids_parts + @dbs.each('ids') {|k, v| + char = k.char + pids = char.to_s + ar = [] + counter = 0 + loop { + ids = pids.decompose + break if ids == pids #これ以上分割できないようだったら終了〜。 + ar += ids.to_a + counter += 1 + p [char.to_s, pids, ids, ar] if 10 < counter #これは何かおかしいぞと + pids = ids + } + ar.sort! + ar.uniq! + #やっぱりIDS文字も加えることにする. by eto 2003-02-05 + # ar.delete_if {|ch| + # ch.char.is_ids? #IDS文字はまぎれこませない。 + # } + str = ar.join('') + char['ids-parts'] = str + } + @dbs.dump_db('ids-parts') + end + def make_ids_contained + h = Hash.new + @dbs.each('ids-parts') {|k, v| + char = k.char + parts = char.ids_parts + parts.each_char {|ch| + # part = ch.char + h[ch] = [] if h[ch].nil? + h[ch] << k + # h[ch] += k + # part['ids-contained'] = "" if part['ids-contained'].nil? + # part['ids-contained'] += k + } + } + h.each {|k, v| + char = k.char + v.sort! + char['ids-contained'] = v.join('') + + } + @dbs.dump_db('ids-contained') + end + def make_ids_decomposed + @dbs.each('ids') {|k, v| + char = k.char + de= char.decompose_all + char['ids-decomposed'] = de + } + @dbs.dump_db('ids-decomposed') + end + end + + class Node < Array #=======================================================木構造の中の一つの枝 + def initialize(nodeleaf=nil, nodenum=nil) + super() + @nodeleaf = nodeleaf + @nodenum = nodenum + if @nodeleaf + original_add(@nodeleaf) + end + end + attr_reader :nodenum + alias original_add << + private :original_add + def <<(obj) + original_add(obj) + @nodenum -= 1 if @nodenum + end + def nodes + ar = [] + ar << self.to_s + self.each {|n| + ar += n.nodes if n.is_a? Node + } + return ar + end + end + + class Tree #======================================================================木構造を扱う + def initialize() + @root = Node.new() + @stack = [@root] + @leafnum = 0 + @depth = 1 #stackの深さが最大になったところの値、木構造が無いときは1となる + end + def depth() @depth - 1 end + def add_node(nodeleaf=nil, nodenum=nil) #枝を追加 + new_node = Node.new(nodeleaf, nodenum) + @stack.last << new_node + @stack << new_node + if @depth < @stack.length + @depth = @stack.length + end + self + end + def end_node() #この枝は終り + @stack.pop + self + end + def add_leaf(a) #葉を追加 + @stack.last << a + end_check() + self + end + def end_check() + n = @stack.last.nodenum + if n && n == 0 + end_node() + end_check() #再帰 + end + end + def check_integrity + n = @stack.last.nodenum + return nil if @root.length == 0 #no tree is good tree + return "unmatch leaves" if n && n != 0 + return "extra nodes" if @root.first.is_a?(Node) && @root.length != 1 + return "extra leaves" if @root.length != 1 + return nil + end + def nodes + r = @root.nodes + r.shift + r + end + def sub_nodes + r = nodes + r.shift + r + end + def to_s() @root.to_s end + def inspect() @root.inspect end + end + + class IDS_Tree < Tree #====================================================================== + def initialize(str) + @str = str + super() + parse() + end + def parse() + @str.each_char {|ch| + char = Character.new(ch) + if is_ids?(char) + add_node(char, ids_operator_argc(char)) + else + add_leaf(char) + end + } + end + def is_ids?(obj) + return true if "+*".include?(obj.to_s) #テスト用ですかね + return true if obj.is_ids? + return false + end + def ids_operator_argc(obj) + return obj.ids_operator_argc if 0 < obj.ids_operator_argc + return 2 #テスト用ってことで + end + def check_integrity + r = super + return r if r #不完全がすでにわかっているならreturn + return "contains ques" if @str =~ /\?/ #?が含まれている? + return nil + end + end + + class IDS #======================================================================IDSそのものを扱うclass + def initialize(str) #IDS文字列をうけとる。 + @str = str + end + def parse + end + def parse_x #柔軟型のParse. IDSキャラクターが前にきてなくてもよい。などなど。 + end + end + + class Counter #====================================================================== + #使い方 + #counter = Counter.new(50) { exit } + #counter.count + def initialize(max) + @max = max + @count = 0 + @proc = proc + end + def count + @count += 1 + if @max <= @count + @proc.call + end + end + end + +end + +#----------------------------------------------------------------------end. diff --git a/src/rbchise.rb b/src/rbchise.rb new file mode 100755 index 0000000..0333a69 --- /dev/null +++ b/src/rbchise.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby +# rbchise compatible ruby library by eto 2003-0317 + +module CHISE + + class DataSource #====================================================================== + NONE = 0 + Berkeley_DB = 1 + #DEFAULT_CHAR_DB_DIR = "/usr/local/lib/chise/char-db" + DEFAULT_CHAR_DB_DIR = "d:/work/chise/char-db" + def initialize(type=Berkeley_DB, location = DEFAULT_CHAR_DB_DIR) + @type, @location = type, location + end + def close + end + def open_decofing_table(ccs) + DecodingTable.new(self, ccs) + end + def open_feature_table(feature) + FeatureTable.new(self, feature) + end + end + + class AttributeTable #====================================================================== + def open(from, to, real_subtpe, accessmask, modemask) + end + def get_value(char_id) + @db.get(char_id) + end + def close + end + end + + class DecodingTable #====================================================================== + def initialize(ds, ccs) + @ds, @ccs = ds, ccs + #‚±‚±‚Åopen‚·‚é + @db = nil + end + def get_char(code_point) + @db.get(code_point) + end + def close + end + end + + class FeatureTable #====================================================================== + def initialize(ds, feature) + @ds, @feature = ds, feature + #‚±‚±‚Åopen‚·‚é + @db = nil + end + def get_value(char_id) + @db.get(char_id) + end + def close + end + end + + class Value #====================================================================== + def initialize(v) + @v = v; + end + def to_s() @v; end + end + +end + +#----------------------------------------------------------------------end.