uniParse.tcl
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:10k
源码类别:

通讯编程

开发平台:

Visual C++

  1. # uniParse.tcl --
  2. #
  3. # This program parses the UnicodeData file and generates the
  4. # corresponding tclUniData.c file with compressed character
  5. # data tables.  The input to this program should be the latest
  6. # UnicodeData file from:
  7. #     ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData-Latest.txt
  8. #
  9. # Copyright (c) 1998-1999 by Scriptics Corporation.
  10. # All rights reserved.
  11. # RCS: @(#) $Id: uniParse.tcl,v 1.4 2001/05/28 04:37:57 hobbs Exp $
  12. namespace eval uni {
  13.     set shift 5; # number of bits of data within a page
  14. # This value can be adjusted to find the
  15. # best split to minimize table size
  16.     variable pMap; # map from page to page index, each entry is
  17. # an index into the pages table, indexed by
  18. # page number
  19.     variable pages; # map from page index to page info, each
  20. # entry is a list of indices into the groups
  21. # table, the list is indexed by the offset
  22.     variable groups; # list of character info values, indexed by
  23. # group number, initialized with the
  24. # unassigned character group
  25.     variable categories {
  26. Cn Lu Ll Lt Lm Lo Mn Me Mc Nd Nl No Zs Zl Zp
  27. Cc Cf Co Cs Pc Pd Ps Pe Pi Pf Po Sm Sc Sk So
  28.     }; # Ordered list of character categories, must
  29. # match the enumeration in the header file.
  30.     variable titleCount 0; # Count of the number of title case
  31. # characters.  This value is used in the
  32. # regular expression code to allocate enough
  33. # space for the title case variants.
  34. }
  35. proc uni::getValue {items index} {
  36.     variable categories
  37.     variable titleCount
  38.     # Extract character info
  39.     set category [lindex $items 2]
  40.     if {[scan [lindex $items 12] %4x toupper] == 1} {
  41. set toupper [expr {$index - $toupper}]
  42.     } else {
  43. set toupper {}
  44.     }
  45.     if {[scan [lindex $items 13] %4x tolower] == 1} {
  46. set tolower [expr {$tolower - $index}]
  47.     } else {
  48. set tolower {}
  49.     }
  50.     if {[scan [lindex $items 14] %4x totitle] == 1} {
  51. set totitle [expr {$index - $totitle}]
  52.     } else {
  53. set totitle {}
  54.     }
  55.     set categoryIndex [lsearch -exact $categories $category]
  56.     if {$categoryIndex < 0} {
  57. puts "Unexpected character category: $index($category)"
  58. set categoryIndex 0
  59.     } elseif {$category == "Lt"} {
  60. incr titleCount
  61.     }
  62.     return "$categoryIndex,$toupper,$tolower,$totitle"
  63. }
  64. proc uni::getGroup {value} {
  65.     variable groups
  66.     set gIndex [lsearch -exact $groups $value]
  67.     if {$gIndex == -1} {
  68. set gIndex [llength $groups]
  69. lappend groups $value
  70.     }
  71.     return $gIndex
  72. }
  73. proc uni::addPage {info} {
  74.     variable pMap
  75.     variable pages
  76.     
  77.     set pIndex [lsearch -exact $pages $info]
  78.     if {$pIndex == -1} {
  79. set pIndex [llength $pages]
  80. lappend pages $info
  81.     }
  82.     lappend pMap $pIndex
  83.     return
  84. }
  85.     
  86. proc uni::buildTables {data} {
  87.     variable shift
  88.     variable pMap {}
  89.     variable pages {}
  90.     variable groups {{0,,,}}
  91.     set info {} ;# temporary page info
  92.     
  93.     set mask [expr {(1 << $shift) - 1}]
  94.     set next 0
  95.     foreach line [split $data n] {
  96. if {$line == ""} {
  97.     set line "FFFF;;Cn;0;ON;;;;;N;;;;;n"
  98. }
  99. set items [split $line ;]
  100. scan [lindex $items 0] %4x index
  101. set index [format 0x%0.4x $index]
  102. set gIndex [getGroup [getValue $items $index]]
  103. # Since the input table omits unassigned characters, these will
  104. # show up as gaps in the index sequence.  There are a few special cases
  105. # where the gaps correspond to a uniform block of assigned characters.
  106. # These are indicated as such in the character name.
  107. # Enter all unassigned characters up to the current character.
  108. if {($index > $next) 
  109. && ![regexp "Last>$" [lindex $items 1]]} {
  110.     for {} {$next < $index} {incr next} {
  111. lappend info 0
  112. if {($next & $mask) == $mask} {
  113.     addPage $info
  114.     set info {}
  115. }
  116.     }
  117. }
  118. # Enter all assigned characters up to the current character
  119. for {set i $next} {$i <= $index} {incr i} {
  120.     # Split character index into offset and page number
  121.     set offset [expr {$i & $mask}]
  122.     set page [expr {($i >> $shift)}]
  123.     # Add the group index to the info for the current page
  124.     lappend info $gIndex
  125.     # If this is the last entry in the page, add the page
  126.     if {$offset == $mask} {
  127. addPage $info
  128. set info {}
  129.     }
  130. }
  131. set next [expr {$index + 1}]
  132.     }
  133.     return
  134. }
  135. proc uni::main {} {
  136.     global argc argv0 argv
  137.     variable pMap
  138.     variable pages
  139.     variable groups
  140.     variable shift
  141.     variable titleCount
  142.     if {$argc != 2} {
  143. puts stderr "nusage: $argv0 <datafile> <outdir>n"
  144. exit 1
  145.     }
  146.     set f [open [lindex $argv 0] r]
  147.     set data [read $f]
  148.     close $f
  149.     buildTables $data
  150.     puts "X = [llength $pMap]  Y= [llength $pages]  A= [llength $groups]"
  151.     set size [expr {[llength $pMap] + [llength $pages]*(1<<$shift)}]
  152.     puts "shift = 6, space = $size"
  153.     puts "title case count = $titleCount"
  154.     set f [open [file join [lindex $argv 1] tclUniData.c] w]
  155.     fconfigure $f -translation lf
  156.     puts $f "/*
  157.  * tclUniData.c --
  158.  *
  159.  * Declarations of Unicode character information tables.  This file is
  160.  * automatically generated by the tools/uniParse.tcl script.  Do not
  161.  * modify this file by hand.
  162.  *
  163.  * Copyright (c) 1998 by Scriptics Corporation.
  164.  * All rights reserved.
  165.  *
  166.  * RCS: @(#) $Id$
  167.  */
  168. /*
  169.  * A 16-bit Unicode character is split into two parts in order to index
  170.  * into the following tables.  The lower OFFSET_BITS comprise an offset
  171.  * into a page of characters.  The upper bits comprise the page number.
  172.  */
  173. #define OFFSET_BITS $shift
  174. /*
  175.  * The pageMap is indexed by page number and returns an alternate page number
  176.  * that identifies a unique page of characters.  Many Unicode characters map
  177.  * to the same alternate page number.
  178.  */
  179. static unsigned char pageMap[] = {"
  180.     set line "    "
  181.     set last [expr {[llength $pMap] - 1}]
  182.     for {set i 0} {$i <= $last} {incr i} {
  183. append line [lindex $pMap $i]
  184. if {$i != $last} {
  185.     append line ", "
  186. }
  187. if {[string length $line] > 70} {
  188.     puts $f $line
  189.     set line "    "
  190. }
  191.     }
  192.     puts $f $line
  193.     puts $f "};
  194. /*
  195.  * The groupMap is indexed by combining the alternate page number with
  196.  * the page offset and returns a group number that identifies a unique
  197.  * set of character attributes.
  198.  */
  199. static unsigned char groupMap[] = {"
  200.     set line "    "
  201.     set lasti [expr {[llength $pages] - 1}]
  202.     for {set i 0} {$i <= $lasti} {incr i} {
  203. set page [lindex $pages $i]
  204. set lastj [expr {[llength $page] - 1}]
  205. for {set j 0} {$j <= $lastj} {incr j} {
  206.     append line [lindex $page $j]
  207.     if {$j != $lastj || $i != $lasti} {
  208. append line ", "
  209.     }
  210.     if {[string length $line] > 70} {
  211. puts $f $line
  212. set line "    "
  213.     }
  214. }
  215.     }
  216.     puts $f $line
  217.     puts $f "};
  218. /*
  219.  * Each group represents a unique set of character attributes.  The attributes
  220.  * are encoded into a 32-bit value as follows:
  221.  *
  222.  * Bits 0-4 Character category: see the constants listed below.
  223.  *
  224.  * Bits 5-7 Case delta type: 000 = identity
  225.  *  010 = add delta for lower
  226.  *  011 = add delta for lower, add 1 for title
  227.  *  100 = sutract delta for title/upper
  228.  *  101 = sub delta for upper, sub 1 for title
  229.  *  110 = sub delta for upper, add delta for lower
  230.  *
  231.  * Bits 8-21 Reserved for future use.
  232.  *
  233.  * Bits 22-31 Case delta: delta for case conversions.  This should be the
  234.  *     highest field so we can easily sign extend.
  235.  */
  236. static int groups[] = {"
  237.     set line "    "
  238.     set last [expr {[llength $groups] - 1}]
  239.     for {set i 0} {$i <= $last} {incr i} {
  240. foreach {type toupper tolower totitle} [split [lindex $groups $i] ,] {}
  241. # Compute the case conversion type and delta
  242. if {$totitle != ""} {
  243.     if {$totitle == $toupper} {
  244. # subtract delta for title or upper
  245. set case 4
  246. set delta $toupper
  247.     } elseif {$toupper != ""} {
  248. # subtract delta for upper, subtract 1 for title
  249. set case 5
  250. set delta $toupper
  251.     } else {
  252. # add delta for lower, add 1 for title
  253. set case 3
  254. set delta $tolower
  255.     }
  256. } elseif {$toupper != ""} {
  257.     # subtract delta for upper, add delta for lower
  258.     set case 6
  259.     set delta $toupper
  260. } elseif {$tolower != ""} {
  261.     # add delta for lower
  262.     set case 2
  263.     set delta $tolower
  264. } else {
  265.     # noop
  266.     set case 0
  267.     set delta 0
  268. }
  269. set val [expr {($delta << 22) | ($case << 5) | $type}]
  270. append line [format "%d" $val]
  271. if {$i != $last} {
  272.     append line ", "
  273. }
  274. if {[string length $line] > 65} {
  275.     puts $f $line
  276.     set line "    "
  277. }
  278.     }
  279.     puts $f $line
  280.     puts $f "};
  281. /*
  282.  * The following constants are used to determine the category of a
  283.  * Unicode character.
  284.  */
  285. #define UNICODE_CATEGORY_MASK 0X1F
  286. enum {
  287.     UNASSIGNED,
  288.     UPPERCASE_LETTER,
  289.     LOWERCASE_LETTER,
  290.     TITLECASE_LETTER,
  291.     MODIFIER_LETTER,
  292.     OTHER_LETTER,
  293.     NON_SPACING_MARK,
  294.     ENCLOSING_MARK,
  295.     COMBINING_SPACING_MARK,
  296.     DECIMAL_DIGIT_NUMBER,
  297.     LETTER_NUMBER,
  298.     OTHER_NUMBER,
  299.     SPACE_SEPARATOR,
  300.     LINE_SEPARATOR,
  301.     PARAGRAPH_SEPARATOR,
  302.     CONTROL,
  303.     FORMAT,
  304.     PRIVATE_USE,
  305.     SURROGATE,
  306.     CONNECTOR_PUNCTUATION,
  307.     DASH_PUNCTUATION,
  308.     OPEN_PUNCTUATION,
  309.     CLOSE_PUNCTUATION,
  310.     INITIAL_QUOTE_PUNCTUATION,
  311.     FINAL_QUOTE_PUNCTUATION,
  312.     OTHER_PUNCTUATION,
  313.     MATH_SYMBOL,
  314.     CURRENCY_SYMBOL,
  315.     MODIFIER_SYMBOL,
  316.     OTHER_SYMBOL
  317. };
  318. /*
  319.  * The following macros extract the fields of the character info.  The
  320.  * GetDelta() macro is complicated because we can't rely on the C compiler
  321.  * to do sign extension on right shifts.
  322.  */
  323. #define GetCaseType(info) (((info) & 0xE0) >> 5)
  324. #define GetCategory(info) ((info) & 0x1F)
  325. #define GetDelta(info) (((info) > 0) ? ((info) >> 22) : (~(~((info)) >> 22)))
  326. /*
  327.  * This macro extracts the information about a character from the
  328.  * Unicode character tables.
  329.  */
  330. #define GetUniCharInfo(ch) (groups[groupMap[(pageMap[(((int)(ch)) & 0xffff) >> OFFSET_BITS] << OFFSET_BITS) | ((ch) & ((1 << OFFSET_BITS)-1))]])
  331. "
  332.     close $f
  333. }
  334. uni::main
  335. return