2004-04-30 Dick Porter <dick@ximian.com>
[mono.git] / mcs / class / corlib / System.Globalization / CultureInfo.cs
1 //
2 // System.Globalization.CultureInfo.cs
3 //
4 // Miguel de Icaza (miguel@ximian.com)
5 // Dick Porter (dick@ximian.com)
6 //
7 // (C) 2001, 2002, 2003 Ximian, Inc. (http://www.ximian.com)
8 //
9
10 using System.Collections;
11 using System.Threading;
12 using System.Runtime.CompilerServices;
13
14 namespace System.Globalization
15 {
16         [Serializable]
17         public class CultureInfo : ICloneable, IFormatProvider
18         {
19                 static CultureInfo invariant_culture_info;
20                 
21                 bool m_isReadOnly;
22                 int  cultureID;
23                 [NonSerialized]
24                 int parent_lcid;
25                 [NonSerialized]
26                 int specific_lcid;
27                 [NonSerialized]
28                 int datetime_index;
29                 [NonSerialized]
30                 int number_index;
31                 bool m_useUserOverride;
32                 NumberFormatInfo numInfo;
33                 DateTimeFormatInfo dateTimeInfo;
34                 TextInfo textInfo;
35                 private string m_name;
36                 
37                 [NonSerialized]
38                 private string displayname;
39                 [NonSerialized]
40                 private string englishname;
41                 [NonSerialized]
42                 private string nativename;
43                 [NonSerialized]
44                 private string iso3lang;
45                 [NonSerialized]
46                 private string iso2lang;
47                 [NonSerialized]
48                 private string icu_name;
49                 [NonSerialized]
50                 private string win3lang;
51                 CompareInfo compareInfo;
52                 Calendar calendar;
53                 
54                 int m_dataItem; // MS.NET serializes this.
55                 
56                 // Deserialized instances will set this to false
57                 [NonSerialized]
58                 bool constructed;
59                 
60                 private static readonly string MSG_READONLY = "This instance is read only";
61                 
62                 static public CultureInfo InvariantCulture {
63                         get {
64                                 if (invariant_culture_info == null) {
65                                         lock (typeof (CultureInfo)) {
66                                                 if (invariant_culture_info == null) {
67                                                         invariant_culture_info = new CultureInfo (0x7f, false);
68                                                         invariant_culture_info.m_isReadOnly = true;
69                                                 }
70                                         }
71                                 }
72                                 
73                                 return(invariant_culture_info);
74                         }
75                 }
76
77                 public static CultureInfo CreateSpecificCulture (string name)
78                 {
79                         if (name == null) {
80                                 throw new ArgumentNullException ("name");
81                         }
82
83                         if (name == String.Empty)
84                                 return InvariantCulture;
85
86                         CultureInfo ci = new CultureInfo ();
87                         if (!construct_internal_locale_from_specific_name (ci, name.ToLowerInvariant ()))
88                                 throw new ArgumentException ("Culture name " + name +
89                                                 " is not supported.", name);
90
91                         return ci;
92                 }
93
94                 public static CultureInfo CurrentCulture 
95                 {
96                         get {
97                                 return Thread.CurrentThread.CurrentCulture;
98                         }
99                 }
100
101                 public static CultureInfo CurrentUICulture 
102                 {
103                         get {
104                                 return Thread.CurrentThread.CurrentUICulture;
105                         }
106                 }
107
108                 internal static CultureInfo ConstructCurrentCulture ()
109                 {
110                         CultureInfo ci = new CultureInfo ();
111                         if (!construct_internal_locale_from_current_locale (ci))
112                                 ci = InvariantCulture;
113                         return ci;
114                 }
115
116                 internal static CultureInfo ConstructCurrentUICulture ()
117                 {
118                         return ConstructCurrentCulture ();
119                 }
120
121                 public virtual int LCID {
122                         get {
123                                 return cultureID;
124                         }
125                 }
126
127                 public virtual string Name {
128                         get {
129                                 return(m_name);
130                         }
131                 }
132
133                 public virtual string NativeName
134                 {
135                         get {
136                                 if (!constructed) Construct ();
137                                 return(nativename);
138                         }
139                 }
140                 
141
142                 [MonoTODO]
143                 public virtual Calendar Calendar
144                 {
145                         get { return calendar; }
146                 }
147
148                 [MonoTODO]
149                 public virtual Calendar[] OptionalCalendars
150                 {
151                         get {
152                                 return(null);
153                         }
154                 }
155
156                 public virtual CultureInfo Parent
157                 {
158                         get {
159                                 if (!constructed) Construct ();
160                                 if (parent_lcid == cultureID)
161                                         return null;
162                                 return new CultureInfo (parent_lcid);
163                         }
164                 }
165
166                 public virtual TextInfo TextInfo
167                 {
168                         get {
169                                 if (textInfo == null) {
170                                         lock (this) {
171                                                 if(textInfo == null) {
172                                                         textInfo = new TextInfo (cultureID);
173                                                 }
174                                         }
175                                 }
176                                 
177                                 return(textInfo);
178                         }
179                 }
180
181                 public virtual string ThreeLetterISOLanguageName
182                 {
183                         get {
184                                 if (!constructed) Construct ();
185                                 return(iso3lang);
186                         }
187                 }
188
189                 public virtual string ThreeLetterWindowsLanguageName
190                 {
191                         get {
192                                 if (!constructed) Construct ();
193                                 return(win3lang);
194                         }
195                 }
196
197                 public virtual string TwoLetterISOLanguageName
198                 {
199                         get {
200                                 if (!constructed) Construct ();
201                                 return(iso2lang);
202                         }
203                 }
204
205                 public bool UseUserOverride
206                 {
207                         get {
208                                 return m_useUserOverride;
209                         }
210                 }
211
212                 internal string IcuName {
213                         get {
214                                 if (!constructed) Construct ();
215                                 return icu_name;
216                         }
217                 }
218
219                 public void ClearCachedData()
220                 {
221                         Thread.CurrentThread.CurrentCulture = null;
222                         Thread.CurrentThread.CurrentUICulture = null;
223                 }
224
225                 public virtual object Clone()
226                 {
227                         if (!constructed) Construct ();
228                         CultureInfo ci=(CultureInfo)MemberwiseClone ();
229                         ci.m_isReadOnly=false;
230                         return(ci);
231                 }
232
233                 public override bool Equals (object value)
234                 {
235                         CultureInfo b = value as CultureInfo;
236                         
237                         if (b != null)
238                                 return b.cultureID == cultureID;
239                         return false;
240                 }
241
242                 public static CultureInfo[] GetCultures(CultureTypes types)
243                 {
244                         bool neutral=((types & CultureTypes.NeutralCultures)!=0);
245                         bool specific=((types & CultureTypes.SpecificCultures)!=0);
246                         bool installed=((types & CultureTypes.InstalledWin32Cultures)!=0);  // TODO
247
248                         return internal_get_cultures (neutral, specific, installed);
249                 }
250
251                 public override int GetHashCode()
252                 {
253                         return cultureID;
254                 }
255
256                 public static CultureInfo ReadOnly(CultureInfo ci)
257                 {
258                         if(ci==null) {
259                                 throw new ArgumentNullException("ci");
260                         }
261
262                         if(ci.m_isReadOnly) {
263                                 return(ci);
264                         } else {
265                                 CultureInfo new_ci=(CultureInfo)ci.Clone ();
266                                 new_ci.m_isReadOnly=true;
267                                 return(new_ci);
268                         }
269                 }
270
271                 public override string ToString()
272                 {
273                         return(m_name);
274                 }
275                 
276                 public virtual CompareInfo CompareInfo
277                 {
278                         get {
279                                 if (!constructed) Construct ();
280                                 if(compareInfo==null) {
281                                         lock (this) {
282                                                 if(compareInfo==null) {
283                                                         compareInfo=new CompareInfo (this);
284                                                 }
285                                         }
286                                 }
287                                 
288                                 return(compareInfo);
289                         }
290                 }
291
292                 internal static bool IsIDNeutralCulture (int lcid)
293                 {
294                         bool ret;
295                         if (!internal_is_lcid_neutral (lcid, out ret))
296                                 throw new ArgumentException (String.Format ("Culture id 0x{:x4} is not supported.", lcid));
297                                 
298                         return ret;
299                 }
300
301                 public virtual bool IsNeutralCulture {
302                         get {
303                                 if (!constructed) Construct ();
304                                 return ((cultureID & 0xff00) == 0 || specific_lcid == 0);
305                         }
306                 }
307
308                 public virtual NumberFormatInfo NumberFormat {
309                         get {
310                                 if (!constructed) Construct ();
311                                 if (numInfo == null){
312                                         lock (this){
313                                                 if (numInfo == null) {
314                                                         numInfo = new NumberFormatInfo ();
315                                                         construct_number_format ();
316                                                 }
317                                         }
318                                 }
319
320                                 return numInfo;
321                         }
322
323                         set {
324                                 if (!constructed) Construct ();
325                                 if (m_isReadOnly) throw new InvalidOperationException(MSG_READONLY);
326
327                                 if (value == null)
328                                         throw new ArgumentNullException ("NumberFormat");
329                                 
330                                 numInfo = value;
331                         }
332                 }
333
334                 public virtual DateTimeFormatInfo DateTimeFormat
335                 {
336                         get 
337                         {
338                                 if (!constructed) Construct ();
339                                 if (dateTimeInfo == null)
340                                 {
341                                         lock (this)
342                                         {
343                                                 if (dateTimeInfo == null) {
344                                                         dateTimeInfo = new DateTimeFormatInfo();
345                                                         construct_datetime_format ();
346                                                 }
347                                         }
348                                 }
349
350                                 return dateTimeInfo;
351                         }
352
353                         set 
354                         {
355                                 if (!constructed) Construct ();
356                                 if (m_isReadOnly) throw new InvalidOperationException(MSG_READONLY);
357
358                                 if (value == null)
359                                         throw new ArgumentNullException ("DateTimeFormat");
360                                 
361                                 dateTimeInfo = value;
362                         }
363                 }
364
365                 public virtual string DisplayName
366                 {
367                         get {
368                                 if (!constructed) Construct ();
369                                 return(displayname);
370                         }
371                 }
372
373                 public virtual string EnglishName
374                 {
375                         get {
376                                 if (!constructed) Construct ();
377                                 return(englishname);
378                         }
379                 }
380
381                 [MonoTODO]
382                 public static CultureInfo InstalledUICulture
383                 {
384                         get {
385                                 return(null);
386                         }
387                 }
388
389                 public bool IsReadOnly 
390                 {
391                         get {
392                                 return(m_isReadOnly);
393                         }
394                 }
395                 
396
397                 // 
398                 // IFormatProvider implementation
399                 //
400                 public virtual object GetFormat( Type formatType )
401                 {
402                         object format = null;
403
404                         if ( formatType == typeof(NumberFormatInfo) )
405                                 format = NumberFormat;
406                         else if ( formatType == typeof(DateTimeFormatInfo) )
407                                 format = DateTimeFormat;
408                         
409                         return format;
410                 }
411                 
412                 void Construct ()
413                 {
414                         construct_internal_locale_from_lcid (cultureID);
415                         constructed = true;
416                 }
417
418                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
419                 private extern void construct_internal_locale (string locale);
420
421                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
422                 private extern bool construct_internal_locale_from_lcid (int lcid);
423
424                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
425                 private extern bool construct_internal_locale_from_name (string name);
426
427                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
428                 private extern static bool construct_internal_locale_from_specific_name (CultureInfo ci,
429                                 string name);
430
431                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
432                 private extern static bool construct_internal_locale_from_current_locale (CultureInfo ci);
433
434                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
435                 private extern static CultureInfo [] internal_get_cultures (bool neutral, bool specific, bool installed);
436
437                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
438                 private extern void construct_datetime_format ();
439
440                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
441                 private extern void construct_number_format ();
442
443                 // Returns false if the culture can not be found, sets is_neutral if it is
444                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
445                 private extern static bool internal_is_lcid_neutral (int lcid, out bool is_neutral);
446
447                 private void ConstructInvariant (bool use_user_override)
448                 {
449                         m_isReadOnly=false;
450                         cultureID=0x7f;
451                         this.m_useUserOverride=use_user_override;
452
453                         /* NumberFormatInfo defaults to the invariant data */
454                         numInfo=new NumberFormatInfo ();
455                         
456                         /* DateTimeFormatInfo defaults to the invariant data */
457                         dateTimeInfo=new DateTimeFormatInfo ();
458
459                         textInfo=new TextInfo ();
460
461                         m_name="";
462                         displayname="Invariant Language (Invariant Country)";
463                         englishname="Invariant Language (Invariant Country)";
464                         nativename="Invariant Language (Invariant Country)";
465                         iso3lang="IVL";
466                         iso2lang="iv";
467                         icu_name="en_US_POSIX";
468                         win3lang="IVL";
469                 }
470                 
471                 public CultureInfo (int culture, bool use_user_override)
472                 {
473                         if (culture < 0)
474                                 throw new ArgumentOutOfRangeException ("culture");
475
476                         constructed = true;
477                         
478                         if(culture==0x007f) {
479                                 /* Short circuit the invariant culture */
480                                 ConstructInvariant (use_user_override);
481                                 return;
482                         }
483
484                         if (!construct_internal_locale_from_lcid (culture))
485                                 throw new ArgumentException ("Culture name " + m_name +
486                                                 " is not supported.", "name");
487                 }
488
489                 public CultureInfo (int culture) : this (culture, false) {}
490                 
491                 public CultureInfo (string name, bool use_user_override)
492                 {
493                         if (name == null)
494                                 throw new ArgumentNullException ();
495
496                         constructed = true;
497                         
498                         if(name=="") {
499                                 /* Short circuit the invariant culture */
500                                 ConstructInvariant (use_user_override);
501                                 return;
502                         }
503
504                         if (!construct_internal_locale_from_name (name.ToLowerInvariant ()))
505                                 throw new ArgumentException ("Culture name " + name +
506                                                 " is not supported.", "name");
507                 }
508
509                 public CultureInfo (string name) : this (name, false) {}
510
511                 // This is used when creating by specific name and creating by
512                 // current locale so we can initialize the object without
513                 // doing any member initialization
514                 private CultureInfo () { constructed = true; } 
515         }
516 }