!=========================================================================
! Copyright (C) VMware, Inc. 1986-2011.  All Rights Reserved.
!
! $Id: unicode.gs,v 1.5 2008-01-09 22:50:20 stever Exp $
!
! Superclass Hierarchy:
!   UnicodeData, Object.
!
!=========================================================================

! UnicodeData is a "goodies" class to support operations on the
! Unicode standards database.  This class is also used internally
! by VMware Inc to generate C code for the default
! character mapping tables.

doit
Object subclass: 'UnicodeData'
  instVarNames: #( id name category
                    combineClass bidiClass decompType decompMap
                    decDigit digit number bidiMirrored
                    unicode1Name isoComment upperCase lowerCase
                    titleCase dispatchId collateId collatePrevious
                    collateNext)
  classVars: #( CollateEnd File MAX_ENTRY SortedTable Table)
  classInstVars: #()
  poolDictionaries: #[]
  inDictionary: Globals
  constraints: #[  ]
  instancesInvariant: false
  isModifiable: false

%

! Remove existing behavior from UnicodeData
doit
UnicodeData removeAllMethods.
UnicodeData class removeAllMethods.
%
! ------------------- Class methods for UnicodeData
category: 'Reading'
classmethod: UnicodeData
_upToSeparator: stream

" Scans through stream and returns next substring up to separator character 
';' (or end of line ) "

| s c parsing |
parsing := true.
s := String new.
[ parsing ] whileTrue: [
    stream atEnd ifTrue: [ ^ s ].
    c := stream next.
    ( c = $; ) ifTrue: [ ^ s ].
    ( c == ( Character lf ) ) ifTrue: [ ^ s ].
    s add: c ]
%
category: 'Collate'
classmethod: UnicodeData
calculateCollation

self clearCollateLinks.
self calculateCollationSequence.
self calculateCollationIds.
%
category: 'Collate'
classmethod: UnicodeData
calculateCollationIds

" Once the collation linked list chain has been established, this method 
  scans down the linked list and generates SortedTable in the correct order. "

| id tableSize entry  |

SortedTable := Array new.
Table do: [ :entry | entry == nil ifFalse: [ entry collateId: nil ] ].

id := 0.
entry := Table at: 1.
[ entry == nil ] whileFalse: [ 
    SortedTable add: entry.
    entry collateId: id.
    id := id + 1.
    entry := entry collateNext ].

" Now scan for errors "
Table do: [ :entry |
    entry == nil ifFalse: [
        entry collateId == nil ifTrue: [ 
            self halt: 'Missing collate index' ] ] ]
%
category: 'Collate'
classmethod: UnicodeData
calculateCollationSequence

" Collation sequence is handled using a linked list chain on the collateNext
  instvar, with class variable CollateEnd tracking the end of the chain.  
  Following code generates the link list chain. "

| tableSize entry entryBaseU  |
GsFile stdout log: 'Now doing calculateCollation.'.
tableSize := Table size.

entry := Table at: 1.
CollateEnd := entry.

2 to: tableSize do: [ :i |
    entry := Table at: i.
    entry == nil ifFalse: [
        entry isLetter 
            ifFalse: [ 
                entry collatePrevious: CollateEnd.
                CollateEnd collateNext: entry.
                CollateEnd := entry ]
            ifTrue: [ 
                entryBaseU := entry baseUpper.
                ( entryBaseU = entry ) 
                    ifTrue: [
                        entry collatePrevious: CollateEnd.
                        CollateEnd collateNext: entry.
                        CollateEnd := entry collateEnd ]
                    ifFalse: [
                        entryBaseU collate: entry ] ] ] ].

" All done, save results "

System commitTransaction ifFalse: [ self halt: 'Problem committing..' ]
%
category: 'Collate'
classmethod: UnicodeData
clearCollateLinks

" Clears the collation linked list chains in preparation for a new collation "

| tableSize entry id cat map mapEntry baseIndex baseEntry x |
tableSize := Table size.
SortedTable := nil.
CollateEnd := nil.
1 to: tableSize do: [ :i |
    entry := Table at: i.
    entry == nil ifFalse: [
        entry collatePrevious: nil.
        entry collateNext: nil ] ]
%
category: 'Accessing'
classmethod: UnicodeData
CollateEnd

    ^ CollateEnd
%
category: 'Accessing'
classmethod: UnicodeData
CollateEnd: entry

    CollateEnd := entry
%
category: 'Collate'
classmethod: UnicodeData
collateOrder

" Generate an array in collation order "

    | result entry |
    result := Array new.
    entry := Table at: 1.
    [ entry == nil ] whileFalse: [
        result add: entry.
        entry := entry collateNext ].
    ^ result
%
category: 'Accessing'
classmethod: UnicodeData
File

^ File
%
category: 'Misc'
classmethod: UnicodeData
findGaps

"Scan through Table and report regions with no entries "
| gap tally start stop |
gap := false.
tally := 0.
1 to: Table size do: [ :i |
    ( Table at: i ) == nil 
    ifTrue: [
        tally := tally + 1.
        gap ifFalse: [ 
            gap := true.
            start := i - 1 ] ]
    ifFalse: [
        gap ifTrue: [
            gap := false.
            stop := i - 2.
            GsFile stdout log: 
                'From ' + ( start printString ) + 
                ' to ' + ( stop printString ) + 
                ' total: ' + ( ( stop - start + 1 ) printString )  ] ] ].
GsFile stdout log: 'Total empty entries: ' + ( tally printString )
%
category: 'Reading'
classmethod: UnicodeData
fromHexString: string

string size == 0 ifTrue: [ ^ nil ].
^ Integer fromHexString: string
%
category: 'Reading'
classmethod: UnicodeData
fromIntegerString: string

string size == 0 ifTrue: [ ^ nil ].
^ Integer fromString: string
%
category: 'Reading'
classmethod: UnicodeData
fromMultiHexString: string

| size data element i c s|
size := string size.
size == 0 ifTrue: [ ^ nil ].
data := Array new.
i := 1.
[ i <= size ] whileTrue: [ 
    s := String new.
    [ ( i <= size ) _and: [ c := string at: i.  self isHexDigit: c ] ] 
    whileTrue: [  
        s add: c.
        i := i + 1. ].
    data add: ( Integer fromHexString: s ).
    i := i + 1 ].
^ data
%
category: 'Main Operations'
classmethod: UnicodeData
generateCode: fileName

" Generate C code for internal Unicode data.

  This code is used by GemStone System Inc. to generate C code 
  for the internal default character data tables. "

| tableSize sortedSize titleCaseEntries count n COMMENTS |

COMMENTS := true.  " set to true to generate comment fields "
GsFile stdout log: 'Generating C output file..'.
File == nil ifFalse: [ File close ].
File := GsFile openWrite: fileName.
tableSize := Table size.
sortedSize := SortedTable size.
titleCaseEntries := 
    SortedTable select: [ :entry | ( entry upperCase ) ~= ( entry titleCase ) ].

" Generate header info "
File log: '/*  Contents generated from UnicodeData(class)>>generateCode: */'.
File cr.
File cr.
File nextPutAll: 'static long XCharDispatchTableSize =  '.
File nextPutAll: tableSize printString.
File log: ';'.
File cr.
File nextPutAll: 'static long XCharTableSize = '.
File nextPutAll: sortedSize printString.
File log: ';'.
File cr.
File nextPutAll: 'static long XCharTitleCaseTableSize = '.
File nextPutAll: titleCaseEntries size printString.
File log: ';'.
File cr.

" First, generate dispatch table "
File nextPutAll: 'static unsigned short defaultDispatchTable[ ] = { '.
File cr.
count := 0.
Table do: [ :entry | 
    count := count + 1.
    entry == nil 
      ifTrue: [
        File nextPutAll: '0, ' ]
      ifFalse: [ 
        File nextPutAll: entry collateId printString.
        ( count < tableSize ) ifTrue: [ File nextPutAll: ', ' ] ].
    ( ( count \\ 10 ) == 0 ) ifTrue: [ File cr ] ].
File log: '};'. File cr. File cr.

" Now generate Index Table "
File nextPutAll: 'static unsigned short defaultIndexTable[ ] = {'.
File cr.
count := 0.
SortedTable do: [ :entry |
    count := count + 1.
    File nextPutAll: ( entry id asString ).
    ( count < sortedSize ) ifTrue: [ File nextPutAll: ', ' ].
    ( ( count \\ 10 ) == 0 ) ifTrue: [ File cr ] ].
File log: '};'.  File cr. File cr.

" Now generate Category Table "
File nextPutAll: 'static ByteType defaultCategoryTable[ ] = {'.
File cr.
count := 0.
SortedTable do: [ :entry |
    count := count + 1.
    File nextPutAll: ( entry categoryId asString ).
    ( count < sortedSize ) ifTrue: [ File nextPutAll: ', ' ].
    ( ( count \\ 10 ) == 0 ) ifTrue: [ File cr ] ].
File log: '};'.  File cr. File cr.

" Now generate Main Data table "
File nextPutAll: 'static XCharEntrySType defaultEntryTable[ ] = { '.
File cr.
count := 0.
SortedTable do: [ :entry |
    count := count + 1.
    File nextPutAll: ' {'.
    ( entry category first = $L )
    ifTrue: [ 
        entry upperCase == nil
            ifTrue: [ File nextPutAll: '0' ]
            ifFalse: [ File nextPutAll: ( entry upperCase id printString ) ].
        File nextPutAll: ', '.
        entry lowerCase == nil
            ifTrue: [ File nextPutAll: '0' ]
            ifFalse: [ File nextPutAll: ( entry lowerCase id printString ) ] ]
    ifFalse: [
        ( entry category first = $N )
            ifTrue: [
                n := entry number.
                ( n isKindOf: Fraction )
                    ifTrue: [
                        File nextPutAll: ( n numerator printString ).
                        File nextPutAll: ', '.
                        File nextPutAll: ( n denominator printString ) ]
                    ifFalse: [
                        File nextPutAll: ( n printString ).
                        File nextPutAll: ', 0' ] ]
            ifFalse: [
                File nextPutAll: '0, 0' ] ].
    File nextPutAll: ' }'.
    ( count < sortedSize ) ifTrue: [ File nextPutAll: ', ' ].
    COMMENTS 
        ifTrue: [
            File nextPutAll: '   /* '.
            File nextPutAll: entry id printString.
            File nextPutAll: ':  '.
            File nextPutAll: ( entry name ).
            File nextPutAll: ' */'.
            File cr ]
        ifFalse: [
            ( ( count \\ 4 ) == 0 ) ifTrue: [ File cr ] ] ].
File cr.
File log: '};'. File cr.  File cr.

" Now generate TitleCase Data table "
File nextPutAll: 
    'static XCharTitleCaseEntrySType defaultTitleCaseTable[ ] = {'.
File cr.
count := 0.
titleCaseEntries do: [ :entry | 
    count := count + 1.
    File nextPutAll: '{ '.
    File nextPutAll: entry id printString.
    File nextPutAll: ', '.
    File nextPutAll: entry titleCase id printString.
    File nextPutAll: '}'.
    ( count < titleCaseEntries size ) ifTrue: [ File nextPutAll: ', ' ].
    ( ( count \\ 4 ) == 0 ) ifTrue: [ File cr ] ].
File cr.
File log: '};'. File cr. File cr.

File close.
%
category: 'Main Operations'
classmethod: UnicodeData
generateTables

" Generate tables that can be used by the 
  Character>>installCharTables: method "

| result item |

result := Array new.
SortedTable do: [ :entry | | field1 field2 n |
    field1 := nil. field2 := nil. n := nil.
    ( entry category first = $L )
    ifTrue: [ 
        entry upperCase == nil
            ifFalse: [ field1 := entry upperCase asCharacter ].
        entry lowerCase == nil
            ifFalse: [ field2 := entry lowerCase asCharacter ] ]
    ifFalse: [
        ( entry category first = $N )
            ifTrue: [
                n := entry number.
                ( n isKindOf: Fraction )
                    ifTrue: [
                        field1 := n numerator.
                        field2 := n denominator ]
                    ifFalse: [
                        field1 := n.
                        field2 := nil ] ] ].
    item := Array 
            with: entry asCharacter
            with: ( entry category )
            with: field1
            with: field2.
    ( entry upperCase ) = ( entry titleCase ) ifFalse: [
        item add: entry titleCase asCharacter ].
    result add: item ].
    ^ result
%
category: 'Misc'
classmethod: UnicodeData
initialize: fileName

" Initialize UnicodeData Table from specified file "

| entry id tally asterisk s |

Table := Array new: ( MAX_ENTRY + 1 ).
SortedTable := nil.
File := GsFile openRead: fileName.
asterisk := '*'.    " Used in isoComment field "
id := 0.
tally := 0.
[ ( File atEnd ) _or: [ id > MAX_ENTRY ] ] whileFalse: [
    tally := tally + 1.
    " extract Name field "
    id := Integer fromHexString: ( self upToSeparator: File ).
    " For now, only record the entries fitting in 16-bits "
    ( id <= MAX_ENTRY  ) ifTrue: [
        entry := self new.
        entry id: id.
        " extract Name field "
        entry name: ( self upToSeparator: File ).
        " extract General_Category field "
        entry category: ( self upToSeparator: File ) asSymbol.
        " extract Canonical_Combining_Class field "
        entry combineClass: 
            ( self fromIntegerString: ( self upToSeparator: File )).
        " extract Bidi_Class field "
        s := self upToSeparator: File.
        ( s size > 0 ) ifTrue: [ entry bidiClass: s asSymbol ].
        " check for and extract Decomposition_Type field "
        ( File peek = $< ) ifTrue: [ 
            entry decompType: ( self parseBracketString: File ).
            File next. " skips the space char after the bracket string "
            ].
        " extract Decomposition_Mapping field "
        entry decompMap: 
            ( self fromMultiHexString: ( self upToSeparator: File )).
        " extract Numeric_Value for decimal digit "
        entry decDigit: ( self upToSeparator: File ).
        " extract Numeric_Value for digit "
        entry digit: ( self upToSeparator: File ).
        " extract Numeric_Value for numerical "
        entry number: ( self upToSeparator: File ).
        " extract Bidi_Mirrored field "
        s := self upToSeparator: File.
        ( s first = $Y) ifTrue: [ entry bidiMirrored: true ].
        ( s first = $N ) ifTrue: [ entry bidiMirrored: false ].
        " extract Unicode_1_Name field "
        entry unicode1Name: ( self upToSeparator: File ).
        " extract ISO_Comment field "
        s := ( self upToSeparator: File ).
        ( s == asterisk ) 
            ifTrue: [ entry isoComment: asterisk ]
            ifFalse: [ entry isoComment: s ].
        " extract Simple_Uppercase_Mapping "
        entry upperCase: ( self fromHexString: ( self upToSeparator: File )).
        " extract Simple_Lowercase_Mapping "
        entry lowerCase: ( self fromHexString: ( self upToSeparator: File )).
        " extract Simple_Titlecase_Mapping "
        entry titleCase: ( self fromHexString: ( self upToSeparator: File )).
        Table at: id + 1 put: entry.
        ( tally \\ 200 == 0 )  ifTrue: [ 
            GsFile stdout log: ' Processing ID ' + id printString.
            System commitTransaction ifFalse: [ 
                self halt: 'problem committing'  ] ].
        ] ].
System commitTransaction ifFalse: [ self halt: 'problem committing' ].
File close.
self postProcess.
%
category: 'Reading'
classmethod: UnicodeData
isHexDigit: c

    ( ( c >= $0) _and: [ c <= $9 ] ) ifTrue: [ ^ true ].
    ( ( c >= $A) _and: [ c <= $F] ) ifTrue: [ ^ true ].
    ^ false
%
category: 'Main Operations'
classmethod: UnicodeData
loadFromFile:  fileName

" Load in the Unicode Database from a file "

MAX_ENTRY := 65535.  " FOR FULL 16-bit UNICODE TABLE "
" MAX_ENTRY := 255.   FOR DEFAULT 256 SIZE INTERNAL TABLE "
self initialize: fileName.
self calculateCollation.
%
category: 'Reading'
classmethod: UnicodeData
parseBracketString: stream

" Parse out 'string' from '<string>' "

    | s c |
    s := String new.
    stream next.  " discard the $< character "
    [ ( c := stream next ) = $> ] whileFalse: [ s add: c ].
    ^ s asSymbol
%
category: 'Misc'
classmethod: UnicodeData
postProcess

| tableSize entry id cat map mapEntry baseIndex baseEntry x dispatchIndex |
GsFile stdout log: 'Now doing postProcessing..'.
tableSize := Table size.
" First pass: patch up case information "
1 to: tableSize do: [ :i |
    entry := Table at: i.
    entry == nil ifFalse: [
        id := entry id.
        cat := entry category.
        " fill in defaulted fields for case info "
        cat == #Lu ifTrue: [ 
            entry upperCase: id.
            entry titleCase == nil  ifTrue: [ 
                entry titleCase: id ] ].
        cat == #Ll ifTrue: [ 
            entry lowerCase: id.
            entry titleCase == nil ifTrue: [ 
                entry titleCase: ( entry upperCase ) ] ] ] ].

" Second pass: setup dispatch index, 
    convert numeric fields, 
   replace indexes with object references "
dispatchIndex := -1.
1 to: tableSize do: [ :i |
    entry := Table at: i.
    entry == nil ifFalse: [ 
        dispatchIndex := dispatchIndex + 1.
        entry dispatchId: dispatchIndex.
        id := entry id.

        " Convert numeric fields from strings to numbers "
        entry decDigit == nil ifFalse: [ 
            entry decDigit: ( Integer fromString: entry decDigit ) ].
        entry digit == nil ifFalse: [
            entry digit: ( Integer fromString: entry digit ) ].
        entry number == nil ifFalse: [
            ( entry number includes: $/ ) 
            ifFalse: [ entry number: ( Integer fromString: entry number ) ]
            ifTrue: [ entry number: ( Fraction fromString: entry number ) ] ].

        " Convert id's into object references from Table (remember +1 offset) "
        map := entry decompMap.
        map == nil ifFalse: [ 
            1 to: map size do: [ :i | 
                mapEntry := map at: i.
                ( mapEntry <= MAX_ENTRY ) 
                    ifTrue: [ map at: i put: ( Table at: ( mapEntry + 1 )) ] 
                    ifFalse: [ map at: i put: nil ] ] ].
        id := entry upperCase.
        ( (id ~~ nil) _and: [ id <= MAX_ENTRY ] )
            ifTrue: [ entry upperCase: ( Table at: ( id + 1 )) ]
            ifFalse: [ entry upperCase: entry ].
        id := entry lowerCase.
        ((id ~~ nil) _and: [ id <= MAX_ENTRY ] )
            ifTrue: [ entry lowerCase: ( Table at: ( id + 1 )) ]
            ifFalse: [ entry lowerCase: entry ].
        id := entry titleCase.
        ((id ~~ nil) _and: [ id <= MAX_ENTRY ] )
            ifTrue: [ entry titleCase: ( Table at: ( id + 1 )) ]
            ifFalse: [ entry titleCase: entry ].

    ] ].

" All done, save results "
System commitTransaction ifFalse: [ self halt: 'Problem committing..' ]
%
category: 'Accessing'
classmethod: UnicodeData
SortedTable

    ^ SortedTable
%
category: 'Accessing'
classmethod: UnicodeData
Table

    ^ Table
%
category: 'Accessing'
classmethod: UnicodeData
Table: anArray

    Table := anArray
%
category: 'Reading'
classmethod: UnicodeData
test: stream

    | out |
    out := GsFile stdout.
    [ stream atEnd ] whileFalse: [ 
        1 to: 15 do: [ :i |
        out log: ( i printString ) + ':  ' + ( self upToSeparator: stream ) ].
    ].
%
category: 'Reading'
classmethod: UnicodeData
upToSeparator: stream

| s |
s := self _upToSeparator: stream.
^ ( s size == 0 )
    ifTrue: [ nil ]
    ifFalse: [ s ]
%
! ------------------- Instance methods for UnicodeData
category: 'Comparisons'
method: UnicodeData
< entry

" Establishes current collation order for the Unicode character set.

  Approach is to use the base component (from decompMap) of the letter 
  to keep variations of a letter next to each other.  Order would be:

  $A $A-with-diacritics $a $a-with-diacritics $B...

"

    | base1 base2 base1U base2U |

    ( ( self isLetter ) _and: [ entry isLetter ] ) 
        ifFalse: [ 
            ( self isLetter ) ifTrue: [ 
                ^ ( self upperCase id ) < ( entry id ) ].
            ( entry isLetter ) ifTrue: [ 
                ^ ( self id ) < ( entry upperCase id ) ].
            ^ ( self id ) < ( entry id ) ].

    base1 := self base.
    base2 := entry base.
    ( base1 = base2 )
        ifTrue: [ 
            ( self = base1 ) ifTrue: [ ^ true ].
            ( entry = base2 ) ifTrue: [ ^ false ].
            ^ ( self id ) < ( entry id ) ].

    base1U := base1 upperCase.
    base2U := base2 upperCase.
    ( base1U = base2U )
        ifFalse: [ ^ ( base1U id ) < ( base2U id ) ].

    ( base1U = base2 ) ifTrue: [ ^ false ].
    ( base2U = base1 ) ifTrue: [ ^ true ].
    ^ ( self id ) < ( entry id )
%
category: 'Comparisons'
method: UnicodeData
> entry

^ entry < self
%
category: 'Misc'
method: UnicodeData
asCharacter

    ^ Character withValue: self id
%
category: 'Misc'
method: UnicodeData
base

" The base of a unicode data item is the first letter entry from 
  its decompMap.

  ( note: may have to recurse on entry if it is in turn a composite) "

    decompMap == nil
        ifTrue: [ ^ self ]
        ifFalse: [ 
            decompMap do: [ :entry |
                ( ( entry ~~ nil ) _and: [ entry isLetter ] ) ifTrue: [ 
                    ^ entry base ] ] ].
    ^ self
%
category: 'Misc'
method: UnicodeData
baseUpper

    ^ self base upperCase
%
category: 'Accessing'
method: UnicodeData
bidiClass

   "Return the value of the instance variable 'bidiClass'."
   ^bidiClass
%
category: 'Updating'
method: UnicodeData
bidiClass: newValue

   "Modify the value of the instance variable 'bidiClass'."
   bidiClass := newValue
%
category: 'Accessing'
method: UnicodeData
bidiMirrored

   "Return the value of the instance variable 'bidiMirrored'."
   ^bidiMirrored
%
category: 'Updating'
method: UnicodeData
bidiMirrored: newValue

   "Modify the value of the instance variable 'bidiMirrored'."
   bidiMirrored := newValue
%
category: 'Accessing'
method: UnicodeData
category

   "Return the value of the instance variable 'category'."
   ^category
%
category: 'Updating'
method: UnicodeData
category: newValue

   "Modify the value of the instance variable 'category'."
   category := newValue
%
category: 'Accessing'
method: UnicodeData
categoryId

" returns index code for category symbol "

^ #( #Lu #Ll #Lt #Lm #Lo #Mn #Mc #Me #Nd #Nl #No #Pc #Pd #Ps 
    #Pe #Pi #Pf #Po #Sm #Sc #Sk #So #Zs #Zl #Zp #Cc #Cf #Cs #Co #Cn) 
    indexOf: category

%
category: 'Misc'
method: UnicodeData
collate: entry

" Starting from here, insert this entry into the 
  linked list collate chain in the appropriate place "

    | next |
    ( self > entry ) ifTrue: [ self halt: 'Problem with collate sequence' ].
    next := self collateNext.
    next == nil
        ifFalse: [ 
            ( entry > next )
                ifTrue: [ next collate: entry ]
                ifFalse: [ 
                    entry collatePrevious: self.
                    entry collateNext: next.
                    self collateNext: entry.
                    next collatePrevious: entry ] ]
        ifTrue: [ 
            self collateNext: entry.
            entry collatePrevious: self.
            entry collateNext: nil.
            ( self class CollateEnd = self )
                ifTrue: [
                    self class CollateEnd: entry ] ]
%
category: 'Misc'
method: UnicodeData
collateEnd

    " Find the end of the linked list collate chain "

    self collateNext == nil 
    ifTrue: [ ^ self ]
    ifFalse: [ ^ self collateNext collateEnd ]
%
category: 'Accessing'
method: UnicodeData
collateId

   "Return the value of the instance variable 'collateId'."
   ^collateId
%
category: 'Updating'
method: UnicodeData
collateId: newValue

   "Modify the value of the instance variable 'collateId'."
   collateId := newValue
%
category: 'Accessing'
method: UnicodeData
collateNext

   "Return the value of the instance variable 'collateNext'."
   ^collateNext
%
category: 'Updating'
method: UnicodeData
collateNext: newValue

   "Modify the value of the instance variable 'collateNext'."
   collateNext := newValue
%
category: 'Accessing'
method: UnicodeData
collatePrevious

   "Return the value of the instance variable 'collatePrevious'."
   ^collatePrevious
%
category: 'Updating'
method: UnicodeData
collatePrevious: newValue

   "Modify the value of the instance variable 'collatePrevious'."
   collatePrevious := newValue
%
category: 'Accessing'
method: UnicodeData
combineClass

   "Return the value of the instance variable 'combineClass'."
   ^combineClass
%
category: 'Updating'
method: UnicodeData
combineClass: newValue

   "Modify the value of the instance variable 'combineClass'."
   combineClass := newValue
%
category: 'Accessing'
method: UnicodeData
decDigit

   "Return the value of the instance variable 'decDigit'."
   ^decDigit
%
category: 'Updating'
method: UnicodeData
decDigit: newValue

   "Modify the value of the instance variable 'decDigit'."
   decDigit := newValue
%
category: 'Accessing'
method: UnicodeData
decompMap

   "Return the value of the instance variable 'decompMap'."
   ^decompMap
%
category: 'Updating'
method: UnicodeData
decompMap: newValue

   "Modify the value of the instance variable 'decompMap'."
   decompMap := newValue
%
category: 'Accessing'
method: UnicodeData
decompType

   "Return the value of the instance variable 'decompType'."
   ^decompType
%
category: 'Updating'
method: UnicodeData
decompType: newValue

   "Modify the value of the instance variable 'decompType'."
   decompType := newValue
%
category: 'Accessing'
method: UnicodeData
digit

   "Return the value of the instance variable 'digit'."
   ^digit
%
category: 'Updating'
method: UnicodeData
digit: newValue

   "Modify the value of the instance variable 'digit'."
   digit := newValue
%
category: 'Accessing'
method: UnicodeData
dispatchId

   "Return the value of the instance variable 'dispatchId'."
   ^dispatchId
%
category: 'Updating'
method: UnicodeData
dispatchId: newValue

   "Modify the value of the instance variable 'dispatchId'."
   dispatchId := newValue
%
category: 'Accessing'
method: UnicodeData
id

   "Return the value of the instance variable 'id'."
   ^id
%
category: 'Updating'
method: UnicodeData
id: newValue

   "Modify the value of the instance variable 'id'."
   id := newValue
%
category: 'Testing'
method: UnicodeData
isLetter

^ ( category == #Lu ) _or: [ ( category == #Ll ) _or: [ category == #Lt ] ]
%
category: 'Testing'
method: UnicodeData
isNumber

^ ( category == #Nd ) _or: [ ( category == #Nl ) _or: [ category == #No ] ]
%
category: 'Accessing'
method: UnicodeData
isoComment

   "Return the value of the instance variable 'isoComment'."
   ^isoComment
%
category: 'Updating'
method: UnicodeData
isoComment: newValue

   "Modify the value of the instance variable 'isoComment'."
   isoComment := newValue
%
category: 'Accessing'
method: UnicodeData
lowerCase

   "Return the value of the instance variable 'lowerCase'."
   ^lowerCase
%
category: 'Updating'
method: UnicodeData
lowerCase: newValue

   "Modify the value of the instance variable 'lowerCase'."
   lowerCase := newValue
%
category: 'Accessing'
method: UnicodeData
name

   "Return the value of the instance variable 'name'."
   ^name
%
category: 'Updating'
method: UnicodeData
name: newValue

   "Modify the value of the instance variable 'name'."
   name := newValue
%
category: 'Accessing'
method: UnicodeData
number

   "Return the value of the instance variable 'number'."
   ^number
%
category: 'Updating'
method: UnicodeData
number: newValue

   "Modify the value of the instance variable 'number'."
   number := newValue
%
category: 'Printing'
method: UnicodeData
printOn: aStream

    aStream nextPut: name.
    unicode1Name == nil ifFalse: [  
        aStream nextPut: ' / '.
        aStream nextPut: unicode1Name ].
    isoComment == nil ifFalse: [
        aStream nextPut: ' / '.
        aStream nextPut: isoComment ].
%
category: 'Accessing'
method: UnicodeData
titleCase

   "Return the value of the instance variable 'titleCase'."
   ^titleCase
%
category: 'Updating'
method: UnicodeData
titleCase: newValue

   "Modify the value of the instance variable 'titleCase'."
   titleCase := newValue
%
category: 'Accessing'
method: UnicodeData
unicode1Name

   "Return the value of the instance variable 'unicode1Name'."
   ^unicode1Name
%
category: 'Updating'
method: UnicodeData
unicode1Name: newValue

   "Modify the value of the instance variable 'unicode1Name'."
   unicode1Name := newValue
%
category: 'Accessing'
method: UnicodeData
upperCase

   "Return the value of the instance variable 'upperCase'."
   ^upperCase
%
category: 'Updating'
method: UnicodeData
upperCase: newValue

   "Modify the value of the instance variable 'upperCase'."
   upperCase := newValue
%
