putil.cpp 79 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491
  1. // © 2016 and later: Unicode, Inc. and others.
  2. // License & terms of use: http://www.unicode.org/copyright.html
  3. /*
  4. ******************************************************************************
  5. *
  6. * Copyright (C) 1997-2016, International Business Machines
  7. * Corporation and others. All Rights Reserved.
  8. *
  9. ******************************************************************************
  10. *
  11. * FILE NAME : putil.c (previously putil.cpp and ptypes.cpp)
  12. *
  13. * Date Name Description
  14. * 04/14/97 aliu Creation.
  15. * 04/24/97 aliu Added getDefaultDataDirectory() and
  16. * getDefaultLocaleID().
  17. * 04/28/97 aliu Rewritten to assume Unix and apply general methods
  18. * for assumed case. Non-UNIX platforms must be
  19. * special-cased. Rewrote numeric methods dealing
  20. * with NaN and Infinity to be platform independent
  21. * over all IEEE 754 platforms.
  22. * 05/13/97 aliu Restored sign of timezone
  23. * (semantics are hours West of GMT)
  24. * 06/16/98 erm Added IEEE_754 stuff, cleaned up isInfinite, isNan,
  25. * nextDouble..
  26. * 07/22/98 stephen Added remainder, max, min, trunc
  27. * 08/13/98 stephen Added isNegativeInfinity, isPositiveInfinity
  28. * 08/24/98 stephen Added longBitsFromDouble
  29. * 09/08/98 stephen Minor changes for Mac Port
  30. * 03/02/99 stephen Removed openFile(). Added AS400 support.
  31. * Fixed EBCDIC tables
  32. * 04/15/99 stephen Converted to C.
  33. * 06/28/99 stephen Removed mutex locking in u_isBigEndian().
  34. * 08/04/99 jeffrey R. Added OS/2 changes
  35. * 11/15/99 helena Integrated S/390 IEEE support.
  36. * 04/26/01 Barry N. OS/400 support for uprv_getDefaultLocaleID
  37. * 08/15/01 Steven H. OS/400 support for uprv_getDefaultCodepage
  38. * 01/03/08 Steven L. Fake Time Support
  39. ******************************************************************************
  40. */
  41. // Defines _XOPEN_SOURCE for access to POSIX functions.
  42. // Must be before any other #includes.
  43. #include "uposixdefs.h"
  44. // First, the platform type. Need this for U_PLATFORM.
  45. #include "unicode/platform.h"
  46. #if U_PLATFORM == U_PF_MINGW && defined __STRICT_ANSI__
  47. /* tzset isn't defined in strict ANSI on MinGW. */
  48. #undef __STRICT_ANSI__
  49. #endif
  50. /*
  51. * Cygwin with GCC requires inclusion of time.h after the above disabling strict asci mode statement.
  52. */
  53. #include <time.h>
  54. #if !U_PLATFORM_USES_ONLY_WIN32_API
  55. #include <sys/time.h>
  56. #endif
  57. /* include the rest of the ICU headers */
  58. #include "unicode/putil.h"
  59. #include "unicode/ustring.h"
  60. #include "putilimp.h"
  61. #include "uassert.h"
  62. #include "umutex.h"
  63. #include "cmemory.h"
  64. #include "cstring.h"
  65. #include "locmap.h"
  66. #include "ucln_cmn.h"
  67. #include "charstr.h"
  68. /* Include standard headers. */
  69. #include <stdio.h>
  70. #include <stdlib.h>
  71. #include <string.h>
  72. #include <math.h>
  73. #include <locale.h>
  74. #include <float.h>
  75. #ifndef U_COMMON_IMPLEMENTATION
  76. #error U_COMMON_IMPLEMENTATION not set - must be set for all ICU source files in common/ - see https://unicode-org.github.io/icu/userguide/howtouseicu
  77. #endif
  78. /* include system headers */
  79. #if U_PLATFORM_USES_ONLY_WIN32_API
  80. /*
  81. * TODO: U_PLATFORM_USES_ONLY_WIN32_API includes MinGW.
  82. * Should Cygwin be included as well (U_PLATFORM_HAS_WIN32_API)
  83. * to use native APIs as much as possible?
  84. */
  85. #ifndef WIN32_LEAN_AND_MEAN
  86. # define WIN32_LEAN_AND_MEAN
  87. #endif
  88. # define VC_EXTRALEAN
  89. # define NOUSER
  90. # define NOSERVICE
  91. # define NOIME
  92. # define NOMCX
  93. # include <windows.h>
  94. # include "unicode/uloc.h"
  95. # include "wintz.h"
  96. #elif U_PLATFORM == U_PF_OS400
  97. # include <float.h>
  98. # include <qusec.h> /* error code structure */
  99. # include <qusrjobi.h>
  100. # include <qliept.h> /* EPT_CALL macro - this include must be after all other "QSYSINCs" */
  101. # include <mih/testptr.h> /* For uprv_maximumPtr */
  102. #elif U_PLATFORM == U_PF_OS390
  103. # include "unicode/ucnv.h" /* Needed for UCNV_SWAP_LFNL_OPTION_STRING */
  104. #elif U_PLATFORM_IS_DARWIN_BASED || U_PLATFORM_IS_LINUX_BASED || U_PLATFORM == U_PF_BSD || U_PLATFORM == U_PF_SOLARIS
  105. # include <limits.h>
  106. # include <unistd.h>
  107. # if U_PLATFORM == U_PF_SOLARIS
  108. # ifndef _XPG4_2
  109. # define _XPG4_2
  110. # endif
  111. # elif U_PLATFORM == U_PF_ANDROID
  112. # include <sys/system_properties.h>
  113. # include <dlfcn.h>
  114. # endif
  115. #elif U_PLATFORM == U_PF_QNX
  116. # include <sys/neutrino.h>
  117. #endif
  118. /*
  119. * Only include langinfo.h if we have a way to get the codeset. If we later
  120. * depend on more feature, we can test on U_HAVE_NL_LANGINFO.
  121. *
  122. */
  123. #if U_HAVE_NL_LANGINFO_CODESET
  124. #include <langinfo.h>
  125. #endif
  126. /**
  127. * Simple things (presence of functions, etc) should just go in configure.in and be added to
  128. * icucfg.h via autoheader.
  129. */
  130. #if U_PLATFORM_IMPLEMENTS_POSIX
  131. # if U_PLATFORM == U_PF_OS400
  132. # define HAVE_DLFCN_H 0
  133. # define HAVE_DLOPEN 0
  134. # else
  135. # ifndef HAVE_DLFCN_H
  136. # define HAVE_DLFCN_H 1
  137. # endif
  138. # ifndef HAVE_DLOPEN
  139. # define HAVE_DLOPEN 1
  140. # endif
  141. # endif
  142. # ifndef HAVE_GETTIMEOFDAY
  143. # define HAVE_GETTIMEOFDAY 1
  144. # endif
  145. #else
  146. # define HAVE_DLFCN_H 0
  147. # define HAVE_DLOPEN 0
  148. # define HAVE_GETTIMEOFDAY 0
  149. #endif
  150. U_NAMESPACE_USE
  151. /* Define the extension for data files, again... */
  152. #define DATA_TYPE "dat"
  153. /* Leave this copyright notice here! */
  154. static const char copyright[] = U_COPYRIGHT_STRING;
  155. /* floating point implementations ------------------------------------------- */
  156. /* We return QNAN rather than SNAN*/
  157. #define SIGN 0x80000000U
  158. /* Make it easy to define certain types of constants */
  159. typedef union {
  160. int64_t i64; /* This must be defined first in order to allow the initialization to work. This is a C89 feature. */
  161. double d64;
  162. } BitPatternConversion;
  163. static const BitPatternConversion gNan = { (int64_t) INT64_C(0x7FF8000000000000) };
  164. static const BitPatternConversion gInf = { (int64_t) INT64_C(0x7FF0000000000000) };
  165. /*---------------------------------------------------------------------------
  166. Platform utilities
  167. Our general strategy is to assume we're on a POSIX platform. Platforms which
  168. are non-POSIX must declare themselves so. The default POSIX implementation
  169. will sometimes work for non-POSIX platforms as well (e.g., the NaN-related
  170. functions).
  171. ---------------------------------------------------------------------------*/
  172. #if U_PLATFORM_USES_ONLY_WIN32_API || U_PLATFORM == U_PF_OS400
  173. # undef U_POSIX_LOCALE
  174. #else
  175. # define U_POSIX_LOCALE 1
  176. #endif
  177. /*
  178. WARNING! u_topNBytesOfDouble and u_bottomNBytesOfDouble
  179. can't be properly optimized by the gcc compiler sometimes (i.e. gcc 3.2).
  180. */
  181. #if !IEEE_754
  182. static char*
  183. u_topNBytesOfDouble(double* d, int n)
  184. {
  185. #if U_IS_BIG_ENDIAN
  186. return (char*)d;
  187. #else
  188. return (char*)(d + 1) - n;
  189. #endif
  190. }
  191. static char*
  192. u_bottomNBytesOfDouble(double* d, int n)
  193. {
  194. #if U_IS_BIG_ENDIAN
  195. return (char*)(d + 1) - n;
  196. #else
  197. return (char*)d;
  198. #endif
  199. }
  200. #endif /* !IEEE_754 */
  201. #if IEEE_754
  202. static UBool
  203. u_signBit(double d) {
  204. uint8_t hiByte;
  205. #if U_IS_BIG_ENDIAN
  206. hiByte = *(uint8_t *)&d;
  207. #else
  208. hiByte = *(((uint8_t *)&d) + sizeof(double) - 1);
  209. #endif
  210. return (hiByte & 0x80) != 0;
  211. }
  212. #endif
  213. #if defined (U_DEBUG_FAKETIME)
  214. /* Override the clock to test things without having to move the system clock.
  215. * Assumes POSIX gettimeofday() will function
  216. */
  217. UDate fakeClock_t0 = 0; /** Time to start the clock from **/
  218. UDate fakeClock_dt = 0; /** Offset (fake time - real time) **/
  219. UBool fakeClock_set = false; /** True if fake clock has spun up **/
  220. static UDate getUTCtime_real() {
  221. struct timeval posixTime;
  222. gettimeofday(&posixTime, nullptr);
  223. return (UDate)(((int64_t)posixTime.tv_sec * U_MILLIS_PER_SECOND) + (posixTime.tv_usec/1000));
  224. }
  225. static UDate getUTCtime_fake() {
  226. static UMutex fakeClockMutex;
  227. umtx_lock(&fakeClockMutex);
  228. if(!fakeClock_set) {
  229. UDate real = getUTCtime_real();
  230. const char *fake_start = getenv("U_FAKETIME_START");
  231. if((fake_start!=nullptr) && (fake_start[0]!=0)) {
  232. sscanf(fake_start,"%lf",&fakeClock_t0);
  233. fakeClock_dt = fakeClock_t0 - real;
  234. fprintf(stderr,"U_DEBUG_FAKETIME was set at compile time, so the ICU clock will start at a preset value\n"
  235. "env variable U_FAKETIME_START=%.0f (%s) for an offset of %.0f ms from the current time %.0f\n",
  236. fakeClock_t0, fake_start, fakeClock_dt, real);
  237. } else {
  238. fakeClock_dt = 0;
  239. fprintf(stderr,"U_DEBUG_FAKETIME was set at compile time, but U_FAKETIME_START was not set.\n"
  240. "Set U_FAKETIME_START to the number of milliseconds since 1/1/1970 to set the ICU clock.\n");
  241. }
  242. fakeClock_set = true;
  243. }
  244. umtx_unlock(&fakeClockMutex);
  245. return getUTCtime_real() + fakeClock_dt;
  246. }
  247. #endif
  248. #if U_PLATFORM_USES_ONLY_WIN32_API
  249. typedef union {
  250. int64_t int64;
  251. FILETIME fileTime;
  252. } FileTimeConversion; /* This is like a ULARGE_INTEGER */
  253. /* Number of 100 nanoseconds from 1/1/1601 to 1/1/1970 */
  254. #define EPOCH_BIAS INT64_C(116444736000000000)
  255. #define HECTONANOSECOND_PER_MILLISECOND 10000
  256. #endif
  257. /*---------------------------------------------------------------------------
  258. Universal Implementations
  259. These are designed to work on all platforms. Try these, and if they
  260. don't work on your platform, then special case your platform with new
  261. implementations.
  262. ---------------------------------------------------------------------------*/
  263. U_CAPI UDate U_EXPORT2
  264. uprv_getUTCtime()
  265. {
  266. #if defined(U_DEBUG_FAKETIME)
  267. return getUTCtime_fake(); /* Hook for overriding the clock */
  268. #else
  269. return uprv_getRawUTCtime();
  270. #endif
  271. }
  272. /* Return UTC (GMT) time measured in milliseconds since 0:00 on 1/1/70.*/
  273. U_CAPI UDate U_EXPORT2
  274. uprv_getRawUTCtime()
  275. {
  276. #if U_PLATFORM_USES_ONLY_WIN32_API
  277. FileTimeConversion winTime;
  278. GetSystemTimeAsFileTime(&winTime.fileTime);
  279. return (UDate)((winTime.int64 - EPOCH_BIAS) / HECTONANOSECOND_PER_MILLISECOND);
  280. #else
  281. #if HAVE_GETTIMEOFDAY
  282. struct timeval posixTime;
  283. gettimeofday(&posixTime, nullptr);
  284. return (UDate)(((int64_t)posixTime.tv_sec * U_MILLIS_PER_SECOND) + (posixTime.tv_usec/1000));
  285. #else
  286. time_t epochtime;
  287. time(&epochtime);
  288. return (UDate)epochtime * U_MILLIS_PER_SECOND;
  289. #endif
  290. #endif
  291. }
  292. /*-----------------------------------------------------------------------------
  293. IEEE 754
  294. These methods detect and return NaN and infinity values for doubles
  295. conforming to IEEE 754. Platforms which support this standard include X86,
  296. Mac 680x0, Mac PowerPC, AIX RS/6000, and most others.
  297. If this doesn't work on your platform, you have non-IEEE floating-point, and
  298. will need to code your own versions. A naive implementation is to return 0.0
  299. for getNaN and getInfinity, and false for isNaN and isInfinite.
  300. ---------------------------------------------------------------------------*/
  301. U_CAPI UBool U_EXPORT2
  302. uprv_isNaN(double number)
  303. {
  304. #if IEEE_754
  305. BitPatternConversion convertedNumber;
  306. convertedNumber.d64 = number;
  307. /* Infinity is 0x7FF0000000000000U. Anything greater than that is a NaN */
  308. return (UBool)((convertedNumber.i64 & U_INT64_MAX) > gInf.i64);
  309. #elif U_PLATFORM == U_PF_OS390
  310. uint32_t highBits = *(uint32_t*)u_topNBytesOfDouble(&number,
  311. sizeof(uint32_t));
  312. uint32_t lowBits = *(uint32_t*)u_bottomNBytesOfDouble(&number,
  313. sizeof(uint32_t));
  314. return ((highBits & 0x7F080000L) == 0x7F080000L) &&
  315. (lowBits == 0x00000000L);
  316. #else
  317. /* If your platform doesn't support IEEE 754 but *does* have an NaN value,*/
  318. /* you'll need to replace this default implementation with what's correct*/
  319. /* for your platform.*/
  320. return number != number;
  321. #endif
  322. }
  323. U_CAPI UBool U_EXPORT2
  324. uprv_isInfinite(double number)
  325. {
  326. #if IEEE_754
  327. BitPatternConversion convertedNumber;
  328. convertedNumber.d64 = number;
  329. /* Infinity is exactly 0x7FF0000000000000U. */
  330. return (UBool)((convertedNumber.i64 & U_INT64_MAX) == gInf.i64);
  331. #elif U_PLATFORM == U_PF_OS390
  332. uint32_t highBits = *(uint32_t*)u_topNBytesOfDouble(&number,
  333. sizeof(uint32_t));
  334. uint32_t lowBits = *(uint32_t*)u_bottomNBytesOfDouble(&number,
  335. sizeof(uint32_t));
  336. return ((highBits & ~SIGN) == 0x70FF0000L) && (lowBits == 0x00000000L);
  337. #else
  338. /* If your platform doesn't support IEEE 754 but *does* have an infinity*/
  339. /* value, you'll need to replace this default implementation with what's*/
  340. /* correct for your platform.*/
  341. return number == (2.0 * number);
  342. #endif
  343. }
  344. U_CAPI UBool U_EXPORT2
  345. uprv_isPositiveInfinity(double number)
  346. {
  347. #if IEEE_754 || U_PLATFORM == U_PF_OS390
  348. return (UBool)(number > 0 && uprv_isInfinite(number));
  349. #else
  350. return uprv_isInfinite(number);
  351. #endif
  352. }
  353. U_CAPI UBool U_EXPORT2
  354. uprv_isNegativeInfinity(double number)
  355. {
  356. #if IEEE_754 || U_PLATFORM == U_PF_OS390
  357. return (UBool)(number < 0 && uprv_isInfinite(number));
  358. #else
  359. uint32_t highBits = *(uint32_t*)u_topNBytesOfDouble(&number,
  360. sizeof(uint32_t));
  361. return((highBits & SIGN) && uprv_isInfinite(number));
  362. #endif
  363. }
  364. U_CAPI double U_EXPORT2
  365. uprv_getNaN()
  366. {
  367. #if IEEE_754 || U_PLATFORM == U_PF_OS390
  368. return gNan.d64;
  369. #else
  370. /* If your platform doesn't support IEEE 754 but *does* have an NaN value,*/
  371. /* you'll need to replace this default implementation with what's correct*/
  372. /* for your platform.*/
  373. return 0.0;
  374. #endif
  375. }
  376. U_CAPI double U_EXPORT2
  377. uprv_getInfinity()
  378. {
  379. #if IEEE_754 || U_PLATFORM == U_PF_OS390
  380. return gInf.d64;
  381. #else
  382. /* If your platform doesn't support IEEE 754 but *does* have an infinity*/
  383. /* value, you'll need to replace this default implementation with what's*/
  384. /* correct for your platform.*/
  385. return 0.0;
  386. #endif
  387. }
  388. U_CAPI double U_EXPORT2
  389. uprv_floor(double x)
  390. {
  391. return floor(x);
  392. }
  393. U_CAPI double U_EXPORT2
  394. uprv_ceil(double x)
  395. {
  396. return ceil(x);
  397. }
  398. U_CAPI double U_EXPORT2
  399. uprv_round(double x)
  400. {
  401. return uprv_floor(x + 0.5);
  402. }
  403. U_CAPI double U_EXPORT2
  404. uprv_fabs(double x)
  405. {
  406. return fabs(x);
  407. }
  408. U_CAPI double U_EXPORT2
  409. uprv_modf(double x, double* y)
  410. {
  411. return modf(x, y);
  412. }
  413. U_CAPI double U_EXPORT2
  414. uprv_fmod(double x, double y)
  415. {
  416. return fmod(x, y);
  417. }
  418. U_CAPI double U_EXPORT2
  419. uprv_pow(double x, double y)
  420. {
  421. /* This is declared as "double pow(double x, double y)" */
  422. return pow(x, y);
  423. }
  424. U_CAPI double U_EXPORT2
  425. uprv_pow10(int32_t x)
  426. {
  427. return pow(10.0, (double)x);
  428. }
  429. U_CAPI double U_EXPORT2
  430. uprv_fmax(double x, double y)
  431. {
  432. #if IEEE_754
  433. /* first handle NaN*/
  434. if(uprv_isNaN(x) || uprv_isNaN(y))
  435. return uprv_getNaN();
  436. /* check for -0 and 0*/
  437. if(x == 0.0 && y == 0.0 && u_signBit(x))
  438. return y;
  439. #endif
  440. /* this should work for all flt point w/o NaN and Inf special cases */
  441. return (x > y ? x : y);
  442. }
  443. U_CAPI double U_EXPORT2
  444. uprv_fmin(double x, double y)
  445. {
  446. #if IEEE_754
  447. /* first handle NaN*/
  448. if(uprv_isNaN(x) || uprv_isNaN(y))
  449. return uprv_getNaN();
  450. /* check for -0 and 0*/
  451. if(x == 0.0 && y == 0.0 && u_signBit(y))
  452. return y;
  453. #endif
  454. /* this should work for all flt point w/o NaN and Inf special cases */
  455. return (x > y ? y : x);
  456. }
  457. U_CAPI UBool U_EXPORT2
  458. uprv_add32_overflow(int32_t a, int32_t b, int32_t* res) {
  459. // NOTE: Some compilers (GCC, Clang) have primitives available, like __builtin_add_overflow.
  460. // This function could be optimized by calling one of those primitives.
  461. auto a64 = static_cast<int64_t>(a);
  462. auto b64 = static_cast<int64_t>(b);
  463. int64_t res64 = a64 + b64;
  464. *res = static_cast<int32_t>(res64);
  465. return res64 != *res;
  466. }
  467. U_CAPI UBool U_EXPORT2
  468. uprv_mul32_overflow(int32_t a, int32_t b, int32_t* res) {
  469. // NOTE: Some compilers (GCC, Clang) have primitives available, like __builtin_mul_overflow.
  470. // This function could be optimized by calling one of those primitives.
  471. auto a64 = static_cast<int64_t>(a);
  472. auto b64 = static_cast<int64_t>(b);
  473. int64_t res64 = a64 * b64;
  474. *res = static_cast<int32_t>(res64);
  475. return res64 != *res;
  476. }
  477. /**
  478. * Truncates the given double.
  479. * trunc(3.3) = 3.0, trunc (-3.3) = -3.0
  480. * This is different than calling floor() or ceil():
  481. * floor(3.3) = 3, floor(-3.3) = -4
  482. * ceil(3.3) = 4, ceil(-3.3) = -3
  483. */
  484. U_CAPI double U_EXPORT2
  485. uprv_trunc(double d)
  486. {
  487. #if IEEE_754
  488. /* handle error cases*/
  489. if(uprv_isNaN(d))
  490. return uprv_getNaN();
  491. if(uprv_isInfinite(d))
  492. return uprv_getInfinity();
  493. if(u_signBit(d)) /* Signbit() picks up -0.0; d<0 does not. */
  494. return ceil(d);
  495. else
  496. return floor(d);
  497. #else
  498. return d >= 0 ? floor(d) : ceil(d);
  499. #endif
  500. }
  501. /**
  502. * Return the largest positive number that can be represented by an integer
  503. * type of arbitrary bit length.
  504. */
  505. U_CAPI double U_EXPORT2
  506. uprv_maxMantissa()
  507. {
  508. return pow(2.0, DBL_MANT_DIG + 1.0) - 1.0;
  509. }
  510. U_CAPI double U_EXPORT2
  511. uprv_log(double d)
  512. {
  513. return log(d);
  514. }
  515. U_CAPI void * U_EXPORT2
  516. uprv_maximumPtr(void * base)
  517. {
  518. #if U_PLATFORM == U_PF_OS400
  519. /*
  520. * With the provided function we should never be out of range of a given segment
  521. * (a traditional/typical segment that is). Our segments have 5 bytes for the
  522. * id and 3 bytes for the offset. The key is that the casting takes care of
  523. * only retrieving the offset portion minus x1000. Hence, the smallest offset
  524. * seen in a program is x001000 and when casted to an int would be 0.
  525. * That's why we can only add 0xffefff. Otherwise, we would exceed the segment.
  526. *
  527. * Currently, 16MB is the current addressing limitation on i5/OS if the activation is
  528. * non-TERASPACE. If it is TERASPACE it is 2GB - 4k(header information).
  529. * This function determines the activation based on the pointer that is passed in and
  530. * calculates the appropriate maximum available size for
  531. * each pointer type (TERASPACE and non-TERASPACE)
  532. *
  533. * Unlike other operating systems, the pointer model isn't determined at
  534. * compile time on i5/OS.
  535. */
  536. if ((base != nullptr) && (_TESTPTR(base, _C_TERASPACE_CHECK))) {
  537. /* if it is a TERASPACE pointer the max is 2GB - 4k */
  538. return ((void *)(((char *)base)-((uint32_t)(base))+((uint32_t)0x7fffefff)));
  539. }
  540. /* otherwise 16MB since nullptr ptr is not checkable or the ptr is not TERASPACE */
  541. return ((void *)(((char *)base)-((uint32_t)(base))+((uint32_t)0xffefff)));
  542. #else
  543. return U_MAX_PTR(base);
  544. #endif
  545. }
  546. /*---------------------------------------------------------------------------
  547. Platform-specific Implementations
  548. Try these, and if they don't work on your platform, then special case your
  549. platform with new implementations.
  550. ---------------------------------------------------------------------------*/
  551. /* Generic time zone layer -------------------------------------------------- */
  552. /* Time zone utilities */
  553. U_CAPI void U_EXPORT2
  554. uprv_tzset()
  555. {
  556. #if defined(U_TZSET)
  557. U_TZSET();
  558. #else
  559. /* no initialization*/
  560. #endif
  561. }
  562. U_CAPI int32_t U_EXPORT2
  563. uprv_timezone()
  564. {
  565. #ifdef U_TIMEZONE
  566. return U_TIMEZONE;
  567. #else
  568. time_t t, t1, t2;
  569. struct tm tmrec;
  570. int32_t tdiff = 0;
  571. time(&t);
  572. uprv_memcpy( &tmrec, localtime(&t), sizeof(tmrec) );
  573. #if U_PLATFORM != U_PF_IPHONE
  574. UBool dst_checked = (tmrec.tm_isdst != 0); /* daylight savings time is checked*/
  575. #endif
  576. t1 = mktime(&tmrec); /* local time in seconds*/
  577. uprv_memcpy( &tmrec, gmtime(&t), sizeof(tmrec) );
  578. t2 = mktime(&tmrec); /* GMT (or UTC) in seconds*/
  579. tdiff = t2 - t1;
  580. #if U_PLATFORM != U_PF_IPHONE
  581. /* imitate NT behaviour, which returns same timezone offset to GMT for
  582. winter and summer.
  583. This does not work on all platforms. For instance, on glibc on Linux
  584. and on Mac OS 10.5, tdiff calculated above remains the same
  585. regardless of whether DST is in effect or not. iOS is another
  586. platform where this does not work. Linux + glibc and Mac OS 10.5
  587. have U_TIMEZONE defined so that this code is not reached.
  588. */
  589. if (dst_checked)
  590. tdiff += 3600;
  591. #endif
  592. return tdiff;
  593. #endif
  594. }
  595. /* Note that U_TZNAME does *not* have to be tzname, but if it is,
  596. some platforms need to have it declared here. */
  597. #if defined(U_TZNAME) && (U_PLATFORM == U_PF_IRIX || U_PLATFORM_IS_DARWIN_BASED)
  598. /* RS6000 and others reject char **tzname. */
  599. extern U_IMPORT char *U_TZNAME[];
  600. #endif
  601. #if !UCONFIG_NO_FILE_IO && ((U_PLATFORM_IS_DARWIN_BASED && (U_PLATFORM != U_PF_IPHONE || defined(U_TIMEZONE))) || U_PLATFORM_IS_LINUX_BASED || U_PLATFORM == U_PF_BSD || U_PLATFORM == U_PF_SOLARIS)
  602. /* These platforms are likely to use Olson timezone IDs. */
  603. /* common targets of the symbolic link at TZDEFAULT are:
  604. * "/usr/share/zoneinfo/<olsonID>" default, older Linux distros, macOS to 10.12
  605. * "../usr/share/zoneinfo/<olsonID>" newer Linux distros: Red Hat Enterprise Linux 7, Ubuntu 16, SuSe Linux 12
  606. * "/usr/share/lib/zoneinfo/<olsonID>" Solaris
  607. * "../usr/share/lib/zoneinfo/<olsonID>" Solaris
  608. * "/var/db/timezone/zoneinfo/<olsonID>" macOS 10.13
  609. * To avoid checking lots of paths, just check that the target path
  610. * before the <olsonID> ends with "/zoneinfo/", and the <olsonID> is valid.
  611. */
  612. #define CHECK_LOCALTIME_LINK 1
  613. #if U_PLATFORM_IS_DARWIN_BASED
  614. #include <tzfile.h>
  615. #define TZZONEINFO (TZDIR "/")
  616. #elif U_PLATFORM == U_PF_SOLARIS
  617. #define TZDEFAULT "/etc/localtime"
  618. #define TZZONEINFO "/usr/share/lib/zoneinfo/"
  619. #define TZ_ENV_CHECK "localtime"
  620. #else
  621. #define TZDEFAULT "/etc/localtime"
  622. #define TZZONEINFO "/usr/share/zoneinfo/"
  623. #endif
  624. #define TZZONEINFOTAIL "/zoneinfo/"
  625. #if U_HAVE_DIRENT_H
  626. #define TZFILE_SKIP "posixrules" /* tz file to skip when searching. */
  627. /* Some Linux distributions have 'localtime' in /usr/share/zoneinfo
  628. symlinked to /etc/localtime, which makes searchForTZFile return
  629. 'localtime' when it's the first match. */
  630. #define TZFILE_SKIP2 "localtime"
  631. #define SEARCH_TZFILE
  632. #include <dirent.h> /* Needed to search through system timezone files */
  633. #endif
  634. static char gTimeZoneBuffer[PATH_MAX];
  635. static const char *gTimeZoneBufferPtr = nullptr;
  636. #endif
  637. #if !U_PLATFORM_USES_ONLY_WIN32_API
  638. #define isNonDigit(ch) (ch < '0' || '9' < ch)
  639. #define isDigit(ch) ('0' <= ch && ch <= '9')
  640. static UBool isValidOlsonID(const char *id) {
  641. int32_t idx = 0;
  642. int32_t idxMax = 0;
  643. /* Determine if this is something like Iceland (Olson ID)
  644. or AST4ADT (non-Olson ID) */
  645. while (id[idx] && isNonDigit(id[idx]) && id[idx] != ',') {
  646. idx++;
  647. }
  648. /* Allow at maximum 2 numbers at the end of the id to support zone id's
  649. like GMT+11. */
  650. idxMax = idx + 2;
  651. while (id[idx] && isDigit(id[idx]) && idx < idxMax) {
  652. idx++;
  653. }
  654. /* If we went through the whole string, then it might be okay.
  655. The timezone is sometimes set to "CST-7CDT", "CST6CDT5,J129,J131/19:30",
  656. "GRNLNDST3GRNLNDDT" or similar, so we cannot use it.
  657. The rest of the time it could be an Olson ID. George */
  658. return (UBool)(id[idx] == 0
  659. || uprv_strcmp(id, "PST8PDT") == 0
  660. || uprv_strcmp(id, "MST7MDT") == 0
  661. || uprv_strcmp(id, "CST6CDT") == 0
  662. || uprv_strcmp(id, "EST5EDT") == 0);
  663. }
  664. /* On some Unix-like OS, 'posix' subdirectory in
  665. /usr/share/zoneinfo replicates the top-level contents. 'right'
  666. subdirectory has the same set of files, but individual files
  667. are different from those in the top-level directory or 'posix'
  668. because 'right' has files for TAI (Int'l Atomic Time) while 'posix'
  669. has files for UTC.
  670. When the first match for /etc/localtime is in either of them
  671. (usually in posix because 'right' has different file contents),
  672. or TZ environment variable points to one of them, createTimeZone
  673. fails because, say, 'posix/America/New_York' is not an Olson
  674. timezone id ('America/New_York' is). So, we have to skip
  675. 'posix/' and 'right/' at the beginning. */
  676. static void skipZoneIDPrefix(const char** id) {
  677. if (uprv_strncmp(*id, "posix/", 6) == 0
  678. || uprv_strncmp(*id, "right/", 6) == 0)
  679. {
  680. *id += 6;
  681. }
  682. }
  683. #endif
  684. #if defined(U_TZNAME) && !U_PLATFORM_USES_ONLY_WIN32_API
  685. #define CONVERT_HOURS_TO_SECONDS(offset) (int32_t)(offset*3600)
  686. typedef struct OffsetZoneMapping {
  687. int32_t offsetSeconds;
  688. int32_t daylightType; /* 0=U_DAYLIGHT_NONE, 1=daylight in June-U_DAYLIGHT_JUNE, 2=daylight in December=U_DAYLIGHT_DECEMBER*/
  689. const char *stdID;
  690. const char *dstID;
  691. const char *olsonID;
  692. } OffsetZoneMapping;
  693. enum { U_DAYLIGHT_NONE=0,U_DAYLIGHT_JUNE=1,U_DAYLIGHT_DECEMBER=2 };
  694. /*
  695. This list tries to disambiguate a set of abbreviated timezone IDs and offsets
  696. and maps it to an Olson ID.
  697. Before adding anything to this list, take a look at
  698. icu/source/tools/tzcode/tz.alias
  699. Sometimes no daylight savings (0) is important to define due to aliases.
  700. This list can be tested with icu/source/test/compat/tzone.pl
  701. More values could be added to daylightType to increase precision.
  702. */
  703. static const struct OffsetZoneMapping OFFSET_ZONE_MAPPINGS[] = {
  704. {-45900, 2, "CHAST", "CHADT", "Pacific/Chatham"},
  705. {-43200, 1, "PETT", "PETST", "Asia/Kamchatka"},
  706. {-43200, 2, "NZST", "NZDT", "Pacific/Auckland"},
  707. {-43200, 1, "ANAT", "ANAST", "Asia/Anadyr"},
  708. {-39600, 1, "MAGT", "MAGST", "Asia/Magadan"},
  709. {-37800, 2, "LHST", "LHST", "Australia/Lord_Howe"},
  710. {-36000, 2, "EST", "EST", "Australia/Sydney"},
  711. {-36000, 1, "SAKT", "SAKST", "Asia/Sakhalin"},
  712. {-36000, 1, "VLAT", "VLAST", "Asia/Vladivostok"},
  713. {-34200, 2, "CST", "CST", "Australia/South"},
  714. {-32400, 1, "YAKT", "YAKST", "Asia/Yakutsk"},
  715. {-32400, 1, "CHOT", "CHOST", "Asia/Choibalsan"},
  716. {-31500, 2, "CWST", "CWST", "Australia/Eucla"},
  717. {-28800, 1, "IRKT", "IRKST", "Asia/Irkutsk"},
  718. {-28800, 1, "ULAT", "ULAST", "Asia/Ulaanbaatar"},
  719. {-28800, 2, "WST", "WST", "Australia/West"},
  720. {-25200, 1, "HOVT", "HOVST", "Asia/Hovd"},
  721. {-25200, 1, "KRAT", "KRAST", "Asia/Krasnoyarsk"},
  722. {-21600, 1, "NOVT", "NOVST", "Asia/Novosibirsk"},
  723. {-21600, 1, "OMST", "OMSST", "Asia/Omsk"},
  724. {-18000, 1, "YEKT", "YEKST", "Asia/Yekaterinburg"},
  725. {-14400, 1, "SAMT", "SAMST", "Europe/Samara"},
  726. {-14400, 1, "AMT", "AMST", "Asia/Yerevan"},
  727. {-14400, 1, "AZT", "AZST", "Asia/Baku"},
  728. {-10800, 1, "AST", "ADT", "Asia/Baghdad"},
  729. {-10800, 1, "MSK", "MSD", "Europe/Moscow"},
  730. {-10800, 1, "VOLT", "VOLST", "Europe/Volgograd"},
  731. {-7200, 0, "EET", "CEST", "Africa/Tripoli"},
  732. {-7200, 1, "EET", "EEST", "Europe/Athens"}, /* Conflicts with Africa/Cairo */
  733. {-7200, 1, "IST", "IDT", "Asia/Jerusalem"},
  734. {-3600, 0, "CET", "WEST", "Africa/Algiers"},
  735. {-3600, 2, "WAT", "WAST", "Africa/Windhoek"},
  736. {0, 1, "GMT", "IST", "Europe/Dublin"},
  737. {0, 1, "GMT", "BST", "Europe/London"},
  738. {0, 0, "WET", "WEST", "Africa/Casablanca"},
  739. {0, 0, "WET", "WET", "Africa/El_Aaiun"},
  740. {3600, 1, "AZOT", "AZOST", "Atlantic/Azores"},
  741. {3600, 1, "EGT", "EGST", "America/Scoresbysund"},
  742. {10800, 1, "PMST", "PMDT", "America/Miquelon"},
  743. {10800, 2, "UYT", "UYST", "America/Montevideo"},
  744. {10800, 1, "WGT", "WGST", "America/Godthab"},
  745. {10800, 2, "BRT", "BRST", "Brazil/East"},
  746. {12600, 1, "NST", "NDT", "America/St_Johns"},
  747. {14400, 1, "AST", "ADT", "Canada/Atlantic"},
  748. {14400, 2, "AMT", "AMST", "America/Cuiaba"},
  749. {14400, 2, "CLT", "CLST", "Chile/Continental"},
  750. {14400, 2, "FKT", "FKST", "Atlantic/Stanley"},
  751. {14400, 2, "PYT", "PYST", "America/Asuncion"},
  752. {18000, 1, "CST", "CDT", "America/Havana"},
  753. {18000, 1, "EST", "EDT", "US/Eastern"}, /* Conflicts with America/Grand_Turk */
  754. {21600, 2, "EAST", "EASST", "Chile/EasterIsland"},
  755. {21600, 0, "CST", "MDT", "Canada/Saskatchewan"},
  756. {21600, 0, "CST", "CDT", "America/Guatemala"},
  757. {21600, 1, "CST", "CDT", "US/Central"}, /* Conflicts with Mexico/General */
  758. {25200, 1, "MST", "MDT", "US/Mountain"}, /* Conflicts with Mexico/BajaSur */
  759. {28800, 0, "PST", "PST", "Pacific/Pitcairn"},
  760. {28800, 1, "PST", "PDT", "US/Pacific"}, /* Conflicts with Mexico/BajaNorte */
  761. {32400, 1, "AKST", "AKDT", "US/Alaska"},
  762. {36000, 1, "HAST", "HADT", "US/Aleutian"}
  763. };
  764. /*#define DEBUG_TZNAME*/
  765. static const char* remapShortTimeZone(const char *stdID, const char *dstID, int32_t daylightType, int32_t offset)
  766. {
  767. int32_t idx;
  768. #ifdef DEBUG_TZNAME
  769. fprintf(stderr, "TZ=%s std=%s dst=%s daylight=%d offset=%d\n", getenv("TZ"), stdID, dstID, daylightType, offset);
  770. #endif
  771. for (idx = 0; idx < UPRV_LENGTHOF(OFFSET_ZONE_MAPPINGS); idx++)
  772. {
  773. if (offset == OFFSET_ZONE_MAPPINGS[idx].offsetSeconds
  774. && daylightType == OFFSET_ZONE_MAPPINGS[idx].daylightType
  775. && strcmp(OFFSET_ZONE_MAPPINGS[idx].stdID, stdID) == 0
  776. && strcmp(OFFSET_ZONE_MAPPINGS[idx].dstID, dstID) == 0)
  777. {
  778. return OFFSET_ZONE_MAPPINGS[idx].olsonID;
  779. }
  780. }
  781. return nullptr;
  782. }
  783. #endif
  784. #ifdef SEARCH_TZFILE
  785. #define MAX_READ_SIZE 512
  786. typedef struct DefaultTZInfo {
  787. char* defaultTZBuffer;
  788. int64_t defaultTZFileSize;
  789. FILE* defaultTZFilePtr;
  790. UBool defaultTZstatus;
  791. int32_t defaultTZPosition;
  792. } DefaultTZInfo;
  793. /*
  794. * This method compares the two files given to see if they are a match.
  795. * It is currently use to compare two TZ files.
  796. */
  797. static UBool compareBinaryFiles(const char* defaultTZFileName, const char* TZFileName, DefaultTZInfo* tzInfo) {
  798. FILE* file;
  799. int64_t sizeFile;
  800. int64_t sizeFileLeft;
  801. int32_t sizeFileRead;
  802. int32_t sizeFileToRead;
  803. char bufferFile[MAX_READ_SIZE];
  804. UBool result = true;
  805. if (tzInfo->defaultTZFilePtr == nullptr) {
  806. tzInfo->defaultTZFilePtr = fopen(defaultTZFileName, "r");
  807. }
  808. file = fopen(TZFileName, "r");
  809. tzInfo->defaultTZPosition = 0; /* reset position to begin search */
  810. if (file != nullptr && tzInfo->defaultTZFilePtr != nullptr) {
  811. /* First check that the file size are equal. */
  812. if (tzInfo->defaultTZFileSize == 0) {
  813. fseek(tzInfo->defaultTZFilePtr, 0, SEEK_END);
  814. tzInfo->defaultTZFileSize = ftell(tzInfo->defaultTZFilePtr);
  815. }
  816. fseek(file, 0, SEEK_END);
  817. sizeFile = ftell(file);
  818. sizeFileLeft = sizeFile;
  819. if (sizeFile != tzInfo->defaultTZFileSize) {
  820. result = false;
  821. } else {
  822. /* Store the data from the files in separate buffers and
  823. * compare each byte to determine equality.
  824. */
  825. if (tzInfo->defaultTZBuffer == nullptr) {
  826. rewind(tzInfo->defaultTZFilePtr);
  827. tzInfo->defaultTZBuffer = (char*)uprv_malloc(sizeof(char) * tzInfo->defaultTZFileSize);
  828. sizeFileRead = fread(tzInfo->defaultTZBuffer, 1, tzInfo->defaultTZFileSize, tzInfo->defaultTZFilePtr);
  829. }
  830. rewind(file);
  831. while(sizeFileLeft > 0) {
  832. uprv_memset(bufferFile, 0, MAX_READ_SIZE);
  833. sizeFileToRead = sizeFileLeft < MAX_READ_SIZE ? sizeFileLeft : MAX_READ_SIZE;
  834. sizeFileRead = fread(bufferFile, 1, sizeFileToRead, file);
  835. if (memcmp(tzInfo->defaultTZBuffer + tzInfo->defaultTZPosition, bufferFile, sizeFileRead) != 0) {
  836. result = false;
  837. break;
  838. }
  839. sizeFileLeft -= sizeFileRead;
  840. tzInfo->defaultTZPosition += sizeFileRead;
  841. }
  842. }
  843. } else {
  844. result = false;
  845. }
  846. if (file != nullptr) {
  847. fclose(file);
  848. }
  849. return result;
  850. }
  851. /* dirent also lists two entries: "." and ".." that we can safely ignore. */
  852. #define SKIP1 "."
  853. #define SKIP2 ".."
  854. static UBool U_CALLCONV putil_cleanup();
  855. static CharString *gSearchTZFileResult = nullptr;
  856. /*
  857. * This method recursively traverses the directory given for a matching TZ file and returns the first match.
  858. * This function is not thread safe - it uses a global, gSearchTZFileResult, to hold its results.
  859. */
  860. static char* searchForTZFile(const char* path, DefaultTZInfo* tzInfo) {
  861. DIR* dirp = nullptr;
  862. struct dirent* dirEntry = nullptr;
  863. char* result = nullptr;
  864. UErrorCode status = U_ZERO_ERROR;
  865. /* Save the current path */
  866. CharString curpath(path, -1, status);
  867. if (U_FAILURE(status)) {
  868. goto cleanupAndReturn;
  869. }
  870. dirp = opendir(path);
  871. if (dirp == nullptr) {
  872. goto cleanupAndReturn;
  873. }
  874. if (gSearchTZFileResult == nullptr) {
  875. gSearchTZFileResult = new CharString;
  876. if (gSearchTZFileResult == nullptr) {
  877. goto cleanupAndReturn;
  878. }
  879. ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup);
  880. }
  881. /* Check each entry in the directory. */
  882. while((dirEntry = readdir(dirp)) != nullptr) {
  883. const char* dirName = dirEntry->d_name;
  884. if (uprv_strcmp(dirName, SKIP1) != 0 && uprv_strcmp(dirName, SKIP2) != 0
  885. && uprv_strcmp(TZFILE_SKIP, dirName) != 0 && uprv_strcmp(TZFILE_SKIP2, dirName) != 0) {
  886. /* Create a newpath with the new entry to test each entry in the directory. */
  887. CharString newpath(curpath, status);
  888. newpath.append(dirName, -1, status);
  889. if (U_FAILURE(status)) {
  890. break;
  891. }
  892. DIR* subDirp = nullptr;
  893. if ((subDirp = opendir(newpath.data())) != nullptr) {
  894. /* If this new path is a directory, make a recursive call with the newpath. */
  895. closedir(subDirp);
  896. newpath.append('/', status);
  897. if (U_FAILURE(status)) {
  898. break;
  899. }
  900. result = searchForTZFile(newpath.data(), tzInfo);
  901. /*
  902. Have to get out here. Otherwise, we'd keep looking
  903. and return the first match in the top-level directory
  904. if there's a match in the top-level. If not, this function
  905. would return nullptr and set gTimeZoneBufferPtr to nullptr in initDefault().
  906. It worked without this in most cases because we have a fallback of calling
  907. localtime_r to figure out the default timezone.
  908. */
  909. if (result != nullptr)
  910. break;
  911. } else {
  912. if(compareBinaryFiles(TZDEFAULT, newpath.data(), tzInfo)) {
  913. int32_t amountToSkip = sizeof(TZZONEINFO) - 1;
  914. if (amountToSkip > newpath.length()) {
  915. amountToSkip = newpath.length();
  916. }
  917. const char* zoneid = newpath.data() + amountToSkip;
  918. skipZoneIDPrefix(&zoneid);
  919. gSearchTZFileResult->clear();
  920. gSearchTZFileResult->append(zoneid, -1, status);
  921. if (U_FAILURE(status)) {
  922. break;
  923. }
  924. result = gSearchTZFileResult->data();
  925. /* Get out after the first one found. */
  926. break;
  927. }
  928. }
  929. }
  930. }
  931. cleanupAndReturn:
  932. if (dirp) {
  933. closedir(dirp);
  934. }
  935. return result;
  936. }
  937. #endif
  938. #if U_PLATFORM == U_PF_ANDROID
  939. typedef int(system_property_read_callback)(const prop_info* info,
  940. void (*callback)(void* cookie,
  941. const char* name,
  942. const char* value,
  943. uint32_t serial),
  944. void* cookie);
  945. typedef int(system_property_get)(const char*, char*);
  946. static char gAndroidTimeZone[PROP_VALUE_MAX] = { '\0' };
  947. static void u_property_read(void* cookie, const char* name, const char* value,
  948. uint32_t serial) {
  949. uprv_strcpy((char* )cookie, value);
  950. }
  951. #endif
  952. U_CAPI void U_EXPORT2
  953. uprv_tzname_clear_cache()
  954. {
  955. #if U_PLATFORM == U_PF_ANDROID
  956. /* Android's timezone is stored in system property. */
  957. gAndroidTimeZone[0] = '\0';
  958. void* libc = dlopen("libc.so", RTLD_NOLOAD);
  959. if (libc) {
  960. /* Android API 26+ has new API to get system property and old API
  961. * (__system_property_get) is deprecated */
  962. system_property_read_callback* property_read_callback =
  963. (system_property_read_callback*)dlsym(
  964. libc, "__system_property_read_callback");
  965. if (property_read_callback) {
  966. const prop_info* info =
  967. __system_property_find("persist.sys.timezone");
  968. if (info) {
  969. property_read_callback(info, &u_property_read, gAndroidTimeZone);
  970. }
  971. } else {
  972. system_property_get* property_get =
  973. (system_property_get*)dlsym(libc, "__system_property_get");
  974. if (property_get) {
  975. property_get("persist.sys.timezone", gAndroidTimeZone);
  976. }
  977. }
  978. dlclose(libc);
  979. }
  980. #endif
  981. #if defined(CHECK_LOCALTIME_LINK) && !defined(DEBUG_SKIP_LOCALTIME_LINK)
  982. gTimeZoneBufferPtr = nullptr;
  983. #endif
  984. }
  985. U_CAPI const char* U_EXPORT2
  986. uprv_tzname(int n)
  987. {
  988. (void)n; // Avoid unreferenced parameter warning.
  989. const char *tzid = nullptr;
  990. #if U_PLATFORM_USES_ONLY_WIN32_API
  991. tzid = uprv_detectWindowsTimeZone();
  992. if (tzid != nullptr) {
  993. return tzid;
  994. }
  995. #ifndef U_TZNAME
  996. // The return value is free'd in timezone.cpp on Windows because
  997. // the other code path returns a pointer to a heap location.
  998. // If we don't have a name already, then tzname wouldn't be any
  999. // better, so just fall back.
  1000. return uprv_strdup("");
  1001. #endif // !U_TZNAME
  1002. #else
  1003. /*#if U_PLATFORM_IS_DARWIN_BASED
  1004. int ret;
  1005. tzid = getenv("TZFILE");
  1006. if (tzid != nullptr) {
  1007. return tzid;
  1008. }
  1009. #endif*/
  1010. /* This code can be temporarily disabled to test tzname resolution later on. */
  1011. #ifndef DEBUG_TZNAME
  1012. #if U_PLATFORM == U_PF_ANDROID
  1013. tzid = gAndroidTimeZone;
  1014. #else
  1015. tzid = getenv("TZ");
  1016. #endif
  1017. if (tzid != nullptr && isValidOlsonID(tzid)
  1018. #if U_PLATFORM == U_PF_SOLARIS
  1019. /* Don't misinterpret TZ "localtime" on Solaris as a time zone name. */
  1020. && uprv_strcmp(tzid, TZ_ENV_CHECK) != 0
  1021. #endif
  1022. ) {
  1023. /* The colon forces tzset() to treat the remainder as zoneinfo path */
  1024. if (tzid[0] == ':') {
  1025. tzid++;
  1026. }
  1027. /* This might be a good Olson ID. */
  1028. skipZoneIDPrefix(&tzid);
  1029. return tzid;
  1030. }
  1031. /* else U_TZNAME will give a better result. */
  1032. #endif
  1033. #if defined(CHECK_LOCALTIME_LINK) && !defined(DEBUG_SKIP_LOCALTIME_LINK)
  1034. /* Caller must handle threading issues */
  1035. if (gTimeZoneBufferPtr == nullptr) {
  1036. /*
  1037. This is a trick to look at the name of the link to get the Olson ID
  1038. because the tzfile contents is underspecified.
  1039. This isn't guaranteed to work because it may not be a symlink.
  1040. */
  1041. char *ret = realpath(TZDEFAULT, gTimeZoneBuffer);
  1042. if (ret != nullptr && uprv_strcmp(TZDEFAULT, gTimeZoneBuffer) != 0) {
  1043. int32_t tzZoneInfoTailLen = uprv_strlen(TZZONEINFOTAIL);
  1044. const char *tzZoneInfoTailPtr = uprv_strstr(gTimeZoneBuffer, TZZONEINFOTAIL);
  1045. if (tzZoneInfoTailPtr != nullptr) {
  1046. tzZoneInfoTailPtr += tzZoneInfoTailLen;
  1047. skipZoneIDPrefix(&tzZoneInfoTailPtr);
  1048. if (isValidOlsonID(tzZoneInfoTailPtr)) {
  1049. return (gTimeZoneBufferPtr = tzZoneInfoTailPtr);
  1050. }
  1051. }
  1052. } else {
  1053. #if defined(SEARCH_TZFILE)
  1054. DefaultTZInfo* tzInfo = (DefaultTZInfo*)uprv_malloc(sizeof(DefaultTZInfo));
  1055. if (tzInfo != nullptr) {
  1056. tzInfo->defaultTZBuffer = nullptr;
  1057. tzInfo->defaultTZFileSize = 0;
  1058. tzInfo->defaultTZFilePtr = nullptr;
  1059. tzInfo->defaultTZstatus = false;
  1060. tzInfo->defaultTZPosition = 0;
  1061. gTimeZoneBufferPtr = searchForTZFile(TZZONEINFO, tzInfo);
  1062. /* Free previously allocated memory */
  1063. if (tzInfo->defaultTZBuffer != nullptr) {
  1064. uprv_free(tzInfo->defaultTZBuffer);
  1065. }
  1066. if (tzInfo->defaultTZFilePtr != nullptr) {
  1067. fclose(tzInfo->defaultTZFilePtr);
  1068. }
  1069. uprv_free(tzInfo);
  1070. }
  1071. if (gTimeZoneBufferPtr != nullptr && isValidOlsonID(gTimeZoneBufferPtr)) {
  1072. return gTimeZoneBufferPtr;
  1073. }
  1074. #endif
  1075. }
  1076. }
  1077. else {
  1078. return gTimeZoneBufferPtr;
  1079. }
  1080. #endif
  1081. #endif
  1082. #ifdef U_TZNAME
  1083. #if U_PLATFORM_USES_ONLY_WIN32_API
  1084. /* The return value is free'd in timezone.cpp on Windows because
  1085. * the other code path returns a pointer to a heap location. */
  1086. return uprv_strdup(U_TZNAME[n]);
  1087. #else
  1088. /*
  1089. U_TZNAME is usually a non-unique abbreviation, which isn't normally usable.
  1090. So we remap the abbreviation to an olson ID.
  1091. Since Windows exposes a little more timezone information,
  1092. we normally don't use this code on Windows because
  1093. uprv_detectWindowsTimeZone should have already given the correct answer.
  1094. */
  1095. {
  1096. struct tm juneSol, decemberSol;
  1097. int daylightType;
  1098. static const time_t juneSolstice=1182478260; /*2007-06-21 18:11 UT*/
  1099. static const time_t decemberSolstice=1198332540; /*2007-12-22 06:09 UT*/
  1100. /* This probing will tell us when daylight savings occurs. */
  1101. localtime_r(&juneSolstice, &juneSol);
  1102. localtime_r(&decemberSolstice, &decemberSol);
  1103. if(decemberSol.tm_isdst > 0) {
  1104. daylightType = U_DAYLIGHT_DECEMBER;
  1105. } else if(juneSol.tm_isdst > 0) {
  1106. daylightType = U_DAYLIGHT_JUNE;
  1107. } else {
  1108. daylightType = U_DAYLIGHT_NONE;
  1109. }
  1110. tzid = remapShortTimeZone(U_TZNAME[0], U_TZNAME[1], daylightType, uprv_timezone());
  1111. if (tzid != nullptr) {
  1112. return tzid;
  1113. }
  1114. }
  1115. return U_TZNAME[n];
  1116. #endif
  1117. #else
  1118. return "";
  1119. #endif
  1120. }
  1121. /* Get and set the ICU data directory --------------------------------------- */
  1122. static icu::UInitOnce gDataDirInitOnce {};
  1123. static char *gDataDirectory = nullptr;
  1124. UInitOnce gTimeZoneFilesInitOnce {};
  1125. static CharString *gTimeZoneFilesDirectory = nullptr;
  1126. #if U_POSIX_LOCALE || U_PLATFORM_USES_ONLY_WIN32_API
  1127. static const char *gCorrectedPOSIXLocale = nullptr; /* Sometimes heap allocated */
  1128. static bool gCorrectedPOSIXLocaleHeapAllocated = false;
  1129. #endif
  1130. static UBool U_CALLCONV putil_cleanup()
  1131. {
  1132. if (gDataDirectory && *gDataDirectory) {
  1133. uprv_free(gDataDirectory);
  1134. }
  1135. gDataDirectory = nullptr;
  1136. gDataDirInitOnce.reset();
  1137. delete gTimeZoneFilesDirectory;
  1138. gTimeZoneFilesDirectory = nullptr;
  1139. gTimeZoneFilesInitOnce.reset();
  1140. #ifdef SEARCH_TZFILE
  1141. delete gSearchTZFileResult;
  1142. gSearchTZFileResult = nullptr;
  1143. #endif
  1144. #if U_POSIX_LOCALE || U_PLATFORM_USES_ONLY_WIN32_API
  1145. if (gCorrectedPOSIXLocale && gCorrectedPOSIXLocaleHeapAllocated) {
  1146. uprv_free(const_cast<char *>(gCorrectedPOSIXLocale));
  1147. gCorrectedPOSIXLocale = nullptr;
  1148. gCorrectedPOSIXLocaleHeapAllocated = false;
  1149. }
  1150. #endif
  1151. return true;
  1152. }
  1153. /*
  1154. * Set the data directory.
  1155. * Make a copy of the passed string, and set the global data dir to point to it.
  1156. */
  1157. U_CAPI void U_EXPORT2
  1158. u_setDataDirectory(const char *directory) {
  1159. char *newDataDir;
  1160. int32_t length;
  1161. if(directory==nullptr || *directory==0) {
  1162. /* A small optimization to prevent the malloc and copy when the
  1163. shared library is used, and this is a way to make sure that nullptr
  1164. is never returned.
  1165. */
  1166. newDataDir = (char *)"";
  1167. }
  1168. else {
  1169. length=(int32_t)uprv_strlen(directory);
  1170. newDataDir = (char *)uprv_malloc(length + 2);
  1171. /* Exit out if newDataDir could not be created. */
  1172. if (newDataDir == nullptr) {
  1173. return;
  1174. }
  1175. uprv_strcpy(newDataDir, directory);
  1176. #if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
  1177. {
  1178. char *p;
  1179. while((p = uprv_strchr(newDataDir, U_FILE_ALT_SEP_CHAR)) != nullptr) {
  1180. *p = U_FILE_SEP_CHAR;
  1181. }
  1182. }
  1183. #endif
  1184. }
  1185. if (gDataDirectory && *gDataDirectory) {
  1186. uprv_free(gDataDirectory);
  1187. }
  1188. gDataDirectory = newDataDir;
  1189. ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup);
  1190. }
  1191. U_CAPI UBool U_EXPORT2
  1192. uprv_pathIsAbsolute(const char *path)
  1193. {
  1194. if(!path || !*path) {
  1195. return false;
  1196. }
  1197. if(*path == U_FILE_SEP_CHAR) {
  1198. return true;
  1199. }
  1200. #if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
  1201. if(*path == U_FILE_ALT_SEP_CHAR) {
  1202. return true;
  1203. }
  1204. #endif
  1205. #if U_PLATFORM_USES_ONLY_WIN32_API
  1206. if( (((path[0] >= 'A') && (path[0] <= 'Z')) ||
  1207. ((path[0] >= 'a') && (path[0] <= 'z'))) &&
  1208. path[1] == ':' ) {
  1209. return true;
  1210. }
  1211. #endif
  1212. return false;
  1213. }
  1214. /* Backup setting of ICU_DATA_DIR_PREFIX_ENV_VAR
  1215. (needed for some Darwin ICU build environments) */
  1216. #if U_PLATFORM_IS_DARWIN_BASED && defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR
  1217. # if !defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
  1218. # define ICU_DATA_DIR_PREFIX_ENV_VAR "IPHONE_SIMULATOR_ROOT"
  1219. # endif
  1220. #endif
  1221. #if defined(ICU_DATA_DIR_WINDOWS)
  1222. // Helper function to get the ICU Data Directory under the Windows directory location.
  1223. static BOOL U_CALLCONV getIcuDataDirectoryUnderWindowsDirectory(char* directoryBuffer, UINT bufferLength)
  1224. {
  1225. wchar_t windowsPath[MAX_PATH];
  1226. char windowsPathUtf8[MAX_PATH];
  1227. UINT length = GetSystemWindowsDirectoryW(windowsPath, UPRV_LENGTHOF(windowsPath));
  1228. if ((length > 0) && (length < (UPRV_LENGTHOF(windowsPath) - 1))) {
  1229. // Convert UTF-16 to a UTF-8 string.
  1230. UErrorCode status = U_ZERO_ERROR;
  1231. int32_t windowsPathUtf8Len = 0;
  1232. u_strToUTF8(windowsPathUtf8, static_cast<int32_t>(UPRV_LENGTHOF(windowsPathUtf8)),
  1233. &windowsPathUtf8Len, reinterpret_cast<const char16_t*>(windowsPath), -1, &status);
  1234. if (U_SUCCESS(status) && (status != U_STRING_NOT_TERMINATED_WARNING) &&
  1235. (windowsPathUtf8Len < (UPRV_LENGTHOF(windowsPathUtf8) - 1))) {
  1236. // Ensure it always has a separator, so we can append the ICU data path.
  1237. if (windowsPathUtf8[windowsPathUtf8Len - 1] != U_FILE_SEP_CHAR) {
  1238. windowsPathUtf8[windowsPathUtf8Len++] = U_FILE_SEP_CHAR;
  1239. windowsPathUtf8[windowsPathUtf8Len] = '\0';
  1240. }
  1241. // Check if the concatenated string will fit.
  1242. if ((windowsPathUtf8Len + UPRV_LENGTHOF(ICU_DATA_DIR_WINDOWS)) < bufferLength) {
  1243. uprv_strcpy(directoryBuffer, windowsPathUtf8);
  1244. uprv_strcat(directoryBuffer, ICU_DATA_DIR_WINDOWS);
  1245. return true;
  1246. }
  1247. }
  1248. }
  1249. return false;
  1250. }
  1251. #endif
  1252. static void U_CALLCONV dataDirectoryInitFn() {
  1253. /* If we already have the directory, then return immediately. Will happen if user called
  1254. * u_setDataDirectory().
  1255. */
  1256. if (gDataDirectory) {
  1257. return;
  1258. }
  1259. const char *path = nullptr;
  1260. #if defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
  1261. char datadir_path_buffer[PATH_MAX];
  1262. #endif
  1263. /*
  1264. When ICU_NO_USER_DATA_OVERRIDE is defined, users aren't allowed to
  1265. override ICU's data with the ICU_DATA environment variable. This prevents
  1266. problems where multiple custom copies of ICU's specific version of data
  1267. are installed on a system. Either the application must define the data
  1268. directory with u_setDataDirectory, define ICU_DATA_DIR when compiling
  1269. ICU, set the data with udata_setCommonData or trust that all of the
  1270. required data is contained in ICU's data library that contains
  1271. the entry point defined by U_ICUDATA_ENTRY_POINT.
  1272. There may also be some platforms where environment variables
  1273. are not allowed.
  1274. */
  1275. # if !defined(ICU_NO_USER_DATA_OVERRIDE) && !UCONFIG_NO_FILE_IO
  1276. /* First try to get the environment variable */
  1277. # if U_PLATFORM_HAS_WINUWP_API == 0 // Windows UWP does not support getenv
  1278. path=getenv("ICU_DATA");
  1279. # endif
  1280. # endif
  1281. /* ICU_DATA_DIR may be set as a compile option.
  1282. * U_ICU_DATA_DEFAULT_DIR is provided and is set by ICU at compile time
  1283. * and is used only when data is built in archive mode eliminating the need
  1284. * for ICU_DATA_DIR to be set. U_ICU_DATA_DEFAULT_DIR is set to the installation
  1285. * directory of the data dat file. Users should use ICU_DATA_DIR if they want to
  1286. * set their own path.
  1287. */
  1288. #if defined(ICU_DATA_DIR) || defined(U_ICU_DATA_DEFAULT_DIR)
  1289. if(path==nullptr || *path==0) {
  1290. # if defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
  1291. const char *prefix = getenv(ICU_DATA_DIR_PREFIX_ENV_VAR);
  1292. # endif
  1293. # ifdef ICU_DATA_DIR
  1294. path=ICU_DATA_DIR;
  1295. # else
  1296. path=U_ICU_DATA_DEFAULT_DIR;
  1297. # endif
  1298. # if defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
  1299. if (prefix != nullptr) {
  1300. snprintf(datadir_path_buffer, sizeof(datadir_path_buffer), "%s%s", prefix, path);
  1301. path=datadir_path_buffer;
  1302. }
  1303. # endif
  1304. }
  1305. #endif
  1306. #if defined(ICU_DATA_DIR_WINDOWS)
  1307. char datadir_path_buffer[MAX_PATH];
  1308. if (getIcuDataDirectoryUnderWindowsDirectory(datadir_path_buffer, UPRV_LENGTHOF(datadir_path_buffer))) {
  1309. path = datadir_path_buffer;
  1310. }
  1311. #endif
  1312. if(path==nullptr) {
  1313. /* It looks really bad, set it to something. */
  1314. path = "";
  1315. }
  1316. u_setDataDirectory(path);
  1317. return;
  1318. }
  1319. U_CAPI const char * U_EXPORT2
  1320. u_getDataDirectory() {
  1321. umtx_initOnce(gDataDirInitOnce, &dataDirectoryInitFn);
  1322. return gDataDirectory;
  1323. }
  1324. static void setTimeZoneFilesDir(const char *path, UErrorCode &status) {
  1325. if (U_FAILURE(status)) {
  1326. return;
  1327. }
  1328. gTimeZoneFilesDirectory->clear();
  1329. gTimeZoneFilesDirectory->append(path, status);
  1330. #if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
  1331. char *p = gTimeZoneFilesDirectory->data();
  1332. while ((p = uprv_strchr(p, U_FILE_ALT_SEP_CHAR)) != nullptr) {
  1333. *p = U_FILE_SEP_CHAR;
  1334. }
  1335. #endif
  1336. }
  1337. #define TO_STRING(x) TO_STRING_2(x)
  1338. #define TO_STRING_2(x) #x
  1339. static void U_CALLCONV TimeZoneDataDirInitFn(UErrorCode &status) {
  1340. U_ASSERT(gTimeZoneFilesDirectory == nullptr);
  1341. ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup);
  1342. gTimeZoneFilesDirectory = new CharString();
  1343. if (gTimeZoneFilesDirectory == nullptr) {
  1344. status = U_MEMORY_ALLOCATION_ERROR;
  1345. return;
  1346. }
  1347. const char *dir = "";
  1348. #if defined(ICU_TIMEZONE_FILES_DIR_PREFIX_ENV_VAR)
  1349. char timezonefilesdir_path_buffer[PATH_MAX];
  1350. const char *prefix = getenv(ICU_TIMEZONE_FILES_DIR_PREFIX_ENV_VAR);
  1351. #endif
  1352. #if U_PLATFORM_HAS_WINUWP_API == 1
  1353. // The UWP version does not support the environment variable setting.
  1354. # if defined(ICU_DATA_DIR_WINDOWS)
  1355. // When using the Windows system data, we can possibly pick up time zone data from the Windows directory.
  1356. char datadir_path_buffer[MAX_PATH];
  1357. if (getIcuDataDirectoryUnderWindowsDirectory(datadir_path_buffer, UPRV_LENGTHOF(datadir_path_buffer))) {
  1358. dir = datadir_path_buffer;
  1359. }
  1360. # endif
  1361. #else
  1362. dir = getenv("ICU_TIMEZONE_FILES_DIR");
  1363. #endif // U_PLATFORM_HAS_WINUWP_API
  1364. #if defined(U_TIMEZONE_FILES_DIR)
  1365. if (dir == nullptr) {
  1366. // Build time configuration setting.
  1367. dir = TO_STRING(U_TIMEZONE_FILES_DIR);
  1368. }
  1369. #endif
  1370. if (dir == nullptr) {
  1371. dir = "";
  1372. }
  1373. #if defined(ICU_TIMEZONE_FILES_DIR_PREFIX_ENV_VAR)
  1374. if (prefix != nullptr) {
  1375. snprintf(timezonefilesdir_path_buffer, sizeof(timezonefilesdir_path_buffer), "%s%s", prefix, dir);
  1376. dir = timezonefilesdir_path_buffer;
  1377. }
  1378. #endif
  1379. setTimeZoneFilesDir(dir, status);
  1380. }
  1381. U_CAPI const char * U_EXPORT2
  1382. u_getTimeZoneFilesDirectory(UErrorCode *status) {
  1383. umtx_initOnce(gTimeZoneFilesInitOnce, &TimeZoneDataDirInitFn, *status);
  1384. return U_SUCCESS(*status) ? gTimeZoneFilesDirectory->data() : "";
  1385. }
  1386. U_CAPI void U_EXPORT2
  1387. u_setTimeZoneFilesDirectory(const char *path, UErrorCode *status) {
  1388. umtx_initOnce(gTimeZoneFilesInitOnce, &TimeZoneDataDirInitFn, *status);
  1389. setTimeZoneFilesDir(path, *status);
  1390. // Note: this function does some extra churn, first setting based on the
  1391. // environment, then immediately replacing with the value passed in.
  1392. // The logic is simpler that way, and performance shouldn't be an issue.
  1393. }
  1394. #if U_POSIX_LOCALE
  1395. /* A helper function used by uprv_getPOSIXIDForDefaultLocale and
  1396. * uprv_getPOSIXIDForDefaultCodepage. Returns the posix locale id for
  1397. * LC_CTYPE and LC_MESSAGES. It doesn't support other locale categories.
  1398. */
  1399. static const char *uprv_getPOSIXIDForCategory(int category)
  1400. {
  1401. const char* posixID = nullptr;
  1402. if (category == LC_MESSAGES || category == LC_CTYPE) {
  1403. /*
  1404. * On Solaris two different calls to setlocale can result in
  1405. * different values. Only get this value once.
  1406. *
  1407. * We must check this first because an application can set this.
  1408. *
  1409. * LC_ALL can't be used because it's platform dependent. The LANG
  1410. * environment variable seems to affect LC_CTYPE variable by default.
  1411. * Here is what setlocale(LC_ALL, nullptr) can return.
  1412. * HPUX can return 'C C C C C C C'
  1413. * Solaris can return /en_US/C/C/C/C/C on the second try.
  1414. * Linux can return LC_CTYPE=C;LC_NUMERIC=C;...
  1415. *
  1416. * The default codepage detection also needs to use LC_CTYPE.
  1417. *
  1418. * Do not call setlocale(LC_*, "")! Using an empty string instead
  1419. * of nullptr, will modify the libc behavior.
  1420. */
  1421. posixID = setlocale(category, nullptr);
  1422. if ((posixID == 0)
  1423. || (uprv_strcmp("C", posixID) == 0)
  1424. || (uprv_strcmp("POSIX", posixID) == 0))
  1425. {
  1426. /* Maybe we got some garbage. Try something more reasonable */
  1427. posixID = getenv("LC_ALL");
  1428. /* Solaris speaks POSIX - See IEEE Std 1003.1-2008
  1429. * This is needed to properly handle empty env. variables
  1430. */
  1431. #if U_PLATFORM == U_PF_SOLARIS
  1432. if ((posixID == 0) || (posixID[0] == '\0')) {
  1433. posixID = getenv(category == LC_MESSAGES ? "LC_MESSAGES" : "LC_CTYPE");
  1434. if ((posixID == 0) || (posixID[0] == '\0')) {
  1435. #else
  1436. if (posixID == 0) {
  1437. posixID = getenv(category == LC_MESSAGES ? "LC_MESSAGES" : "LC_CTYPE");
  1438. if (posixID == 0) {
  1439. #endif
  1440. posixID = getenv("LANG");
  1441. }
  1442. }
  1443. }
  1444. }
  1445. if ((posixID==0)
  1446. || (uprv_strcmp("C", posixID) == 0)
  1447. || (uprv_strcmp("POSIX", posixID) == 0))
  1448. {
  1449. /* Nothing worked. Give it a nice POSIX default value. */
  1450. posixID = "en_US_POSIX";
  1451. // Note: this test will not catch 'C.UTF-8',
  1452. // that will be handled in uprv_getDefaultLocaleID().
  1453. // Leave this mapping here for the uprv_getPOSIXIDForDefaultCodepage()
  1454. // caller which expects to see "en_US_POSIX" in many branches.
  1455. }
  1456. return posixID;
  1457. }
  1458. /* Return just the POSIX id for the default locale, whatever happens to be in
  1459. * it. It gets the value from LC_MESSAGES and indirectly from LC_ALL and LANG.
  1460. */
  1461. static const char *uprv_getPOSIXIDForDefaultLocale()
  1462. {
  1463. static const char* posixID = nullptr;
  1464. if (posixID == 0) {
  1465. posixID = uprv_getPOSIXIDForCategory(LC_MESSAGES);
  1466. }
  1467. return posixID;
  1468. }
  1469. #if !U_CHARSET_IS_UTF8
  1470. /* Return just the POSIX id for the default codepage, whatever happens to be in
  1471. * it. It gets the value from LC_CTYPE and indirectly from LC_ALL and LANG.
  1472. */
  1473. static const char *uprv_getPOSIXIDForDefaultCodepage()
  1474. {
  1475. static const char* posixID = nullptr;
  1476. if (posixID == 0) {
  1477. posixID = uprv_getPOSIXIDForCategory(LC_CTYPE);
  1478. }
  1479. return posixID;
  1480. }
  1481. #endif
  1482. #endif
  1483. /* NOTE: The caller should handle thread safety */
  1484. U_CAPI const char* U_EXPORT2
  1485. uprv_getDefaultLocaleID()
  1486. {
  1487. #if U_POSIX_LOCALE
  1488. /*
  1489. Note that: (a '!' means the ID is improper somehow)
  1490. LC_ALL ----> default_loc codepage
  1491. --------------------------------------------------------
  1492. ab.CD ab CD
  1493. ab@CD ab__CD -
  1494. ab@CD.EF ab__CD EF
  1495. ab_CD.EF@GH ab_CD_GH EF
  1496. Some 'improper' ways to do the same as above:
  1497. ! ab_CD@GH.EF ab_CD_GH EF
  1498. ! ab_CD.EF@GH.IJ ab_CD_GH EF
  1499. ! ab_CD@ZZ.EF@GH.IJ ab_CD_GH EF
  1500. _CD@GH _CD_GH -
  1501. _CD.EF@GH _CD_GH EF
  1502. The variant cannot have dots in it.
  1503. The 'rightmost' variant (@xxx) wins.
  1504. The leftmost codepage (.xxx) wins.
  1505. */
  1506. const char* posixID = uprv_getPOSIXIDForDefaultLocale();
  1507. /* Format: (no spaces)
  1508. ll [ _CC ] [ . MM ] [ @ VV]
  1509. l = lang, C = ctry, M = charmap, V = variant
  1510. */
  1511. if (gCorrectedPOSIXLocale != nullptr) {
  1512. return gCorrectedPOSIXLocale;
  1513. }
  1514. // Copy the ID into owned memory.
  1515. // Over-allocate in case we replace "C" with "en_US_POSIX" (+10), + null termination
  1516. char *correctedPOSIXLocale = static_cast<char *>(uprv_malloc(uprv_strlen(posixID) + 10 + 1));
  1517. if (correctedPOSIXLocale == nullptr) {
  1518. return nullptr;
  1519. }
  1520. uprv_strcpy(correctedPOSIXLocale, posixID);
  1521. char *limit;
  1522. if ((limit = uprv_strchr(correctedPOSIXLocale, '.')) != nullptr) {
  1523. *limit = 0;
  1524. }
  1525. if ((limit = uprv_strchr(correctedPOSIXLocale, '@')) != nullptr) {
  1526. *limit = 0;
  1527. }
  1528. if ((uprv_strcmp("C", correctedPOSIXLocale) == 0) // no @ variant
  1529. || (uprv_strcmp("POSIX", correctedPOSIXLocale) == 0)) {
  1530. // Raw input was C.* or POSIX.*, Give it a nice POSIX default value.
  1531. // (The "C"/"POSIX" case is handled in uprv_getPOSIXIDForCategory())
  1532. uprv_strcpy(correctedPOSIXLocale, "en_US_POSIX");
  1533. }
  1534. /* Note that we scan the *uncorrected* ID. */
  1535. const char *p;
  1536. if ((p = uprv_strrchr(posixID, '@')) != nullptr) {
  1537. p++;
  1538. /* Take care of any special cases here.. */
  1539. if (!uprv_strcmp(p, "nynorsk")) {
  1540. p = "NY";
  1541. /* Don't worry about no__NY. In practice, it won't appear. */
  1542. }
  1543. if (uprv_strchr(correctedPOSIXLocale,'_') == nullptr) {
  1544. uprv_strcat(correctedPOSIXLocale, "__"); /* aa@b -> aa__b (note this can make the new locale 1 char longer) */
  1545. }
  1546. else {
  1547. uprv_strcat(correctedPOSIXLocale, "_"); /* aa_CC@b -> aa_CC_b */
  1548. }
  1549. const char *q;
  1550. if ((q = uprv_strchr(p, '.')) != nullptr) {
  1551. /* How big will the resulting string be? */
  1552. int32_t len = (int32_t)(uprv_strlen(correctedPOSIXLocale) + (q-p));
  1553. uprv_strncat(correctedPOSIXLocale, p, q-p); // do not include charset
  1554. correctedPOSIXLocale[len] = 0;
  1555. }
  1556. else {
  1557. /* Anything following the @ sign */
  1558. uprv_strcat(correctedPOSIXLocale, p);
  1559. }
  1560. /* Should there be a map from 'no@nynorsk' -> no_NO_NY here?
  1561. * How about 'russian' -> 'ru'?
  1562. * Many of the other locales using ISO codes will be handled by the
  1563. * canonicalization functions in uloc_getDefault.
  1564. */
  1565. }
  1566. if (gCorrectedPOSIXLocale == nullptr) {
  1567. gCorrectedPOSIXLocale = correctedPOSIXLocale;
  1568. gCorrectedPOSIXLocaleHeapAllocated = true;
  1569. ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup);
  1570. correctedPOSIXLocale = nullptr;
  1571. }
  1572. posixID = gCorrectedPOSIXLocale;
  1573. if (correctedPOSIXLocale != nullptr) { /* Was already set - clean up. */
  1574. uprv_free(correctedPOSIXLocale);
  1575. }
  1576. return posixID;
  1577. #elif U_PLATFORM_USES_ONLY_WIN32_API
  1578. #define POSIX_LOCALE_CAPACITY 64
  1579. UErrorCode status = U_ZERO_ERROR;
  1580. char *correctedPOSIXLocale = nullptr;
  1581. // If we have already figured this out just use the cached value
  1582. if (gCorrectedPOSIXLocale != nullptr) {
  1583. return gCorrectedPOSIXLocale;
  1584. }
  1585. // No cached value, need to determine the current value
  1586. static WCHAR windowsLocale[LOCALE_NAME_MAX_LENGTH] = {};
  1587. int length = GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, windowsLocale, LOCALE_NAME_MAX_LENGTH);
  1588. // Now we should have a Windows locale name that needs converted to the POSIX style.
  1589. if (length > 0) // If length is 0, then the GetLocaleInfoEx failed.
  1590. {
  1591. // First we need to go from UTF-16 to char (and also convert from _ to - while we're at it.)
  1592. char modifiedWindowsLocale[LOCALE_NAME_MAX_LENGTH] = {};
  1593. int32_t i;
  1594. for (i = 0; i < UPRV_LENGTHOF(modifiedWindowsLocale); i++)
  1595. {
  1596. if (windowsLocale[i] == '_')
  1597. {
  1598. modifiedWindowsLocale[i] = '-';
  1599. }
  1600. else
  1601. {
  1602. modifiedWindowsLocale[i] = static_cast<char>(windowsLocale[i]);
  1603. }
  1604. if (modifiedWindowsLocale[i] == '\0')
  1605. {
  1606. break;
  1607. }
  1608. }
  1609. if (i >= UPRV_LENGTHOF(modifiedWindowsLocale))
  1610. {
  1611. // Ran out of room, can't really happen, maybe we'll be lucky about a matching
  1612. // locale when tags are dropped
  1613. modifiedWindowsLocale[UPRV_LENGTHOF(modifiedWindowsLocale) - 1] = '\0';
  1614. }
  1615. // Now normalize the resulting name
  1616. correctedPOSIXLocale = static_cast<char *>(uprv_malloc(POSIX_LOCALE_CAPACITY + 1));
  1617. /* TODO: Should we just exit on memory allocation failure? */
  1618. if (correctedPOSIXLocale)
  1619. {
  1620. int32_t posixLen = uloc_canonicalize(modifiedWindowsLocale, correctedPOSIXLocale, POSIX_LOCALE_CAPACITY, &status);
  1621. if (U_SUCCESS(status))
  1622. {
  1623. *(correctedPOSIXLocale + posixLen) = 0;
  1624. gCorrectedPOSIXLocale = correctedPOSIXLocale;
  1625. gCorrectedPOSIXLocaleHeapAllocated = true;
  1626. ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup);
  1627. }
  1628. else
  1629. {
  1630. uprv_free(correctedPOSIXLocale);
  1631. }
  1632. }
  1633. }
  1634. // If unable to find a locale we can agree upon, use en-US by default
  1635. if (gCorrectedPOSIXLocale == nullptr) {
  1636. gCorrectedPOSIXLocale = "en_US";
  1637. }
  1638. return gCorrectedPOSIXLocale;
  1639. #elif U_PLATFORM == U_PF_OS400
  1640. /* locales are process scoped and are by definition thread safe */
  1641. static char correctedLocale[64];
  1642. const char *localeID = getenv("LC_ALL");
  1643. char *p;
  1644. if (localeID == nullptr)
  1645. localeID = getenv("LANG");
  1646. if (localeID == nullptr)
  1647. localeID = setlocale(LC_ALL, nullptr);
  1648. /* Make sure we have something... */
  1649. if (localeID == nullptr)
  1650. return "en_US_POSIX";
  1651. /* Extract the locale name from the path. */
  1652. if((p = uprv_strrchr(localeID, '/')) != nullptr)
  1653. {
  1654. /* Increment p to start of locale name. */
  1655. p++;
  1656. localeID = p;
  1657. }
  1658. /* Copy to work location. */
  1659. uprv_strcpy(correctedLocale, localeID);
  1660. /* Strip off the '.locale' extension. */
  1661. if((p = uprv_strchr(correctedLocale, '.')) != nullptr) {
  1662. *p = 0;
  1663. }
  1664. /* Upper case the locale name. */
  1665. T_CString_toUpperCase(correctedLocale);
  1666. /* See if we are using the POSIX locale. Any of the
  1667. * following are equivalent and use the same QLGPGCMA
  1668. * (POSIX) locale.
  1669. * QLGPGCMA2 means UCS2
  1670. * QLGPGCMA_4 means UTF-32
  1671. * QLGPGCMA_8 means UTF-8
  1672. */
  1673. if ((uprv_strcmp("C", correctedLocale) == 0) ||
  1674. (uprv_strcmp("POSIX", correctedLocale) == 0) ||
  1675. (uprv_strncmp("QLGPGCMA", correctedLocale, 8) == 0))
  1676. {
  1677. uprv_strcpy(correctedLocale, "en_US_POSIX");
  1678. }
  1679. else
  1680. {
  1681. int16_t LocaleLen;
  1682. /* Lower case the lang portion. */
  1683. for(p = correctedLocale; *p != 0 && *p != '_'; p++)
  1684. {
  1685. *p = uprv_tolower(*p);
  1686. }
  1687. /* Adjust for Euro. After '_E' add 'URO'. */
  1688. LocaleLen = uprv_strlen(correctedLocale);
  1689. if (correctedLocale[LocaleLen - 2] == '_' &&
  1690. correctedLocale[LocaleLen - 1] == 'E')
  1691. {
  1692. uprv_strcat(correctedLocale, "URO");
  1693. }
  1694. /* If using Lotus-based locale then convert to
  1695. * equivalent non Lotus.
  1696. */
  1697. else if (correctedLocale[LocaleLen - 2] == '_' &&
  1698. correctedLocale[LocaleLen - 1] == 'L')
  1699. {
  1700. correctedLocale[LocaleLen - 2] = 0;
  1701. }
  1702. /* There are separate simplified and traditional
  1703. * locales called zh_HK_S and zh_HK_T.
  1704. */
  1705. else if (uprv_strncmp(correctedLocale, "zh_HK", 5) == 0)
  1706. {
  1707. uprv_strcpy(correctedLocale, "zh_HK");
  1708. }
  1709. /* A special zh_CN_GBK locale...
  1710. */
  1711. else if (uprv_strcmp(correctedLocale, "zh_CN_GBK") == 0)
  1712. {
  1713. uprv_strcpy(correctedLocale, "zh_CN");
  1714. }
  1715. }
  1716. return correctedLocale;
  1717. #endif
  1718. }
  1719. #if !U_CHARSET_IS_UTF8
  1720. #if U_POSIX_LOCALE
  1721. /*
  1722. Due to various platform differences, one platform may specify a charset,
  1723. when they really mean a different charset. Remap the names so that they are
  1724. compatible with ICU. Only conflicting/ambiguous aliases should be resolved
  1725. here. Before adding anything to this function, please consider adding unique
  1726. names to the ICU alias table in the data directory.
  1727. */
  1728. static const char*
  1729. remapPlatformDependentCodepage(const char *locale, const char *name) {
  1730. if (locale != nullptr && *locale == 0) {
  1731. /* Make sure that an empty locale is handled the same way. */
  1732. locale = nullptr;
  1733. }
  1734. if (name == nullptr) {
  1735. return nullptr;
  1736. }
  1737. #if U_PLATFORM == U_PF_AIX
  1738. if (uprv_strcmp(name, "IBM-943") == 0) {
  1739. /* Use the ASCII compatible ibm-943 */
  1740. name = "Shift-JIS";
  1741. }
  1742. else if (uprv_strcmp(name, "IBM-1252") == 0) {
  1743. /* Use the windows-1252 that contains the Euro */
  1744. name = "IBM-5348";
  1745. }
  1746. #elif U_PLATFORM == U_PF_SOLARIS
  1747. if (locale != nullptr && uprv_strcmp(name, "EUC") == 0) {
  1748. /* Solaris underspecifies the "EUC" name. */
  1749. if (uprv_strcmp(locale, "zh_CN") == 0) {
  1750. name = "EUC-CN";
  1751. }
  1752. else if (uprv_strcmp(locale, "zh_TW") == 0) {
  1753. name = "EUC-TW";
  1754. }
  1755. else if (uprv_strcmp(locale, "ko_KR") == 0) {
  1756. name = "EUC-KR";
  1757. }
  1758. }
  1759. else if (uprv_strcmp(name, "eucJP") == 0) {
  1760. /*
  1761. ibm-954 is the best match.
  1762. ibm-33722 is the default for eucJP (similar to Windows).
  1763. */
  1764. name = "eucjis";
  1765. }
  1766. else if (uprv_strcmp(name, "646") == 0) {
  1767. /*
  1768. * The default codepage given by Solaris is 646 but the C library routines treat it as if it was
  1769. * ISO-8859-1 instead of US-ASCII(646).
  1770. */
  1771. name = "ISO-8859-1";
  1772. }
  1773. #elif U_PLATFORM_IS_DARWIN_BASED
  1774. if (locale == nullptr && *name == 0) {
  1775. /*
  1776. No locale was specified, and an empty name was passed in.
  1777. This usually indicates that nl_langinfo didn't return valid information.
  1778. Mac OS X uses UTF-8 by default (especially the locale data and console).
  1779. */
  1780. name = "UTF-8";
  1781. }
  1782. else if (uprv_strcmp(name, "CP949") == 0) {
  1783. /* Remap CP949 to a similar codepage to avoid issues with backslash and won symbol. */
  1784. name = "EUC-KR";
  1785. }
  1786. else if (locale != nullptr && uprv_strcmp(locale, "en_US_POSIX") != 0 && uprv_strcmp(name, "US-ASCII") == 0) {
  1787. /*
  1788. * For non C/POSIX locale, default the code page to UTF-8 instead of US-ASCII.
  1789. */
  1790. name = "UTF-8";
  1791. }
  1792. #elif U_PLATFORM == U_PF_BSD
  1793. if (uprv_strcmp(name, "CP949") == 0) {
  1794. /* Remap CP949 to a similar codepage to avoid issues with backslash and won symbol. */
  1795. name = "EUC-KR";
  1796. }
  1797. #elif U_PLATFORM == U_PF_HPUX
  1798. if (locale != nullptr && uprv_strcmp(locale, "zh_HK") == 0 && uprv_strcmp(name, "big5") == 0) {
  1799. /* HP decided to extend big5 as hkbig5 even though it's not compatible :-( */
  1800. /* zh_TW.big5 is not the same charset as zh_HK.big5! */
  1801. name = "hkbig5";
  1802. }
  1803. else if (uprv_strcmp(name, "eucJP") == 0) {
  1804. /*
  1805. ibm-1350 is the best match, but unavailable.
  1806. ibm-954 is mostly a superset of ibm-1350.
  1807. ibm-33722 is the default for eucJP (similar to Windows).
  1808. */
  1809. name = "eucjis";
  1810. }
  1811. #elif U_PLATFORM == U_PF_LINUX
  1812. if (locale != nullptr && uprv_strcmp(name, "euc") == 0) {
  1813. /* Linux underspecifies the "EUC" name. */
  1814. if (uprv_strcmp(locale, "korean") == 0) {
  1815. name = "EUC-KR";
  1816. }
  1817. else if (uprv_strcmp(locale, "japanese") == 0) {
  1818. /* See comment below about eucJP */
  1819. name = "eucjis";
  1820. }
  1821. }
  1822. else if (uprv_strcmp(name, "eucjp") == 0) {
  1823. /*
  1824. ibm-1350 is the best match, but unavailable.
  1825. ibm-954 is mostly a superset of ibm-1350.
  1826. ibm-33722 is the default for eucJP (similar to Windows).
  1827. */
  1828. name = "eucjis";
  1829. }
  1830. else if (locale != nullptr && uprv_strcmp(locale, "en_US_POSIX") != 0 &&
  1831. (uprv_strcmp(name, "ANSI_X3.4-1968") == 0 || uprv_strcmp(name, "US-ASCII") == 0)) {
  1832. /*
  1833. * For non C/POSIX locale, default the code page to UTF-8 instead of US-ASCII.
  1834. */
  1835. name = "UTF-8";
  1836. }
  1837. /*
  1838. * Linux returns ANSI_X3.4-1968 for C/POSIX, but the call site takes care of
  1839. * it by falling back to 'US-ASCII' when nullptr is returned from this
  1840. * function. So, we don't have to worry about it here.
  1841. */
  1842. #endif
  1843. /* return nullptr when "" is passed in */
  1844. if (*name == 0) {
  1845. name = nullptr;
  1846. }
  1847. return name;
  1848. }
  1849. static const char*
  1850. getCodepageFromPOSIXID(const char *localeName, char * buffer, int32_t buffCapacity)
  1851. {
  1852. char localeBuf[100];
  1853. const char *name = nullptr;
  1854. char *variant = nullptr;
  1855. if (localeName != nullptr && (name = (uprv_strchr(localeName, '.'))) != nullptr) {
  1856. size_t localeCapacity = uprv_min(sizeof(localeBuf), (name-localeName)+1);
  1857. uprv_strncpy(localeBuf, localeName, localeCapacity);
  1858. localeBuf[localeCapacity-1] = 0; /* ensure NUL termination */
  1859. name = uprv_strncpy(buffer, name+1, buffCapacity);
  1860. buffer[buffCapacity-1] = 0; /* ensure NUL termination */
  1861. if ((variant = const_cast<char *>(uprv_strchr(name, '@'))) != nullptr) {
  1862. *variant = 0;
  1863. }
  1864. name = remapPlatformDependentCodepage(localeBuf, name);
  1865. }
  1866. return name;
  1867. }
  1868. #endif
  1869. static const char*
  1870. int_getDefaultCodepage()
  1871. {
  1872. #if U_PLATFORM == U_PF_OS400
  1873. uint32_t ccsid = 37; /* Default to ibm-37 */
  1874. static char codepage[64];
  1875. Qwc_JOBI0400_t jobinfo;
  1876. Qus_EC_t error = { sizeof(Qus_EC_t) }; /* SPI error code */
  1877. EPT_CALL(QUSRJOBI)(&jobinfo, sizeof(jobinfo), "JOBI0400",
  1878. "* ", " ", &error);
  1879. if (error.Bytes_Available == 0) {
  1880. if (jobinfo.Coded_Char_Set_ID != 0xFFFF) {
  1881. ccsid = (uint32_t)jobinfo.Coded_Char_Set_ID;
  1882. }
  1883. else if (jobinfo.Default_Coded_Char_Set_Id != 0xFFFF) {
  1884. ccsid = (uint32_t)jobinfo.Default_Coded_Char_Set_Id;
  1885. }
  1886. /* else use the default */
  1887. }
  1888. snprintf(codepage, sizeof(codepage), "ibm-%d", ccsid);
  1889. return codepage;
  1890. #elif U_PLATFORM == U_PF_OS390
  1891. static char codepage[64];
  1892. strncpy(codepage, nl_langinfo(CODESET),63-strlen(UCNV_SWAP_LFNL_OPTION_STRING));
  1893. strcat(codepage,UCNV_SWAP_LFNL_OPTION_STRING);
  1894. codepage[63] = 0; /* NUL terminate */
  1895. return codepage;
  1896. #elif U_PLATFORM_USES_ONLY_WIN32_API
  1897. static char codepage[64];
  1898. DWORD codepageNumber = 0;
  1899. #if U_PLATFORM_HAS_WINUWP_API == 1
  1900. // UWP doesn't have a direct API to get the default ACP as Microsoft would rather
  1901. // have folks use Unicode than a "system" code page, however this is the same
  1902. // codepage as the system default locale codepage. (FWIW, the system locale is
  1903. // ONLY used for codepage, it should never be used for anything else)
  1904. GetLocaleInfoEx(LOCALE_NAME_SYSTEM_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
  1905. (LPWSTR)&codepageNumber, sizeof(codepageNumber) / sizeof(WCHAR));
  1906. #else
  1907. // Win32 apps can call GetACP
  1908. codepageNumber = GetACP();
  1909. #endif
  1910. // Special case for UTF-8
  1911. if (codepageNumber == 65001)
  1912. {
  1913. return "UTF-8";
  1914. }
  1915. // Windows codepages can look like windows-1252, so format the found number
  1916. // the numbers are eclectic, however all valid system code pages, besides UTF-8
  1917. // are between 3 and 19999
  1918. if (codepageNumber > 0 && codepageNumber < 20000)
  1919. {
  1920. snprintf(codepage, sizeof(codepage), "windows-%ld", codepageNumber);
  1921. return codepage;
  1922. }
  1923. // If the codepage number call failed then return UTF-8
  1924. return "UTF-8";
  1925. #elif U_POSIX_LOCALE
  1926. static char codesetName[100];
  1927. const char *localeName = nullptr;
  1928. const char *name = nullptr;
  1929. localeName = uprv_getPOSIXIDForDefaultCodepage();
  1930. uprv_memset(codesetName, 0, sizeof(codesetName));
  1931. /* On Solaris nl_langinfo returns C locale values unless setlocale
  1932. * was called earlier.
  1933. */
  1934. #if (U_HAVE_NL_LANGINFO_CODESET && U_PLATFORM != U_PF_SOLARIS)
  1935. /* When available, check nl_langinfo first because it usually gives more
  1936. useful names. It depends on LC_CTYPE.
  1937. nl_langinfo may use the same buffer as setlocale. */
  1938. {
  1939. const char *codeset = nl_langinfo(U_NL_LANGINFO_CODESET);
  1940. #if U_PLATFORM_IS_DARWIN_BASED || U_PLATFORM_IS_LINUX_BASED
  1941. /*
  1942. * On Linux and MacOSX, ensure that default codepage for non C/POSIX locale is UTF-8
  1943. * instead of ASCII.
  1944. */
  1945. if (uprv_strcmp(localeName, "en_US_POSIX") != 0) {
  1946. codeset = remapPlatformDependentCodepage(localeName, codeset);
  1947. } else
  1948. #endif
  1949. {
  1950. codeset = remapPlatformDependentCodepage(nullptr, codeset);
  1951. }
  1952. if (codeset != nullptr) {
  1953. uprv_strncpy(codesetName, codeset, sizeof(codesetName));
  1954. codesetName[sizeof(codesetName)-1] = 0;
  1955. return codesetName;
  1956. }
  1957. }
  1958. #endif
  1959. /* Use setlocale in a nice way, and then check some environment variables.
  1960. Maybe the application used setlocale already.
  1961. */
  1962. uprv_memset(codesetName, 0, sizeof(codesetName));
  1963. name = getCodepageFromPOSIXID(localeName, codesetName, sizeof(codesetName));
  1964. if (name) {
  1965. /* if we can find the codeset name from setlocale, return that. */
  1966. return name;
  1967. }
  1968. if (*codesetName == 0)
  1969. {
  1970. /* Everything failed. Return US ASCII (ISO 646). */
  1971. (void)uprv_strcpy(codesetName, "US-ASCII");
  1972. }
  1973. return codesetName;
  1974. #else
  1975. return "US-ASCII";
  1976. #endif
  1977. }
  1978. U_CAPI const char* U_EXPORT2
  1979. uprv_getDefaultCodepage()
  1980. {
  1981. static char const *name = nullptr;
  1982. umtx_lock(nullptr);
  1983. if (name == nullptr) {
  1984. name = int_getDefaultCodepage();
  1985. }
  1986. umtx_unlock(nullptr);
  1987. return name;
  1988. }
  1989. #endif /* !U_CHARSET_IS_UTF8 */
  1990. /* end of platform-specific implementation -------------- */
  1991. /* version handling --------------------------------------------------------- */
  1992. U_CAPI void U_EXPORT2
  1993. u_versionFromString(UVersionInfo versionArray, const char *versionString) {
  1994. char *end;
  1995. uint16_t part=0;
  1996. if(versionArray==nullptr) {
  1997. return;
  1998. }
  1999. if(versionString!=nullptr) {
  2000. for(;;) {
  2001. versionArray[part]=(uint8_t)uprv_strtoul(versionString, &end, 10);
  2002. if(end==versionString || ++part==U_MAX_VERSION_LENGTH || *end!=U_VERSION_DELIMITER) {
  2003. break;
  2004. }
  2005. versionString=end+1;
  2006. }
  2007. }
  2008. while(part<U_MAX_VERSION_LENGTH) {
  2009. versionArray[part++]=0;
  2010. }
  2011. }
  2012. U_CAPI void U_EXPORT2
  2013. u_versionFromUString(UVersionInfo versionArray, const char16_t *versionString) {
  2014. if(versionArray!=nullptr && versionString!=nullptr) {
  2015. char versionChars[U_MAX_VERSION_STRING_LENGTH+1];
  2016. int32_t len = u_strlen(versionString);
  2017. if(len>U_MAX_VERSION_STRING_LENGTH) {
  2018. len = U_MAX_VERSION_STRING_LENGTH;
  2019. }
  2020. u_UCharsToChars(versionString, versionChars, len);
  2021. versionChars[len]=0;
  2022. u_versionFromString(versionArray, versionChars);
  2023. }
  2024. }
  2025. U_CAPI void U_EXPORT2
  2026. u_versionToString(const UVersionInfo versionArray, char *versionString) {
  2027. uint16_t count, part;
  2028. uint8_t field;
  2029. if(versionString==nullptr) {
  2030. return;
  2031. }
  2032. if(versionArray==nullptr) {
  2033. versionString[0]=0;
  2034. return;
  2035. }
  2036. /* count how many fields need to be written */
  2037. for(count=4; count>0 && versionArray[count-1]==0; --count) {
  2038. }
  2039. if(count <= 1) {
  2040. count = 2;
  2041. }
  2042. /* write the first part */
  2043. /* write the decimal field value */
  2044. field=versionArray[0];
  2045. if(field>=100) {
  2046. *versionString++=(char)('0'+field/100);
  2047. field%=100;
  2048. }
  2049. if(field>=10) {
  2050. *versionString++=(char)('0'+field/10);
  2051. field%=10;
  2052. }
  2053. *versionString++=(char)('0'+field);
  2054. /* write the following parts */
  2055. for(part=1; part<count; ++part) {
  2056. /* write a dot first */
  2057. *versionString++=U_VERSION_DELIMITER;
  2058. /* write the decimal field value */
  2059. field=versionArray[part];
  2060. if(field>=100) {
  2061. *versionString++=(char)('0'+field/100);
  2062. field%=100;
  2063. }
  2064. if(field>=10) {
  2065. *versionString++=(char)('0'+field/10);
  2066. field%=10;
  2067. }
  2068. *versionString++=(char)('0'+field);
  2069. }
  2070. /* NUL-terminate */
  2071. *versionString=0;
  2072. }
  2073. U_CAPI void U_EXPORT2
  2074. u_getVersion(UVersionInfo versionArray) {
  2075. (void)copyright; // Suppress unused variable warning from clang.
  2076. u_versionFromString(versionArray, U_ICU_VERSION);
  2077. }
  2078. /**
  2079. * icucfg.h dependent code
  2080. */
  2081. #if U_ENABLE_DYLOAD && HAVE_DLOPEN && !U_PLATFORM_USES_ONLY_WIN32_API
  2082. #if HAVE_DLFCN_H
  2083. #ifdef __MVS__
  2084. #ifndef __SUSV3
  2085. #define __SUSV3 1
  2086. #endif
  2087. #endif
  2088. #include <dlfcn.h>
  2089. #endif /* HAVE_DLFCN_H */
  2090. U_CAPI void * U_EXPORT2
  2091. uprv_dl_open(const char *libName, UErrorCode *status) {
  2092. void *ret = nullptr;
  2093. if(U_FAILURE(*status)) return ret;
  2094. ret = dlopen(libName, RTLD_NOW|RTLD_GLOBAL);
  2095. if(ret==nullptr) {
  2096. #ifdef U_TRACE_DYLOAD
  2097. printf("dlerror on dlopen(%s): %s\n", libName, dlerror());
  2098. #endif
  2099. *status = U_MISSING_RESOURCE_ERROR;
  2100. }
  2101. return ret;
  2102. }
  2103. U_CAPI void U_EXPORT2
  2104. uprv_dl_close(void *lib, UErrorCode *status) {
  2105. if(U_FAILURE(*status)) return;
  2106. dlclose(lib);
  2107. }
  2108. U_CAPI UVoidFunction* U_EXPORT2
  2109. uprv_dlsym_func(void *lib, const char* sym, UErrorCode *status) {
  2110. union {
  2111. UVoidFunction *fp;
  2112. void *vp;
  2113. } uret;
  2114. uret.fp = nullptr;
  2115. if(U_FAILURE(*status)) return uret.fp;
  2116. uret.vp = dlsym(lib, sym);
  2117. if(uret.vp == nullptr) {
  2118. #ifdef U_TRACE_DYLOAD
  2119. printf("dlerror on dlsym(%p,%s): %s\n", lib,sym, dlerror());
  2120. #endif
  2121. *status = U_MISSING_RESOURCE_ERROR;
  2122. }
  2123. return uret.fp;
  2124. }
  2125. #elif U_ENABLE_DYLOAD && U_PLATFORM_USES_ONLY_WIN32_API && !U_PLATFORM_HAS_WINUWP_API
  2126. /* Windows API implementation. */
  2127. // Note: UWP does not expose/allow these APIs, so the UWP version gets the null implementation. */
  2128. U_CAPI void * U_EXPORT2
  2129. uprv_dl_open(const char *libName, UErrorCode *status) {
  2130. HMODULE lib = nullptr;
  2131. if(U_FAILURE(*status)) return nullptr;
  2132. lib = LoadLibraryA(libName);
  2133. if(lib==nullptr) {
  2134. *status = U_MISSING_RESOURCE_ERROR;
  2135. }
  2136. return (void*)lib;
  2137. }
  2138. U_CAPI void U_EXPORT2
  2139. uprv_dl_close(void *lib, UErrorCode *status) {
  2140. HMODULE handle = (HMODULE)lib;
  2141. if(U_FAILURE(*status)) return;
  2142. FreeLibrary(handle);
  2143. return;
  2144. }
  2145. U_CAPI UVoidFunction* U_EXPORT2
  2146. uprv_dlsym_func(void *lib, const char* sym, UErrorCode *status) {
  2147. HMODULE handle = (HMODULE)lib;
  2148. UVoidFunction* addr = nullptr;
  2149. if(U_FAILURE(*status) || lib==nullptr) return nullptr;
  2150. addr = (UVoidFunction*)GetProcAddress(handle, sym);
  2151. if(addr==nullptr) {
  2152. DWORD lastError = GetLastError();
  2153. if(lastError == ERROR_PROC_NOT_FOUND) {
  2154. *status = U_MISSING_RESOURCE_ERROR;
  2155. } else {
  2156. *status = U_UNSUPPORTED_ERROR; /* other unknown error. */
  2157. }
  2158. }
  2159. return addr;
  2160. }
  2161. #else
  2162. /* No dynamic loading, null (nonexistent) implementation. */
  2163. U_CAPI void * U_EXPORT2
  2164. uprv_dl_open(const char *libName, UErrorCode *status) {
  2165. (void)libName;
  2166. if(U_FAILURE(*status)) return nullptr;
  2167. *status = U_UNSUPPORTED_ERROR;
  2168. return nullptr;
  2169. }
  2170. U_CAPI void U_EXPORT2
  2171. uprv_dl_close(void *lib, UErrorCode *status) {
  2172. (void)lib;
  2173. if(U_FAILURE(*status)) return;
  2174. *status = U_UNSUPPORTED_ERROR;
  2175. return;
  2176. }
  2177. U_CAPI UVoidFunction* U_EXPORT2
  2178. uprv_dlsym_func(void *lib, const char* sym, UErrorCode *status) {
  2179. (void)lib;
  2180. (void)sym;
  2181. if(U_SUCCESS(*status)) {
  2182. *status = U_UNSUPPORTED_ERROR;
  2183. }
  2184. return (UVoidFunction*)nullptr;
  2185. }
  2186. #endif
  2187. /*
  2188. * Hey, Emacs, please set the following:
  2189. *
  2190. * Local Variables:
  2191. * indent-tabs-mode: nil
  2192. * End:
  2193. *
  2194. */