]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/locale/src/icu/time_zone.cpp
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / boost / libs / locale / src / icu / time_zone.cpp
CommitLineData
7c673cae
FG
1//
2// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
3//
4// Distributed under the Boost Software License, Version 1.0. (See
5// accompanying file LICENSE_1_0.txt or copy at
6// http://www.boost.org/LICENSE_1_0.txt)
7//
8#define BOOST_LOCALE_SOURCE
9#include "time_zone.hpp"
10
11//
12// Bug - when ICU tries to find a file that is equivalent to /etc/localtime it finds /usr/share/zoneinfo/localtime
13// that is just a symbolic link to /etc/localtime.
14//
15// It started in 4.0 and was fixed in version 4.6, also the fix was backported to the 4.4 branch so it should be
16// available from 4.4.3... So we test if the workaround is required
17//
18// It is also relevant only for Linux, BSD and Apple (as I see in ICU code)
19//
20
21#if U_ICU_VERSION_MAJOR_NUM == 4 && (U_ICU_VERSION_MINOR_NUM * 100 + U_ICU_VERSION_PATCHLEVEL_NUM) <= 402
22# if defined(__linux) || defined(__FreeBSD__) || defined(__APPLE__)
23# define BOOST_LOCALE_WORKAROUND_ICU_BUG
24# endif
25#endif
26
27#ifdef BOOST_LOCALE_WORKAROUND_ICU_BUG
28#include <dirent.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <unistd.h>
32#include <fstream>
33#include <pthread.h>
34#include <string.h>
35#include <memory>
36#endif
37
11fdf7f2
TL
38#include <boost/locale/hold_ptr.hpp>
39
7c673cae
FG
40namespace boost {
41 namespace locale {
42 namespace impl_icu {
43
44 #ifndef BOOST_LOCALE_WORKAROUND_ICU_BUG
45
46 // This is normal behavior
47
48 icu::TimeZone *get_time_zone(std::string const &time_zone)
49 {
50
51 if(time_zone.empty()) {
52 return icu::TimeZone::createDefault();
53 }
54 else {
55 return icu::TimeZone::createTimeZone(time_zone.c_str());
56 }
57 }
58
59 #else
60
61 //
62 // This is a workaround for an ICU timezone detection bug.
63 // It is \b very ICU specific and should not be used
64 // in general. It is also designed to work only on
65 // specific patforms: Linux, BSD and Apple, where this bug may actually
66 // occur
67 //
68 namespace {
69
70 // Under BSD, Linux and Mac OS X dirent has normal size
71 // so no issues with readdir_r
72
73 class directory {
74 public:
75 directory(char const *name) : d(0),read_result(0)
76 {
77 d=opendir(name);
78 if(!d)
79 return;
80 }
81 ~directory()
82 {
83 if(d)
84 closedir(d);
85 }
86 bool is_open()
87 {
88 return d;
89 }
90 char const *next()
91 {
92 if(d && readdir_r(d,&de,&read_result)==0 && read_result!=0)
93 return de.d_name;
94 return 0;
95 }
96 private:
97 DIR *d;
98 struct dirent de;
99 struct dirent *read_result;
100 };
101
102 bool files_equal(std::string const &left,std::string const &right)
103 {
104 char l[256],r[256];
105 std::ifstream ls(left.c_str());
106 if(!ls)
107 return false;
108 std::ifstream rs(right.c_str());
109 if(!rs)
110 return false;
111 do {
112 ls.read(l,sizeof(l));
113 rs.read(r,sizeof(r));
114 size_t n;
115 if((n=ls.gcount())!=size_t(rs.gcount()))
116 return false;
117 if(memcmp(l,r,n)!=0)
118 return false;
119 }while(!ls.eof() || !rs.eof());
120 if(bool(ls.eof())!=bool(rs.eof()))
121 return false;
122 return true;
123 }
124
125 std::string find_file_in(std::string const &ref,size_t size,std::string const &dir)
126 {
127 directory d(dir.c_str());
128 if(!d.is_open())
129 return std::string();
130
131 char const *name=0;
132 while((name=d.next())!=0) {
133 std::string file_name = name;
134 if( file_name == "."
135 || file_name ==".."
136 || file_name=="posixrules"
137 || file_name=="localtime")
138 {
139 continue;
140 }
141 struct stat st;
142 std::string path = dir+"/"+file_name;
143 if(stat(path.c_str(),&st)==0) {
144 if(S_ISDIR(st.st_mode)) {
145 std::string res = find_file_in(ref,size,path);
146 if(!res.empty())
147 return file_name + "/" + res;
148 }
149 else {
150 if(size_t(st.st_size) == size && files_equal(path,ref)) {
151 return file_name;
152 }
153 }
154 }
155 }
156 return std::string();
157 }
158
159 // This actually emulates ICU's search
160 // algorithm... just it ignores localtime
161 std::string detect_correct_time_zone()
162 {
163
164 char const *tz_dir = "/usr/share/zoneinfo";
165 char const *tz_file = "/etc/localtime";
166
167 struct stat st;
168 if(::stat(tz_file,&st)!=0)
169 return std::string();
170 size_t size = st.st_size;
171 std::string r = find_file_in(tz_file,size,tz_dir);
172 if(r.empty())
173 return r;
174 if(r.compare(0,6,"posix/")==0 || r.compare(0,6,"right/",6)==0)
175 return r.substr(6);
176 return r;
177 }
178
179
180 //
181 // Using pthread as:
182 // - This bug is relevant for only Linux, BSD, Mac OS X and
183 // pthreads are native threading API
184 // - The dependency on boost.thread may be removed when using
185 // more recent ICU versions (so TLS would not be needed)
186 //
187 // This the dependency on Boost.Thread is eliminated
188 //
189
190 pthread_once_t init_tz = PTHREAD_ONCE_INIT;
191 std::string default_time_zone_name;
192
193 extern "C" {
194 static void init_tz_proc()
195 {
196 try {
197 default_time_zone_name = detect_correct_time_zone();
198 }
199 catch(...){}
200 }
201 }
202
203 std::string get_time_zone_name()
204 {
205 pthread_once(&init_tz,init_tz_proc);
206 return default_time_zone_name;
207 }
208
209
210 } // namespace
211
212 icu::TimeZone *get_time_zone(std::string const &time_zone)
213 {
214
215 if(!time_zone.empty()) {
216 return icu::TimeZone::createTimeZone(time_zone.c_str());
217 }
11fdf7f2 218 hold_ptr<icu::TimeZone> tz(icu::TimeZone::createDefault());
7c673cae
FG
219 icu::UnicodeString id;
220 tz->getID(id);
221 // Check if there is a bug?
222 if(id != icu::UnicodeString("localtime"))
223 return tz.release();
224 // Now let's deal with the bug and run the fixed
225 // search loop as that of ICU
226 std::string real_id = get_time_zone_name();
227 if(real_id.empty()) {
228 // if we failed fallback to ICU's time zone
229 return tz.release();
230 }
231 return icu::TimeZone::createTimeZone(real_id.c_str());
232 }
233 #endif // bug workaround
234
235 }
236 }
237}
238
239// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4