mapper.sa


Generated by gen_html_sa_files from ICSI. Contact gomes@icsi.berkeley.edu for details
 
------------------------->  GNU Sather - sourcefile  <-------------------------
-- Copyright (C) 2000 by K Hopper, University of Waikato, New Zealand        --
-- This file is part of the GNU Sather library. It is free software; you may --
-- redistribute  and/or modify it under the terms of the GNU Library General --
-- Public  License (LGPL)  as published  by the  Free  Software  Foundation; --
-- either version 2 of the license, or (at your option) any later version.   --
-- This  library  is distributed  in the  hope that it will  be  useful, but --
-- WITHOUT ANY WARRANTY without even the implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE. See Doc/LGPL for more details.       --
-- The license text is also available from:  Free Software Foundation, Inc., --
-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                     --
-------------->  Please email comments to <bug-sather@gnu.org>  <--------------


class CODE_MAPPER < $CODE_MAPPER

class CODE_MAPPER < $CODE_MAPPER is -- This class defines a code mapper which uses data obtained from a file -- in order to carry out code conversions. -- The structure of a map file is as follows :- -- -- (1) A header starting with a magic number 0xb827. -- (see the MAP_HEADER class for further details). -- -- (2) A number of code 'sections' each of which starts with a single -- octet containing the key bit count (eg 8, 16, 32). If, however, -- the 'size' is zero then the next following octet determines the -- structure which follows :- -- -- a. If zero then the end of the map file has been reached. -- -- b. Otherwise it is followed by the following four single -- octets - -- -- source count -- storage method for the section -- key value -- initial target value -- -- If the size was non-zero (ie a valid size) then the section header -- continues with the following three octets - -- -- codes per key -- target size in bits -- codes per target value -- The kinds of storage method for each section has its own structure -- as given in the following sub-paragraphs :- -- -- (1) Key Value pairs - as many simple pairs in the appropriate code -- sizes as indicated by the count. -- -- (2) All keys followed by all target values - up to the specified -- count. -- -- (3) Partial key value 'list' - a number of sub-sections determined -- by the first 'count' octet. However, if this is null and the next -- following octet is null then the end of the current section has been -- reached. If the 'count' octet is non-null then section data follows -- in one of two forms for both of which the keys are 'compressed' into -- contiguous key ranges. The target values appear in one of two -- forms :- -- -- a. Target values 'compressed' - this form begins with a count -- octet for a target value range. If this is null and is followed -- by a further null octet then the section has finished. If the -- count is non-null then data follows. First there is a target -- value count which must be less than or equal to the key count. -- After this there is a target start of range value (in the number -- of octets for the map target). -- -- b. Target value NOT 'compressed' - this consists of a sequence -- of key count target code values (each of the appropriate number -- of octets). -- Version 1.0 Oct 98. Copyright K Hopper, U of Waikato -- Development History -- ------------------- -- Date Who By Detail -- ---- ------ ------ -- 30 Oct 98 kh Original after a Perl script include BINARY ; private const Max_Count : CARD := OCTET::Octet_Max ; -- largest partial chunk! private const Default_Section : MAP_PARTS := MAP_PARTS::Infinite ; private const Default_Method : MAP_MODES := MAP_MODES::Alternate_Key_Val ; private const Default_Key_Compression : BOOL := true ; private const Default_Value_Compression : BOOL := true ; private const Default_Key_Comp_Val : CARD := 11 ; -- from file format def! private const Default_Value_Comp_Val : CARD := 14 ; private const Default_Value_No_Comp_Val : CARD := Default_Value_Comp_Val - 1 ; private const Codes_per_Entry : CARD := 1 ; -- always seem to be one here!??? private const Unicodes_per_Entry : CARD := 1 ; private attr header : MAP_HEADER ; readonly attr section : MAP_PARTS ; -- the initial values! readonly attr method : MAP_MODES ; readonly attr key_compression : BOOL ; readonly attr value_compression : BOOL ; readonly attr kind : CODE_KINDS ; private attr to_map : FMAP{CARD,CARD} ; -- to Unicode code value private attr from_map : FMAP{CARD,CARD} ; -- from Unicode code value private attr loc_lib : LIBCHARS ; -- local code dummy private attr uni_lib : LIBCHARS ; -- either a UCS2 or Unicode dummy private attr codes_per_key : CARD ; private attr codes_per_value : CARD ; private attr sizes_done : BOOL ; -- The above four values are fixed for any one map - so are treated as -- map attributes. insert( non_code : CARD, uni_code : CARD ) pre ~void(self) and ~to_map.test(non_code) and ~from_map.test(uni_code) post (to_map.size = (initial(to_map.size) + 1)) and(from_map.size = (initial(from_map.size) + 1)) and from_map.test(uni_code) and to_map.test(non_code) is -- This private routine is provided to produce the to and from map -- entries from the two codes. to_map := to_map.insert(non_code,uni_code) ; from_map := from_map.insert(uni_code,non_code) end ; private is_end_marker( cursor : BIN_CURSOR ) : BOOL pre ~void(cursor) and ~cursor.is_done post true is -- This private routine tests if the next two octets on the file are -- null, which signifies the end of the current section when true is -- returned, otherwise false and the count parameter is valid. loc_val : OCTET := cursor.get_item ; if loc_val = OCTET::null and cursor.item = OCTET::null then -- yes! cursor.advance ; -- over the mark! cursor.advance ; -- and the 'length' flag return true else cursor.retract ; return false end end ; private handle_param( cursor : BIN_CURSOR ) pre ~void(cursor) post true is -- This routine obtains the next octet from the indicated string and, -- dependent on value, sets one of the map arguments. if cursor.is_done then -- Oops! run off the end! SYS_ERROR::create.error(self, SYS_EXCEPT::Bad_Map,header.code_name.str) end ; loc_code : CARD := cursor.get_item.card ; if loc_code <= MAP_PARTS::cardinality - 1 then section := MAP_PARTS::create(loc_code + 1) elsif loc_code <= MAP_MODES::Partial_Key_Val_Map.card then method := MAP_MODES::create(loc_code) elsif loc_code <= Default_Key_Comp_Val then key_compression := (loc_code = Default_Key_Comp_Val) elsif loc_code <= Default_Value_Comp_Val then value_compression := (loc_code = Default_Value_Comp_Val) else -- a real problem in the file SYS_ERROR::create.error(self,SYS_EXCEPT::Bad_Map,loc_code.str) end ; cursor.advance ; -- past the third (null) octet! return end ; private set_compressed( cursor : BIN_CURSOR, inout key_count : CARD, inout key_start : CARD ) : BOOL pre ~void(cursor) and ~cursor.is_done and (key_count > 0) post ~result or (from_map.size > initial(from_map.size)) is -- This private routine is used to set a section of the map for which -- values are 'compressed'. It returns true if successful or false if there -- has been a file format error. value_count : CARD := cursor.get_item.card ; value_start : CARD := CARD::create(cursor.get_upto(uni_lib.my_size)) ; if value_start = CHAR_CODE::invalid.card then return false end ; loop -- which sets up the maps value_count.times! ; insert(key_start,value_start) ; key_start := key_start + 1 ; value_start := value_start + 1 end ; key_count := key_count - value_count ; return true end ; private set_uncompressed( cursor : BIN_CURSOR, inout key_count : CARD, inout key_start : CARD ) : BOOL pre ~void(cursor) and ~cursor.is_done post (from_map.size = initial(from_map.size) + key_count) is -- This private routine sets a section of the map for which no value -- compression is used. loop -- over values to set maps key_count.times! ; if cursor.is_done then return false end ; insert(key_start,CARD::create( cursor.get_upto(uni_lib.my_size))) ; key_start := key_start + 1 end ; return true end ; private get_partial_section( cursor : BIN_CURSOR ) : BOOL pre ~void(cursor) and ~cursor.is_done post result or (cursor.index = initial(cursor.index)) is -- This private routine extracts a partial map from the mapping file, -- returning true if no error occurred. loc_section : MAP_PARTS ; loc_method : MAP_MODES ; loc_key_comp : BOOL ; loc_value_comp : BOOL ; start_index : CARD := cursor.index ; loop -- over the sub-sections! if cursor.is_done then -- run off the end! cursor.set_index(start_index) ; return false end ; loc_section := section ; -- save state! loc_method := method ; loc_key_comp := key_compression ; loc_value_comp := value_compression ; if is_end_marker(cursor) then break! -- state has not been altered! else -- it's a partial count! key_count : CARD := cursor.get_item.card ; key_start : CARD := CARD::create( cursor.get_upto(loc_lib.my_size)) ; if key_start = CHAR_CODE::invalid.card then cursor.set_index(start_index) ; return false end ; loop -- over the key values while!(key_count > 0) ; if loc_value_comp then -- using value 'compression' if ~set_compressed(cursor, inout key_count, inout key_start) then cursor.set_index(start_index) ; return false end else -- not using value compression if ~set_uncompressed(cursor,inout key_count, inout key_start) then cursor.set_index(start_index) ; return false end end end end ; section := loc_section ; -- restore original state method := loc_method ; key_compression := loc_key_comp ; value_compression := loc_value_comp end ; return true end ; private get_pairs_section( cursor : BIN_CURSOR ) : BOOL pre ~void(cursor) and ~cursor.is_done post (from_map.size > initial(from_map.size)) is -- This private routine sets the map from adjacent pairs of key then -- value in the file. first : BOOL := true ; loop if cursor.is_done then -- this should never happen! return false end ; if ~first and is_end_marker(cursor) then cursor.advance ; -- past the final flag return true end ; key_val : CARD := CARD::create(cursor.get_upto(loc_lib.my_size)) ; value_val : CARD := CARD::create(cursor.get_upto(uni_lib.my_size)) ; if first then first := false end ; insert(key_val,value_val) end end ; private get_twin_lists_section( cursor : BIN_CURSOR ) : BOOL pre ~void(cursor) and ~cursor.is_done and (codes_per_key = codes_per_value) post (from_map.size > initial(from_map.size)) is -- This routine handles a mapfile section which is in the form of two -- lists in sequence, first the key list, then the value list. return false -- NOT YET IMPLEMENTED! end ; private section_header( cursor : BIN_CURSOR ) : BOOL pre ~void(cursor) and ~cursor.is_done post true is -- This routine looks for a section header at the currently indicated -- buffer position. The expected form is one or more of the following - -- -- A leading null octet followed by a section kind octet & null octet -- A leading null octet followed by a method octet and trailing null loop if (cursor.item = OCTET::null) then -- it is a header component cursor.advance ; if cursor.item = OCTET::null then cursor.advance ; -- past the third null!! return false else handle_param(cursor) end else return true end end end ; private get_sizes( cursor : BIN_CURSOR ) is -- This private routine retrieves the size key and code size data from -- the map file - after the first section header. key_octets : CARD := (cursor.get_item.card + (OCTET::Octet_Bits - 1)) / OCTET::Octet_Bits ; if key_octets /= loc_lib.my_size then SYS_ERROR::create.error(self, SYS_EXCEPT::Bad_Map,header.code_name.str) end ; codes_per_key := cursor.get_item.card ; value_octets : CARD := (cursor.get_item.card + (OCTET::Octet_Bits - 1)) / OCTET::Octet_Bits ; if value_octets = CODE_KINDS::Unicode.size then uni_lib := LIBCHARS::default.dummy_lib(CODE_KINDS::Unicode) elsif value_octets = CODE_KINDS::UCS2.size then uni_lib := LIBCHARS::default.dummy_lib(CODE_KINDS::UCS2) end ; codes_per_value := cursor.get_item.card ; end ; private retrieve_section( cursor : BIN_CURSOR, out is_end : BOOL ) : BOOL pre ~void(cursor) and ~cursor.is_done post ~result or (from_map.size > initial(from_map.size)) is -- This private routine handles each section of the map file, inserting -- appropriate elements of the maps. start_index : CARD := cursor.index ; if ~section_header(cursor) then is_end := (cursor.index /= start_index) ; return false end ; if codes_per_key = 0 then -- they must be here if not get_sizes(cursor) end ; case method when MAP_MODES::Alternate_Key_Val then if ~get_pairs_section(cursor) then return false end when MAP_MODES::All_Keys_All_Vals then -- not yet implemented if ~get_twin_lists_section(cursor) then return false end when MAP_MODES::Partial_Key_Val_Map then if (section = MAP_PARTS::Infinite) or (codes_per_key /= 1) or (codes_per_value /= 1) then -- not yet implemented! return false end ; if ~get_partial_section(cursor) then return false end else -- there is a file format error! return false end ; return true end ; build( cursor : BIN_CURSOR ) : SAME pre ~void(self) and ~void(cursor) post true is -- This routine builds a new mapper from the indicated binary string. start_index : CARD := cursor.index ; is_end : BOOL := false ; header := MAP_HEADER::build(cursor) ; if void(header) then -- failed miserably! return void else -- OK to initialise section := Default_Section ; method := Default_Method ; key_compression := Default_Key_Compression ; value_compression := Default_Value_Compression end ; loop -- over the rest of the file! if cursor.is_done then -- shouldn't really get here!!!!! break! end ; loc_section : MAP_PARTS := section ; -- save state for this pass loc_method : MAP_MODES := method ; loc_key_comp : BOOL := key_compression ; loc_value_comp : BOOL := value_compression ; if ~retrieve_section(cursor,out is_end) then if is_end then break! else cursor.set_index(start_index) ; return void end end ; section := loc_section ; -- restore state! method := loc_method ; key_compression := loc_key_comp ; value_compression := loc_value_comp end ; return self end ; create( kind : CODE_KINDS ) : SAME pre ~void(kind) post ~void(result) is -- This routine returns an empty mapper for the given code keys -- using the UCS2 code as default output. me : SAME := new ; me.key_compression := Default_Key_Compression ; me.value_compression := Default_Value_Compression ; me.kind := kind ; me.loc_lib := LIBCHARS::default.dummy_lib(kind) ; me.uni_lib := me.loc_lib.dummy_lib(CODE_KINDS::UCS2) ; me.to_map := FMAP{CARD,CARD}::create ; me.from_map := FMAP{CARD,CARD}::create ; return me end ; create( kind : CODE_KINDS, unicode : BOOL ) : SAME pre ~void(kind) post ~void(result) is -- This routine returns an empty mapper for the given code keys using -- Unicode or UCS2 code as output. me : SAME := new ; me.key_compression := Default_Key_Compression ; me.value_compression := Default_Value_Compression ; me.kind := kind ; me.loc_lib := LIBCHARS::default.dummy_lib(kind) ; if unicode then me.uni_lib := me.loc_lib.dummy_lib(CODE_KINDS::Unicode) else me.uni_lib := me.loc_lib.dummy_lib(CODE_KINDS::UCS2) end ; me.to_map := FMAP{CARD,CARD}::create ; me.from_map := FMAP{CARD,CARD}::create ; return me end ; create( kind : CODE_KINDS, loc_path : FILE_PATH ) : SAME pre ~void(loc_path) post ~void(result) -- or exception has been raised! is -- This routine returns a mapper created from the mapping file whose -- path name is given. fyle : BIN_FILE := BIN_FILE::open_for_read(loc_path.str) ; raiser : SYS_ERROR := SYS_ERROR::create ; if void(fyle) then -- fatal error! raiser.error(create(kind),SYS_EXCEPT::Bad_Name,loc_path.str) elsif fyle.error then raiser.file_error(create(kind),fyle) end ; loc_cursor : BIN_CURSOR := fyle.buffer.binstr.cursor ; fyle.close ; me : SAME := create(kind) ; me := me.build(loc_cursor) ; if void(me) then raiser.error(create(kind),SYS_EXCEPT::Bad_Map,loc_path.str) ; return void -- to keep the compiler happy else return me end end ; set_header( val : MAP_HEADER ) pre ~void(self) and ~void(val) and void(header) post ~void(header) is -- This private routine sets the header of the map - providing that it -- is not yet valid! header := val end ; private adjacent( first : CARD, second : CARD ) : BOOL is -- This private routine returns true if and only if the second argument -- follows the first and differs only in the final code by one - using -- a numeric interpretation of the codes. return (first + 1) = second end ; private chunk_size( vals : ARRAY{CARD}, start_index : CARD ) : CARD pre ~void(vals) and (start_index < vals.size) post (result > 0) is -- Given the sorted key array and a start index this routine seeks for -- an element which is -- -- (1) not adjacent to the previous element in sequence or -- -- (2) there is an element of a different size or -- -- (3) there are 255 adjacent elements or -- -- (4) the end of the array has been reached -- -- returning the number of elements scanned. loc_index : CARD := start_index ; count : CARD := 0 ; loop if loc_index = vals.size then -- singleton last element! return count + 1 elsif count = Max_Count then -- maximum partial chunk! return count elsif ((loc_index + 1) = vals.size) then -- no more to compare! return count + 1 elsif adjacent(vals[loc_index],vals[loc_index + 1]) then loc_index := loc_index + 1 ; count := count + 1 else return count + 1 end end end ; private card_bin( val : CARD, size : CARD ) : BINSTR pre (size >= ((NUM_BITS::create(val).highest / OCTET::Octet_Bits) + 1)) post result.size = size is -- This private routine produces a binary representation of the given -- value using the given number of octets - providing, of course, that -- the pre-condition is met. return val.binstr.tail(size) end ; private param_to_bin( param_code : CARD ) : BINSTR pre true post result.size = 3 is -- This routine prepares a binary representation of the given code, -- surrounding it with null octets, before returning it. return BINSTR::create + OCTET::null + OCTET::create(param_code) + OCTET::null end ; private partial_representation( sect_fixed_hdr : BINSTR, vals : ARRAY{CARD}, val_start : CARD, tally : CARD ) : BINSTR pre ~void(vals) and (tally > 0) post true is -- This private routine builds the binary representation of a code map -- section containing a sequence of values of length tally. res : BINSTR := BINSTR::create + param_to_bin(MAP_MODES::Partial_Key_Val_Map.card) ; if value_compression then res := res + param_to_bin(Default_Value_No_Comp_Val) end ; if ~void(sect_fixed_hdr) then res := res + sect_fixed_hdr end ; res := res + OCTET::create(tally) ; loop loc_code : CARD := vals.elt!(val_start,tally) ; res := res + card_bin(loc_code,uni_lib.my_size) end ; return res end ; private singleton( sect_fixed_hdr : BINSTR, keys : ARRAY{CARD}, vals : ARRAY{CARD}, key_index : CARD, val_index : CARD ) : BINSTR pre ~void(keys) and ~void(vals) post true is -- This private routine builds the binary representation of a singleton -- code map section res : BINSTR := BINSTR::create + param_to_bin(MAP_MODES::Alternate_Key_Val.card) ; if ~void(sect_fixed_hdr) then res := res + sect_fixed_hdr end ; res := res + OCTET::create(key_index) + OCTET::create(val_index) ; res := res + card_bin(keys[key_index],loc_lib.my_size) + card_bin(vals[val_index],uni_lib.my_size) ; return res end ; private try_compression( sect_fixed_hdr : BINSTR, vals : ARRAY{CARD}, val_count : CARD, val_index : CARD ) : BINSTR pre ~void(vals) and (val_count > 0) post true is -- This private routine builds the binary representation of one section -- of the map. res : BINSTR := BINSTR::create + param_to_bin(MAP_MODES::Partial_Key_Val_Map.card) ; if ~value_compression then res := res + param_to_bin(Default_Value_Comp_Val) end ; res := res + sect_fixed_hdr + OCTET::create(val_count) + card_bin(vals[val_index],uni_lib.my_size) ; return res end ; private build_section( sect_fixed_hdr : BINSTR, keys : ARRAY{CARD}, vals : ARRAY{CARD}, key_start : CARD, key_count : CARD ) : BINSTR pre ~void(keys) and ~void(vals) and (key_count > 0) post true is -- This private routine builds the binary representation of one section -- of the map. val_start : CARD := 0 ; key_bin : BINSTR := keys[key_start].binstr ; -- the actual code value! res : BINSTR := BINSTR::create + OCTET::create(key_count) + key_bin.tail(loc_lib.my_size) ; val_index : CARD := val_start ; key_index : CARD := key_start ; loop -- over the keys val_count : CARD := chunk_size(vals,val_start) ; if val_count > 1 then -- can 'compress' if ~void(sect_fixed_hdr) then res := BINSTR::create + sect_fixed_hdr + res end ; res := try_compression(res,vals,val_count,val_index) ; val_start := val_index + val_count ; val_index := val_start else -- just tally count of singles loc_start : CARD := val_start ; loop -- the tally loop while!((val_count = 1) and (loc_start < vals.size)) ; val_count := chunk_size(vals,loc_start) ; loc_start := loc_start + 1 end ; tally : CARD := loc_start - val_start ; if tally = 1 then -- just like a single key! res := res + singleton(sect_fixed_hdr,keys,vals, key_index,val_index) else res := res + partial_representation(sect_fixed_hdr, vals,val_start,tally) end ; key_start := key_start + tally ; key_index := key_start ; val_start := val_start + tally ; val_index := val_start end ; if val_start = key_count then return res end end end ; private section_to_bin( keys : ARRAY{CARD}, key_start : CARD, key_count : CARD ) : BINSTR pre ~void(keys) and (key_count > 0) post true is -- This routine constructs a single binary string consisting of the -- mapping file format of count elements from the from_map. There are three -- cases - -- -- (1) There is a single element. -- -- (2) There are chunks of value which are adjacent. -- -- (3) There are no adjacent values. res : BINSTR := BINSTR::create ; fixed_hdr : BINSTR ; val_index : CARD := 0 ; vals : ARRAY{CARD} := ARRAY{CARD}::create(key_count) ; loop -- to fill in value codes vals.set!(to_map.get(keys.elt!(key_start))) end ; if sizes_done then fixed_hdr := void else sizes_done := true ; fixed_hdr := BINSTR::create + param_to_bin(MAP_PARTS::Byte_Size.card - 1) ; -- File format section header - note the 'special' (-1) -- for the map part! fixed_hdr := fixed_hdr + OCTET::create(loc_lib.my_size * OCTET::Octet_Bits) + OCTET::create(Codes_per_Entry) + OCTET::create(uni_lib.my_size * OCTET::Octet_Bits) + OCTET::create(Unicodes_per_Entry) end ; if key_count = 1 then res := res + param_to_bin(MAP_MODES::Alternate_Key_Val.card) ; if ~void(fixed_hdr) then res := res + fixed_hdr end ; res := res + card_bin(keys[key_start],loc_lib.my_size) + card_bin(vals[val_index],uni_lib.my_size) else res := build_section(fixed_hdr,keys,vals,key_start,key_count) end ; res := res + param_to_bin(0) ; -- the end marker! return res end ; binstr : BINSTR pre ~void(self) post ~void(result) is -- This routine returns a binary string representation of self suitable -- for filing. Note that this always produces the binary string in Partial -- mode and (up to) 255 pair chunks. sizes_done := false ; key_array : ARRAY{CARD} := ARRAY{CARD}::create(to_map.size) ; res : BINSTR := BINSTR::create ; res := res + header.binstr ; -- First fill in and then sort the keys into ascending order. loop key_array.set!(to_map.keys!) end ; key_array.sort ; -- The following loop divides up into chunks which are then -- converted to binary strings and concatenated onto the end of res. loc_start : CARD := 0 ; -- initialise loop loop if loc_start = key_array.size then break! end ; -- first the section header loc_count : CARD := chunk_size(key_array,loc_start) ; if loc_count > OCTET::Octet_Max then loc_count := OCTET::Octet_Max end ; res := res + section_to_bin(key_array,loc_start,loc_count) ; loc_start := loc_start + loc_count end ; res := res + param_to_bin(0) ; -- the null octet end marker return res end ; to_unicode( ch_code : CHAR_CODE ) : CHAR_CODE pre ~void(self) and (ch_code.lib.culture.kind = loc_lib.culture.kind) and ~ch_code.char.is_control post result.lib.has_combining is -- This routine is designed to convert the single code given into -- a Unicode encoding using this mapping table. Note that the has_combining -- property indicates that no conversion is needed. res : CHAR_CODE ; if ch_code.lib.has_combining then res := ch_code else res := CHAR_CODE::create(to_map.get(ch_code.card),uni_lib) end ; return res end ; from_unicode( ch_code : CHAR_CODE ) : CHAR_CODE pre ~void(self) and ch_code.lib.has_combining post ~result.char.is_control and ~result.lib.has_combining is -- This routine is designed to convert the single code given into -- a single character using this mapping table. if from_map.test(ch_code.card) then return CHAR_CODE::create(from_map.get(ch_code.card),loc_lib) else return void end end ; from_unicode( ch_code : CHAR_CODE, lib : LIBCHARS ) : CHAR_CODE pre ~void(self) and ~void(lib) and ~ch_code.lib.has_combining post void(result) or ~result.char.is_control is -- This routine is designed to convert the single code given into -- a single character using this mapping table. if from_map.test(ch_code.card) then return CHAR_CODE::create(from_map.get(ch_code.card),lib) else return void end end ; end ; -- CODE_MAPPER