1 /*******************************************************************************
2 
3         copyright:      Copyright (c) 2005 John Chapman. All rights reserved
4 
5         license:        BSD style: $(LICENSE)
6 
7         version:        Initial release: 2005
8 
9         author:         John Chapman
10 
11 ******************************************************************************/
12 
13 module tango.text.locale.Posix;
14 
15 version (Posix)
16 {
17 alias tango.text.locale.Posix nativeMethods;
18 
19 private import tango.core.Exception;
20 private import tango.text.locale.Data;
21 private import tango.stdc.ctype;
22 private import tango.stdc.posix.stdlib;
23 private import tango.stdc.string;
24 private import tango.stdc.stringz;
25 private import tango.stdc.locale;
26 
27 /*private extern(C) char* setlocale(int type, char* locale);
28 private extern(C) void putenv(char*);
29 
30 private enum {LC_CTYPE, LC_NUMERIC, LC_TIME, LC_COLLATE, LC_MONETARY, LC_MESSAGES, LC_ALL, LC_PAPER, LC_NAME, LC_ADDRESS, LC_TELEPHONE, LC_MEASUREMENT, LC_IDENTIFICATION};*/
31 
32 int getUserCulture() {
33   char* env = getenv("LC_ALL");
34   if (!env || *env == '\0') {
35     env = getenv("LANG");
36   }
37 
38   // getenv returns a string of the form <language>_<region>.
39   // Therefore we need to replace underscores with hyphens.
40   const(char)[] s;
41   if (env){
42       char[] s2 = fromStringz(env).dup;
43       foreach (ref c; s2)
44                if (c == '.')
45                    break;
46                else
47                   if (c == '_')
48                       c = '-';
49       s=s2;
50   } else {
51       s="en-US";
52   }
53   foreach (entry; CultureData.cultureDataTable) {
54     // todo: there is also a local compareString defined. Is it correct that here 
55     // we use tango.text.locale.Data, which matches the signature?
56     if (tango.text.locale.Data.compareString(entry.name, s) == 0)
57       return entry.lcid;
58   }
59   
60   foreach (entry; CultureData.cultureDataTable) {
61     // todo: there is also a local compareString defined. Is it correct that here 
62     // we use tango.text.locale.Data, which matches the signature?
63     if (tango.text.locale.Data.compareString(entry.name, "en-US") == 0)
64       return entry.lcid;
65   }
66   return 0;
67 }
68 
69 import tango.io.Stdout;
70 import tango.stdc.stdio;
71 
72 void setUserCulture(int lcid) {
73   char[] name;
74   try {
75     name = CultureData.getDataFromCultureID(lcid).name ~ ".utf-8";
76   }
77   catch(Exception e) {
78     return;
79   }
80   
81   for(int i = 0; i < name.length; i++) {
82     if(name[i] == '.') break;
83     if(name[i] == '-') name[i] = '_';
84   }
85   
86   putenv(("LANG=" ~ name).ptr);
87   setlocale(LC_CTYPE, name.ptr);
88   setlocale(LC_NUMERIC, name.ptr);
89   setlocale(LC_TIME, name.ptr);
90   setlocale(LC_COLLATE, name.ptr);
91   setlocale(LC_MONETARY, name.ptr);
92 
93   version (GNU) {} else {
94 /*      setlocale(LC_MESSAGES, name.ptr); */
95   }
96 
97   setlocale(LC_PAPER, name.ptr);
98   setlocale(LC_NAME, name.ptr);
99   setlocale(LC_ADDRESS, name.ptr);
100   setlocale(LC_TELEPHONE, name.ptr);
101   setlocale(LC_MEASUREMENT, name.ptr);
102   setlocale(LC_IDENTIFICATION, name.ptr);
103 }
104 
105 int compareString(int lcid, const(char)[] stringA, size_t offsetA, size_t lengthA, const(char)[] stringB, size_t offsetB, size_t lengthB, bool ignoreCase) {
106 
107   void strToLower(char[] string) {
108     for(int i = 0; i < string.length; i++) {
109       string[i] = cast(char)(tolower(cast(int)string[i]));
110     }
111   }
112 
113   char* tempCol = setlocale(LC_COLLATE, null), tempCType = setlocale(LC_CTYPE, null);
114   const(char)[] locale;
115   try {
116     locale = CultureData.getDataFromCultureID(lcid).name ~ ".utf-8";
117   }
118   catch(Exception e) {
119     return 0;
120   }
121 
122   setlocale(LC_COLLATE, locale.ptr);
123   setlocale(LC_CTYPE, locale.ptr);
124   
125   char[] s1 = stringA[offsetA..offsetA+lengthA] ~ "\0",
126          s2 = stringB[offsetB..offsetB+lengthB] ~ "\0";
127   if(ignoreCase) {
128     strToLower(s1);
129     strToLower(s2);
130   }
131   
132   int ret = strcoll(s1.ptr, s2.ptr);
133   
134   setlocale(LC_COLLATE, tempCol);
135   setlocale(LC_CTYPE, tempCType);
136   
137   return ret;
138 }
139 
140 debug(UnitTest)
141 {
142     unittest
143     {
144         int c = getUserCulture();
145         assert(compareString(c, "Alphabet", 0, 8, "Alphabet", 0, 8, false) == 0);
146         assert(compareString(c, "Alphabet", 0, 8, "alphabet", 0, 8, true) == 0);
147         assert(compareString(c, "Alphabet", 0, 8, "alphabet", 0, 8, false) != 0);
148         assert(compareString(c, "lphabet", 0, 7, "alphabet", 0, 8, true) != 0);
149         assert(compareString(c, "Alphabet", 0, 8, "lphabet", 0, 7, true) != 0);
150         assert(compareString(c, "Alphabet", 0, 7, "ZAlphabet", 1, 7, false) == 0);
151     }
152 }
153 }