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