xref: /trunk/main/sal/rtl/source/locale.c (revision 647f063d)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include "rtl/locale.h"
25 
26 #include "osl/diagnose.h"
27 #include "rtl/alloc.h"
28 
29 #include "internal/once.h"
30 
31 static sal_Int32 RTL_HASHTABLE_SIZE[] =
32 {
33     7, 31, 127, 251, 509, 1021, 2039, 4093
34 };
35 
36 typedef struct rtl_hashentry RTL_HASHENTRY;
37 
38 struct rtl_hashentry
39 {
40     rtl_Locale* Entry;
41     RTL_HASHENTRY* Next;
42 };
43 
44 typedef struct rtl_hashtable
45 {
46     sal_Int8        iSize;
47     sal_Int32       Size;
48     sal_Int32       Elements;
49     RTL_HASHENTRY** Table;
50 } RTL_HASHTABLE;
51 
52 static RTL_HASHTABLE* g_pLocaleTable = NULL;
53 
54 static rtl_Locale* g_pDefaultLocale = NULL;
55 
56 static int rtl_locale_init (void);
57 
58 /*************************************************************************
59  */
60 void rtl_hashentry_destroy(RTL_HASHENTRY* entry)
61 {
62     rtl_uString_release(entry->Entry->Language);
63     rtl_uString_release(entry->Entry->Country);
64     rtl_uString_release(entry->Entry->Variant);
65     if (entry->Next)
66         rtl_hashentry_destroy(entry->Next);
67 
68     rtl_freeMemory(entry->Entry);
69     rtl_freeMemory(entry);
70 }
71 
72 void rtl_hashtable_destroy(RTL_HASHTABLE* table)
73 {
74     sal_Int32 size = 0;
75 
76     if (!table)
77         return;
78 
79     size = table->Size;
80 
81     while (size)
82     {
83         if (table->Table[size - 1])
84             rtl_hashentry_destroy(table->Table[size - 1]);
85         size--;
86     }
87 
88     rtl_freeMemory(table->Table);
89     rtl_freeMemory(table);
90 }
91 
92 void rtl_hashtable_init(RTL_HASHTABLE** table, sal_Int8 sizeIndex)
93 {
94     sal_Int32 nSize = RTL_HASHTABLE_SIZE[sizeIndex];
95 
96     if (*table)
97         rtl_hashtable_destroy(*table);
98 
99     *table = (RTL_HASHTABLE*)rtl_allocateMemory( sizeof(RTL_HASHTABLE) );
100 
101     (*table)->iSize = sizeIndex;
102     (*table)->Size = nSize;
103     (*table)->Elements = 0;
104     (*table)->Table = (RTL_HASHENTRY**)rtl_allocateMemory( (*table)->Size * sizeof(RTL_HASHENTRY*) );
105 
106     while (nSize)
107     {
108         (*table)->Table[nSize - 1] = NULL;
109         nSize--;
110     }
111 }
112 
113 sal_Int32 rtl_hashfunc(RTL_HASHTABLE* table, sal_Int32 key)
114 {
115     return ( (sal_uInt32) key % table->Size);
116 }
117 
118 sal_Bool rtl_hashtable_grow(RTL_HASHTABLE** table);
119 
120 rtl_Locale* rtl_hashtable_add(RTL_HASHTABLE** table, rtl_Locale* value)
121 {
122     sal_Int32 key = 0;
123 
124     if (!(*table))
125         return NULL;
126 
127     if ((*table)->Elements > ((*table)->Size / 2))
128         rtl_hashtable_grow(table);
129 
130     key = rtl_hashfunc(*table, value->HashCode);
131 
132     if (!(*table)->Table[key])
133     {
134         RTL_HASHENTRY *newEntry = (RTL_HASHENTRY*)rtl_allocateMemory( sizeof(RTL_HASHENTRY) );
135         newEntry->Entry = value;
136         newEntry->Next = NULL;
137         (*table)->Table[key] = newEntry;
138         (*table)->Elements++;
139         return NULL;
140     } else
141     {
142         RTL_HASHENTRY *pEntry = (*table)->Table[key];
143         RTL_HASHENTRY *newEntry = NULL;
144 
145         while (pEntry)
146         {
147             if (value->HashCode == pEntry->Entry->HashCode)
148                 return pEntry->Entry;
149 
150             if (!pEntry->Next)
151                 break;
152 
153             pEntry = pEntry->Next;
154         }
155 
156         newEntry = (RTL_HASHENTRY*)rtl_allocateMemory( sizeof(RTL_HASHENTRY) );
157         newEntry->Entry = value;
158         newEntry->Next = NULL;
159         pEntry->Next = newEntry;
160         (*table)->Elements++;
161         return NULL;
162     }
163 }
164 
165 sal_Bool rtl_hashtable_grow(RTL_HASHTABLE** table)
166 {
167     RTL_HASHTABLE* pNewTable = NULL;
168     sal_Int32 i = 0;
169 
170     rtl_hashtable_init(&pNewTable, (sal_Int8)((*table)->iSize + 1));
171 
172     while (i < (*table)->Size)
173     {
174         if ((*table)->Table[i])
175         {
176             RTL_HASHENTRY *pNext;
177             RTL_HASHENTRY *pEntry = (*table)->Table[i];
178 
179             rtl_hashtable_add(&pNewTable, pEntry->Entry);
180 
181             while (pEntry->Next)
182             {
183                 rtl_hashtable_add(&pNewTable, pEntry->Next->Entry);
184                 pNext = pEntry->Next;
185                 rtl_freeMemory(pEntry);
186                 pEntry = pNext;
187             }
188 
189             rtl_freeMemory(pEntry);
190         }
191         i++;
192     }
193 
194     rtl_freeMemory((*table)->Table);
195     rtl_freeMemory((*table));
196     (*table) = pNewTable;
197 
198     return sal_True;
199 }
200 
201 sal_Bool rtl_hashtable_find(RTL_HASHTABLE * table, sal_Int32 key, sal_Int32 hashCode, rtl_Locale** pValue)
202 {
203     if (!table)
204         return sal_False;
205 
206     if (table->Table[key])
207     {
208         RTL_HASHENTRY *pEntry = table->Table[key];
209 
210         while (pEntry && hashCode != pEntry->Entry->HashCode)
211             pEntry = pEntry->Next;
212 
213         if (pEntry)
214             *pValue = pEntry->Entry;
215         else
216             return sal_False;
217     } else
218         return sal_False;
219 
220     return sal_True;
221 }
222 
223 /*************************************************************************
224  *  rtl_locale_init
225  */
226 static void rtl_locale_once_init (void)
227 {
228   OSL_ASSERT(g_pLocaleTable == 0);
229   rtl_hashtable_init(&g_pLocaleTable, 1);
230 }
231 
232 static int rtl_locale_init (void)
233 {
234   static sal_once_type g_once = SAL_ONCE_INIT;
235   SAL_ONCE(&g_once, rtl_locale_once_init);
236   return (g_pLocaleTable != 0);
237 }
238 
239 /*************************************************************************
240  *  rtl_locale_fini
241  */
242 #if defined(__GNUC__)
243 static void rtl_locale_fini (void) __attribute__((destructor));
244 #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
245 #pragma fini(rtl_locale_fini)
246 static void rtl_locale_fini (void);
247 #endif /* __GNUC__ || __SUNPRO_C */
248 
249 void rtl_locale_fini (void)
250 {
251   if (g_pLocaleTable != 0)
252   {
253     rtl_hashtable_destroy (g_pLocaleTable);
254     g_pLocaleTable = 0;
255   }
256 }
257 
258 /*************************************************************************
259  *  rtl_locale_register
260  */
261 rtl_Locale * SAL_CALL rtl_locale_register( const sal_Unicode * language, const sal_Unicode * country, const sal_Unicode * variant )
262 {
263     sal_Unicode c = 0;
264     rtl_uString* sLanguage = NULL;
265     rtl_uString* sCountry = NULL;
266     rtl_uString* sVariant = NULL;
267     rtl_Locale *newLocale = NULL;
268     sal_Int32 hashCode = -1;
269     sal_Int32 key = 0;
270 
271     if ( !country )
272         country = &c;
273     if ( !variant )
274         variant = &c;
275 
276     if (!rtl_locale_init())
277       return NULL;
278 
279     hashCode = rtl_ustr_hashCode(language) ^ rtl_ustr_hashCode(country) ^ rtl_ustr_hashCode(variant);
280     key = rtl_hashfunc(g_pLocaleTable, hashCode);
281 
282     if (rtl_hashtable_find(g_pLocaleTable, key, hashCode, &newLocale))
283         return newLocale;
284 
285     rtl_uString_newFromStr(&sLanguage, language);
286     rtl_uString_newFromStr(&sCountry, country);
287     rtl_uString_newFromStr(&sVariant, variant);
288 
289     newLocale = (rtl_Locale*)rtl_allocateMemory( sizeof(rtl_Locale) );
290 
291     newLocale->Language = sLanguage;
292     newLocale->Country = sCountry;
293     newLocale->Variant = sVariant;
294     newLocale->HashCode = hashCode;
295 
296     rtl_hashtable_add(&g_pLocaleTable, newLocale);
297 
298     return newLocale;
299 }
300 
301 /*************************************************************************
302  *  rtl_locale_getDefault
303  */
304 rtl_Locale * SAL_CALL rtl_locale_getDefault()
305 {
306     return g_pDefaultLocale;
307 }
308 
309 /*************************************************************************
310  *  rtl_locale_setDefault
311  */
312 void SAL_CALL rtl_locale_setDefault( const sal_Unicode * language, const sal_Unicode * country, const sal_Unicode * variant )
313 {
314     g_pDefaultLocale = rtl_locale_register(language, country, variant);
315 }
316 
317 /*************************************************************************
318  *  rtl_locale_getLanguage
319  */
320 rtl_uString * SAL_CALL rtl_locale_getLanguage( rtl_Locale * This )
321 {
322     rtl_uString_acquire(This->Language);
323     return This->Language;
324 }
325 
326 /*************************************************************************
327  *  rtl_locale_getCountry
328  */
329 rtl_uString * SAL_CALL rtl_locale_getCountry( rtl_Locale * This )
330 {
331     rtl_uString_acquire(This->Country);
332     return This->Country;
333 }
334 
335 /*************************************************************************
336  *  rtl_locale_getVariant
337  */
338 rtl_uString * SAL_CALL rtl_locale_getVariant( rtl_Locale * This )
339 {
340     rtl_uString_acquire(This->Variant);
341     return This->Variant;
342 }
343 
344 /*************************************************************************
345  *  rtl_locale_hashCode
346  */
347 sal_Int32 SAL_CALL rtl_locale_hashCode( rtl_Locale * This )
348 {
349     return This->HashCode;
350 }
351 
352 /*************************************************************************
353  *  rtl_locale_equals
354  */
355 sal_Int32 SAL_CALL rtl_locale_equals( rtl_Locale * This, rtl_Locale * obj  )
356 {
357     return This == obj;
358 }
359