Coverage Report

Created: 2018-09-25 14:53

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