~ubuntu-branches/ubuntu/quantal/icu/quantal

« back to all changes in this revision

Viewing changes to source/i18n/titletrn.cpp

  • Committer: Package Import Robot
  • Author(s): Yves Arrouye
  • Date: 2002-03-03 15:31:13 UTC
  • Revision ID: package-import@ubuntu.com-20020303153113-3ssceqlq45xbmbnc
Tags: upstream-2.0-2.1pre20020303
ImportĀ upstreamĀ versionĀ 2.0-2.1pre20020303

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
**********************************************************************
 
3
*   Copyright (C) 2001, International Business Machines
 
4
*   Corporation and others.  All Rights Reserved.
 
5
**********************************************************************
 
6
*   Date        Name        Description
 
7
*   05/24/01    aliu        Creation.
 
8
**********************************************************************
 
9
*/
 
10
 
 
11
#include "unicode/uchar.h"
 
12
#include "titletrn.h"
 
13
#include "unicode/uniset.h"
 
14
#include "mutex.h"
 
15
#include "ucln_in.h"
 
16
#include "unicode/ustring.h"
 
17
#include "ustr_imp.h"
 
18
#include "cpputils.h"
 
19
 
 
20
U_NAMESPACE_BEGIN
 
21
 
 
22
/**
 
23
 * ID for this transliterator.
 
24
 */
 
25
const char TitlecaseTransliterator::_ID[] = "Any-Title";
 
26
 
 
27
/**
 
28
 * Mutex for statics IN THIS FILE
 
29
 */
 
30
static UMTX MUTEX = 0;
 
31
 
 
32
/**
 
33
 * The set of characters we skip.  These are neither cased nor
 
34
 * non-cased, to us; we copy them verbatim.
 
35
 */
 
36
static UnicodeSet* SKIP = NULL;
 
37
 
 
38
/**
 
39
 * The set of characters that cause the next non-SKIP character
 
40
 * to be lowercased.
 
41
 */
 
42
static UnicodeSet* CASED = NULL;
 
43
 
 
44
TitlecaseTransliterator::TitlecaseTransliterator(const Locale& theLoc) :
 
45
    Transliterator(_ID, 0),
 
46
    loc(theLoc), 
 
47
    buffer(0) {
 
48
    buffer = new UChar[u_getMaxCaseExpansion()];
 
49
    // Need to look back 2 characters in the case of "can't"
 
50
    setMaximumContextLength(2);
 
51
}
 
52
 
 
53
/**
 
54
 * Destructor.
 
55
 */
 
56
TitlecaseTransliterator::~TitlecaseTransliterator() {
 
57
    delete [] buffer;
 
58
}
 
59
 
 
60
/**
 
61
 * Copy constructor.
 
62
 */
 
63
TitlecaseTransliterator::TitlecaseTransliterator(const TitlecaseTransliterator& o) :
 
64
    Transliterator(o),
 
65
    loc(o.loc),
 
66
    buffer(0) {
 
67
    buffer = new UChar[u_getMaxCaseExpansion()];    
 
68
    uprv_arrayCopy(o.buffer, 0, this->buffer, 0, u_getMaxCaseExpansion());
 
69
}
 
70
 
 
71
/**
 
72
 * Assignment operator.
 
73
 */
 
74
TitlecaseTransliterator& TitlecaseTransliterator::operator=(
 
75
                             const TitlecaseTransliterator& o) {
 
76
    Transliterator::operator=(o);
 
77
    loc = o.loc;
 
78
    uprv_arrayCopy(o.buffer, 0, this->buffer, 0, u_getMaxCaseExpansion());
 
79
    return *this;
 
80
}
 
81
 
 
82
/**
 
83
 * Transliterator API.
 
84
 */
 
85
Transliterator* TitlecaseTransliterator::clone(void) const {
 
86
    return new TitlecaseTransliterator(*this);
 
87
}
 
88
 
 
89
/**
 
90
 * Implements {@link Transliterator#handleTransliterate}.
 
91
 */
 
92
void TitlecaseTransliterator::handleTransliterate(
 
93
                                  Replaceable& text, UTransPosition& offsets,
 
94
                                  UBool isIncremental) const {
 
95
    if (SKIP == NULL) {
 
96
        Mutex lock(&MUTEX);
 
97
        if (SKIP == NULL) {
 
98
            UErrorCode ec = U_ZERO_ERROR;
 
99
            SKIP = new UnicodeSet(UNICODE_STRING_SIMPLE("[\\u00AD \\u2019 \\' [:Mn:] [:Me:] [:Cf:] [:Lm:] [:Sk:]]"), ec);
 
100
            CASED = new UnicodeSet(UNICODE_STRING_SIMPLE("[[:Lu:] [:Ll:] [:Lt:]]"), ec);
 
101
            ucln_i18n_registerCleanup();
 
102
        }
 
103
    }
 
104
 
 
105
    // Our mode; we are either converting letter toTitle or
 
106
    // toLower.
 
107
    UBool doTitle = TRUE;
 
108
    
 
109
    // Determine if there is a preceding context of CASED SKIP*,
 
110
    // in which case we want to start in toLower mode.  If the
 
111
    // prior context is anything else (including empty) then start
 
112
    // in toTitle mode.
 
113
    UChar32 c;
 
114
    int32_t start;
 
115
    for (start = offsets.start - 1; start >= offsets.contextStart; start -= UTF_CHAR_LENGTH(c)) {
 
116
        c = text.char32At(start);
 
117
        if (SKIP->contains(c)) {
 
118
            continue;
 
119
        }
 
120
        doTitle = !CASED->contains(c);
 
121
        break;
 
122
    }
 
123
    
 
124
    // Convert things after a CASED character toLower; things
 
125
    // after a non-CASED, non-SKIP character toTitle.  SKIP
 
126
    // characters are copied directly and do not change the mode.
 
127
    int32_t textPos = offsets.start;
 
128
    if (textPos >= offsets.limit) return;
 
129
 
 
130
    // get string for context
 
131
    // TODO: add convenience method to do this, since we do it all over
 
132
 
 
133
    int32_t loop = 0;
 
134
    UnicodeString original;
 
135
    /* UChar *original = new UChar[offsets.contextLimit - offsets.contextStart+1]; */// get whole context
 
136
    /* Extract the characters from Replaceable */
 
137
    for (loop = offsets.contextStart; loop < offsets.contextLimit; loop++) {
 
138
        original.append(text.charAt(loop));
 
139
    }
 
140
    // Walk through original string
 
141
    // If there is a case change, modify corresponding position in replaceable
 
142
 
 
143
    int32_t i = textPos - offsets.contextStart;
 
144
    int32_t limit = offsets.limit - offsets.contextStart;
 
145
    UChar32 cp;
 
146
    int32_t oldLen;
 
147
    int32_t newLen;
 
148
 
 
149
    for (; i < limit; ) {
 
150
        UErrorCode status = U_ZERO_ERROR;
 
151
        int32_t s = i;
 
152
 
 
153
        UTF_GET_CHAR(original.getBuffer(), 0, i, original.length(), cp);
 
154
        oldLen = UTF_CHAR_LENGTH(cp);
 
155
        i += oldLen;
 
156
        if (!SKIP->contains(cp)) {
 
157
            if (doTitle) {
 
158
                newLen = u_internalToTitle(cp, /* ### TODO: pass in UCharIterator */ 0, buffer, u_getMaxCaseExpansion(), loc.getName());
 
159
            } else {
 
160
                newLen = u_internalToLower(cp, /* ### TODO: pass in UCharIterator */ 0, buffer, u_getMaxCaseExpansion(), loc.getName());
 
161
            }
 
162
            doTitle = !CASED->contains(cp);
 
163
            if (newLen >= 0) {
 
164
                UnicodeString temp(buffer, newLen);
 
165
                text.handleReplaceBetween(textPos, textPos + oldLen, temp);
 
166
                if (newLen != oldLen) {
 
167
                    textPos += newLen;
 
168
                    offsets.limit += newLen - oldLen;
 
169
                    offsets.contextLimit += newLen - oldLen;
 
170
                    continue;
 
171
                }
 
172
            }
 
173
        }
 
174
        textPos += oldLen;
 
175
    }
 
176
    offsets.start = offsets.limit;
 
177
}
 
178
 
 
179
/**
 
180
 * Static memory cleanup function.
 
181
 */
 
182
void TitlecaseTransliterator::cleanup() {
 
183
    if (SKIP != NULL) {
 
184
        delete SKIP; SKIP = NULL;
 
185
        delete CASED; CASED = NULL;
 
186
        umtx_destroy(&MUTEX);
 
187
    }
 
188
}
 
189
 
 
190
U_NAMESPACE_END
 
191