Coverage Report

Created: 2023-06-07 07:17

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