Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members  

putil.c

00001 /*
00002 *******************************************************************************
00003 *
00004 *   Copyright (C) 1997-1999, International Business Machines
00005 *   Corporation and others.  All Rights Reserved.
00006 *
00007 *******************************************************************************
00008 *
00009 *  FILE NAME : putil.c (previously putil.cpp and ptypes.cpp)
00010 *
00011 *   Date        Name        Description
00012 *   04/14/97    aliu        Creation.
00013 *   04/24/97    aliu        Added getDefaultDataDirectory() and
00014 *                            getDefaultLocaleID().
00015 *   04/28/97    aliu        Rewritten to assume Unix and apply general methods 
00016 *                            for assumed case.  Non-UNIX platforms must be
00017 *                            special-cased.  Rewrote numeric methods dealing
00018 *                            with NaN and Infinity to be platform independent
00019 *                             over all IEEE 754 platforms.
00020 *   05/13/97    aliu        Restored sign of timezone 
00021 *                            (semantics are hours West of GMT)
00022 *   06/16/98    erm         Added IEEE_754 stuff, cleaned up isInfinite, isNan,
00023 *                             nextDouble..
00024 *   07/22/98    stephen     Added remainder, max, min, trunc
00025 *   08/13/98    stephen     Added isNegativeInfinity, isPositiveInfinity
00026 *   08/24/98    stephen     Added longBitsFromDouble
00027 *   09/08/98    stephen     Minor changes for Mac Port
00028 *   03/02/99    stephen     Removed openFile().  Added AS400 support.  
00029 *                            Fixed EBCDIC tables
00030 *   04/15/99    stephen     Converted to C.
00031 *   06/28/99    stephen     Removed mutex locking in u_isBigEndian().
00032 *   08/04/99    jeffrey R.  Added OS/2 changes
00033 *   11/15/99    helena      Integrated S/390 IEEE support.
00034 *******************************************************************************
00035 */
00036 
00037 #ifdef _AIX
00038 #    include<sys/types.h>
00039 #endif
00040 
00041 /* Define _XOPEN_SOURCE for Solaris and friends. */
00042 #ifndef PTX
00043 #ifndef _XOPEN_SOURCE
00044 #define _XOPEN_SOURCE
00045 #endif
00046 
00047 /* Define __USE_POSIX and __USE_XOPEN for Linux and glibc. */
00048 #ifndef __USE_POSIX
00049 #define __USE_POSIX
00050 #endif
00051 #ifndef __USE_XOPEN
00052 #define __USE_XOPEN
00053 #endif
00054 #endif
00055 
00056 /* Include standard headers. */
00057 #include <stdio.h>
00058 #include <stdlib.h>
00059 #include <string.h>
00060 #include <math.h>
00061 #include <locale.h>
00062 #include <time.h>
00063 
00064 /* include ICU headers */
00065 #include "unicode/utypes.h"
00066 #include "umutex.h"
00067 #include "cmemory.h"
00068 #include "cstring.h"
00069 #include "filestrm.h"
00070 
00071 /* include system headers */
00072 #ifdef WIN32
00073 #   include <wtypes.h>
00074 #   include <winnls.h>
00075 #   include "locmap.h"
00076 #elif defined(OS2)
00077 #   define INCL_DOSMISC
00078 #   define INCL_DOSERRORS
00079 #   define INCL_DOSMODULEMGR
00080 #   include <os2.h>
00081 #elif defined(OS400)
00082 #   include <float.h>
00083 #elif defined(XP_MAC)
00084 #   include <Files.h>
00085 #   include <IntlResources.h>
00086 #   include <Script.h>
00087 #   include <Folders.h>
00088 #   include <Errors.h>
00089 #   include <TextUtils.h>
00090 #elif defined(AIX)
00091 #   include <sys/ldr.h>
00092 #elif defined(U_SOLARIS) || defined(U_LINUX)
00093 #   include <dlfcn.h>
00094 #   include <link.h>
00095 #elif defined(HPUX)
00096 #   include <dl.h>
00097 #endif 
00098 
00099 /* floating point implementations ------------------------------------------- */
00100 
00101 /* We return QNAN rather than SNAN*/
00102 #if IEEE_754
00103 #define NAN_TOP ((int16_t)0x7FF8)
00104 #define INF_TOP ((int16_t)0x7FF0)
00105 #elif defined(OS390)
00106 #define NAN_TOP ((int16_t)0x7F08)
00107 #define INF_TOP ((int16_t)0x3F00)
00108 #endif
00109 
00110 #define SIGN 0x80000000L
00111 
00112 /* statics */
00113 static UBool fgNaNInitialized = FALSE;
00114 static double fgNan;
00115 static UBool fgInfInitialized = FALSE;
00116 static double fgInf;
00117 
00118 /* protos */
00119 static char* u_topNBytesOfDouble(double* d, int n);
00120 static char* u_bottomNBytesOfDouble(double* d, int n);
00121 
00122 
00123 /*---------------------------------------------------------------------------
00124   Platform utilities
00125   Our general strategy is to assume we're on a POSIX platform.  Platforms which
00126   are non-POSIX must declare themselves so.  The default POSIX implementation
00127   will sometimes work for non-POSIX platforms as well (e.g., the NaN-related
00128   functions).
00129   ---------------------------------------------------------------------------*/
00130 
00131 #if defined(_WIN32) || defined(XP_MAC) || defined(OS400) || defined(OS2)
00132 #   undef U_POSIX_LOCALE
00133 #else
00134 #   define U_POSIX_LOCALE       1
00135 #endif
00136 
00137 /*
00138  * Only include langinfo.h if we have a way to get the codeset. If we later
00139  * depend on more feature, we can test on U_HAVE_NL_LANGINFO.
00140  *
00141  */
00142 
00143 #if U_HAVE_NL_LANGINFO_CODESET
00144 #include <langinfo.h>
00145 #endif
00146 
00147 /*---------------------------------------------------------------------------
00148   Universal Implementations
00149   These are designed to work on all platforms.  Try these, and if they don't
00150   work on your platform, then special case your platform with new
00151   implementations.
00152   ---------------------------------------------------------------------------*/
00153 
00154 /* Get UTC (GMT) time measured in seconds since 0:00 on 1/1/70.*/
00155 int32_t
00156 uprv_getUTCtime()
00157 {
00158 #ifdef XP_MAC
00159     time_t t, t1, t2;
00160     struct tm tmrec;
00161 
00162     memset( &tmrec, 0, sizeof(tmrec) );
00163     tmrec.tm_year = 70;
00164     tmrec.tm_mon = 0;
00165     tmrec.tm_mday = 1;
00166     t1 = mktime(&tmrec);    /* seconds of 1/1/1970*/
00167 
00168     time(&t);
00169     memcpy( &tmrec, gmtime(&t), sizeof(tmrec) );
00170     t2 = mktime(&tmrec);    /* seconds of current GMT*/
00171     return t2 - t1;         /* GMT (or UTC) in seconds since 1970*/
00172 #else
00173     time_t epochtime;
00174     time(&epochtime);
00175     return epochtime;
00176 #endif
00177 }
00178 
00179 /*-----------------------------------------------------------------------------
00180   IEEE 754
00181   These methods detect and return NaN and infinity values for doubles
00182   conforming to IEEE 754.  Platforms which support this standard include X86,
00183   Mac 680x0, Mac PowerPC, AIX RS/6000, and most others.
00184   If this doesn't work on your platform, you have non-IEEE floating-point, and
00185   will need to code your own versions.  A naive implementation is to return 0.0
00186   for getNaN and getInfinity, and false for isNaN and isInfinite.
00187   ---------------------------------------------------------------------------*/
00188 
00189 UBool 
00190 uprv_isNaN(double number)
00191 {
00192 #if IEEE_754
00193     /* This should work in theory, but it doesn't, so we resort to the more*/
00194     /* complicated method below.*/
00195     /*  return number != number;*/
00196 
00197     /* You can't return number == getNaN() because, by definition, NaN != x for*/
00198     /* all x, including NaN (that is, NaN != NaN).  So instead, we compare*/
00199     /* against the known bit pattern.  We must be careful of endianism here.*/
00200     /* The pattern we are looking for id:*/
00201 
00202     /*   7FFy yyyy yyyy yyyy  (some y non-zero)*/
00203 
00204     /* There are two different kinds of NaN, but we ignore the distinction*/
00205     /* here.  Note that the y value must be non-zero; if it is zero, then we*/
00206     /* have infinity.*/
00207 
00208     uint32_t highBits = *(uint32_t*)u_topNBytesOfDouble(&number, 
00209                               sizeof(uint32_t));
00210     uint32_t lowBits  = *(uint32_t*)u_bottomNBytesOfDouble(&number, 
00211                              sizeof(uint32_t));
00212 
00213     return (UBool)(((highBits & 0x7FF00000L) == 0x7FF00000L) && 
00214       (((highBits & 0x000FFFFFL) != 0) || (lowBits != 0)));
00215 
00216 #elif defined(OS390)
00217     uint32_t highBits = *(uint32_t*)u_topNBytesOfDouble(&number,
00218                         sizeof(uint32_t));
00219     uint32_t lowBits  = *(uint32_t*)u_bottomNBytesOfDouble(&number,
00220                         sizeof(uint32_t));
00221 
00222     return ((highBits & 0x7F080000L) == 0x7F080000L) &&
00223       (lowBits == 0x00000000L);
00224 
00225 #else
00226     /* If your platform doesn't support IEEE 754 but *does* have an NaN value,*/
00227     /* you'll need to replace this default implementation with what's correct*/
00228     /* for your platform.*/
00229     return number != number;
00230 #endif
00231 }
00232 
00233 UBool
00234 uprv_isInfinite(double number)
00235 {
00236 #if IEEE_754
00237     /* We know the top bit is the sign bit, so we mask that off in a copy of */
00238     /* the number and compare against infinity. [LIU]*/
00239     /* The following approach doesn't work for some reason, so we go ahead and */
00240     /* scrutinize the pattern itself. */
00241     /*  double a = number; */
00242     /*  *(int8_t*)u_topNBytesOfDouble(&a, 1) &= 0x7F;*/
00243     /*  return a == uprv_getInfinity();*/
00244     /* Instead, We want to see either:*/
00245 
00246     /*   7FF0 0000 0000 0000*/
00247     /*   FFF0 0000 0000 0000*/
00248   
00249     uint32_t highBits = *(uint32_t*)u_topNBytesOfDouble(&number, 
00250                         sizeof(uint32_t));
00251     uint32_t lowBits  = *(uint32_t*)u_bottomNBytesOfDouble(&number, 
00252                         sizeof(uint32_t));
00253 
00254     return (UBool)(((highBits  & ~SIGN) == 0x7FF00000L) &&
00255       (lowBits == 0x00000000L));
00256 
00257 #elif defined(OS390)
00258     uint32_t highBits = *(uint32_t*)u_topNBytesOfDouble(&number,
00259                         sizeof(uint32_t));
00260     uint32_t lowBits  = *(uint32_t*)u_bottomNBytesOfDouble(&number,
00261                         sizeof(uint32_t));
00262 
00263     return ((highBits  & ~SIGN) == 0x70FF0000L) && (lowBits == 0x00000000L);
00264 
00265 #else
00266     /* If your platform doesn't support IEEE 754 but *does* have an infinity*/
00267     /* value, you'll need to replace this default implementation with what's*/
00268     /* correct for your platform.*/
00269     return number == (2.0 * number);
00270 #endif
00271 }
00272 
00273 UBool   
00274 uprv_isPositiveInfinity(double number)
00275 {
00276 #if IEEE_754 || defined(OS390)
00277     return (UBool)(number > 0 && uprv_isInfinite(number));
00278 #else
00279     return uprv_isInfinite(number);
00280 #endif
00281 }
00282 
00283 UBool   
00284 uprv_isNegativeInfinity(double number)
00285 {
00286 #if IEEE_754 || defined(OS390)
00287     return (UBool)(number < 0 && uprv_isInfinite(number));
00288 
00289 #else
00290     uint32_t highBits = *(uint32_t*)u_topNBytesOfDouble(&number,
00291                         sizeof(uint32_t));
00292     return((highBits & SIGN) && uprv_isInfinite(number));
00293 
00294 #endif
00295 }
00296 
00297 double 
00298 uprv_getNaN()
00299 {
00300 #if IEEE_754 || defined(OS390)
00301     if( !fgNaNInitialized) {
00302         umtx_lock(NULL);
00303         if( ! fgNaNInitialized) {
00304             int i;
00305             int8_t* p = (int8_t*)&fgNan;
00306             for(i = 0; i < sizeof(double); ++i) 
00307                 *p++ = 0;
00308             *(int16_t*)u_topNBytesOfDouble(&fgNan, sizeof(NAN_TOP)) = NAN_TOP;
00309             fgNaNInitialized = TRUE;
00310         }
00311         umtx_unlock(NULL);
00312     }
00313     return fgNan;
00314 #else
00315     /* If your platform doesn't support IEEE 754 but *does* have an NaN value,*/
00316     /* you'll need to replace this default implementation with what's correct*/
00317     /* for your platform.*/
00318     return 0.0;
00319 #endif
00320 }
00321 
00322 double 
00323 uprv_getInfinity()
00324 {
00325 #if IEEE_754 || defined(OS390)
00326     if (!fgInfInitialized)
00327     {
00328         int i;
00329         int8_t* p = (int8_t*)&fgInf;
00330         for(i = 0; i < sizeof(double); ++i) 
00331             *p++ = 0;
00332         *(int16_t*)u_topNBytesOfDouble(&fgInf, sizeof(INF_TOP)) = INF_TOP;
00333         fgInfInitialized = TRUE;
00334     }
00335     return fgInf;
00336 #else
00337     /* If your platform doesn't support IEEE 754 but *does* have an infinity*/
00338     /* value, you'll need to replace this default implementation with what's*/
00339     /* correct for your platform.*/
00340     return 0.0;
00341 #endif
00342 }
00343 
00344 double 
00345 uprv_floor(double x)
00346 {
00347     return floor(x);
00348 }
00349 
00350 double 
00351 uprv_ceil(double x)
00352 {
00353     return ceil(x);
00354 }
00355 
00356 double 
00357 uprv_fabs(double x)
00358 {
00359     return fabs(x);
00360 }
00361 
00362 double 
00363 uprv_modf(double x, double* y)
00364 {
00365     return modf(x, y);
00366 }
00367 
00368 double 
00369 uprv_fmod(double x, double y)
00370 {
00371     return fmod(x, y);
00372 }
00373 
00374 double
00375 uprv_pow10(int32_t x)
00376 {
00377     /* This is declared as "double pow(double x, double y)" */
00378     return pow(10.0, (double)x);
00379 }
00380 
00406 double 
00407 uprv_IEEEremainder(double x, double p)
00408 {
00409 #if IEEE_754
00410     int32_t hx, hp;
00411     uint32_t sx, lx, lp;
00412     double p_half;
00413 
00414     hx = *(int32_t*)u_topNBytesOfDouble(&x, sizeof(int32_t));
00415     lx = *(uint32_t*)u_bottomNBytesOfDouble(&x, sizeof(uint32_t));
00416 
00417     hp = *(int32_t*)u_topNBytesOfDouble(&p, sizeof(int32_t));
00418     lp = *(uint32_t*)u_bottomNBytesOfDouble(&p, sizeof(uint32_t));
00419 
00420     sx = hx & SIGN;
00421 
00422     hp &= 0x7fffffff;
00423     hx &= 0x7fffffff;
00424 
00425     /* purge off exception values */
00426     if((hp|lp) == 0) 
00427         return (x*p) / (x*p);     /* p = 0 */
00428     if((hx >= 0x7ff00000)||        /* x not finite */
00429       ((hp>=0x7ff00000) &&    /* p is NaN */
00430       (((hp-0x7ff00000)|lp) != 0)))
00431         return (x*p) / (x*p);
00432 
00433     if(hp <= 0x7fdfffff) 
00434         x = uprv_fmod(x, p + p);    /* now x < 2p */
00435     if(((hx-hp)|(lx-lp)) == 0) 
00436         return 0.0 * x;
00437     x = uprv_fabs(x);
00438     p = uprv_fabs(p);
00439     if (hp < 0x00200000) {
00440         if(x + x > p) {
00441             x -= p;
00442             if(x + x >= p) 
00443                 x -= p;
00444         }
00445     }
00446     else {
00447         p_half = 0.5 * p;
00448         if(x > p_half) {
00449             x -= p;
00450             if(x >= p_half) 
00451                 x -= p;
00452         }
00453     }
00454 
00455     *(int32_t*)u_topNBytesOfDouble(&x, sizeof(int32_t)) ^= sx;
00456 
00457     return x;
00458 
00459 #else
00460     /* INACCURATE but portable implementation of IEEEremainder.  This
00461      * implementation should work on platforms that do not have IEEE
00462      * bit layouts.  Deficiencies of this implementation are its
00463      * inaccuracy and that it does not attempt to handle NaN or
00464      * infinite parameters and it returns the dividend if the divisor
00465      * is zero.  This is probably not an issue on non-IEEE
00466      * platforms. - aliu
00467      */
00468     if (p != 0.0) { /* exclude zero divisor */
00469         double a = x / p;
00470         double aint = uprv_floor(a);
00471         double afrac = a - aint;
00472         if (afrac > 0.5) {
00473             aint += 1.0;
00474         } else if (!(afrac < 0.5)) { /* avoid == comparison */
00475             if (uprv_modf(aint / 2.0, &a) > 0.0) {
00476                 aint += 1.0;
00477             }
00478         }
00479         x -= (p * aint);
00480     }
00481     return x;
00482 #endif
00483 }
00484 
00485 double 
00486 uprv_fmax(double x, double y)
00487 {
00488 #if IEEE_754
00489     int32_t lowBits;
00490 
00491     /* first handle NaN*/
00492     if(uprv_isNaN(x) || uprv_isNaN(y))
00493         return uprv_getNaN();
00494 
00495     /* check for -0 and 0*/
00496     lowBits = *(uint32_t*) u_bottomNBytesOfDouble(&x, sizeof(uint32_t));
00497     if(x == 0.0 && y == 0.0 && (lowBits & SIGN))
00498         return y; 
00499 
00500     return (x > y ? x : y);
00501 #else
00502 
00503     /* this should work for all flt point w/o NaN and Infpecial cases */
00504     return (x > y ? x : y);
00505 #endif
00506 }
00507 
00508 int32_t 
00509 uprv_max(int32_t x, int32_t y)
00510 {
00511     return (x > y ? x : y);
00512 }
00513 
00514 double 
00515 uprv_fmin(double x, double y)
00516 {
00517 #if IEEE_754
00518     int32_t lowBits;
00519 
00520     /* first handle NaN*/
00521     if(uprv_isNaN(x) || uprv_isNaN(y))
00522         return uprv_getNaN();
00523 
00524     /* check for -0 and 0*/
00525     lowBits = *(uint32_t*) u_bottomNBytesOfDouble(&y, sizeof(uint32_t));
00526     if(x == 0.0 && y == 0.0 && (lowBits & SIGN))
00527         return y; 
00528 
00529     return (x > y ? y : x);
00530 #else
00531 
00532     /* this should work for all flt point w/o NaN and Inf special cases */
00533     return (x > y ? y : x);
00534 #endif
00535 }
00536 
00537 int32_t 
00538 uprv_min(int32_t x, int32_t y)
00539 {
00540     return (x > y ? y : x);
00541 }
00542 
00550 double 
00551 uprv_trunc(double d)
00552 {
00553 #if IEEE_754
00554     int32_t lowBits;
00555 
00556     /* handle error cases*/
00557     if(uprv_isNaN(d))
00558         return uprv_getNaN();
00559     if(uprv_isInfinite(d))
00560         return uprv_getInfinity();
00561 
00562     lowBits = *(uint32_t*) u_bottomNBytesOfDouble(&d, sizeof(uint32_t));
00563     if( (d == 0.0 && (lowBits & SIGN)) || d < 0)
00564         return ceil(d);
00565     else
00566         return floor(d);
00567 
00568 #else
00569   return d >= 0 ? floor(d) : ceil(d);
00570 
00571 #endif
00572 }
00573 
00574 void 
00575 uprv_longBitsFromDouble(double d, int32_t *hi, uint32_t *lo)
00576 {
00577     *hi = *(int32_t*)u_topNBytesOfDouble(&d, sizeof(int32_t));
00578     *lo = *(uint32_t*)u_bottomNBytesOfDouble(&d, sizeof(uint32_t));
00579 }
00580 
00581 
00589 int16_t 
00590 uprv_log10(double d)
00591 {
00592     /* The reason this routine is needed is that simply taking the*/
00593     /* log and dividing by log10 yields a result which may be off*/
00594     /* by 1 due to rounding errors.  For example, the naive log10*/
00595     /* of 1.0e300 taken this way is 299, rather than 300.*/
00596     double alog10 = log(d) / log(10.0);
00597     int16_t ailog10 = (int16_t) floor(alog10);
00598 
00599     /* Positive logs could be too small, e.g. 0.99 instead of 1.0*/
00600     if (alog10 > 0 && d >= pow(10.0, ailog10 + 1))
00601         ++ailog10;
00602 
00603     /* Negative logs could be too big, e.g. -0.99 instead of -1.0*/
00604     else if (alog10 < 0 && d < pow(10.0, ailog10))
00605         --ailog10;
00606 
00607     return ailog10;
00608 }
00609 
00610 int32_t 
00611 uprv_digitsAfterDecimal(double x)
00612 {
00613     char buffer[20];
00614     int32_t numDigits;
00615     char *p;
00616     int32_t ptPos, exponent;
00617 
00618     /* negative numbers throw off the calculations*/
00619     x = fabs(x);
00620 
00621     /* cheat and use the string-format routine to get a string representation*/
00622     /* (it handles mathematical inaccuracy better than we can), then find out */
00623     /* many characters are to the right of the decimal point */
00624     sprintf(buffer, "%.9g", x);
00625     p = uprv_strchr(buffer, '.');
00626     if (p == 0)
00627         return 0;
00628 
00629     ptPos = (int16_t)(p - buffer);
00630     numDigits = (int16_t)(strlen(buffer) - ptPos - 1);
00631 
00632     /* if the number's string representation is in scientific notation, find */
00633     /* the exponent and take it into account*/
00634     exponent = 0;
00635     p = uprv_strchr(buffer, 'e');
00636     if (p != 0) {
00637         int16_t expPos = (int16_t)(p - buffer);
00638         numDigits -= strlen(buffer) - expPos;
00639         exponent = (int16_t)(atoi(p + 1));
00640     }
00641 
00642     /* the string representation may still have spurious decimal digits in it, */
00643     /* so we cut off at the ninth digit to the right of the decimal, and have */
00644     /* to search backward from there to the first non-zero digit*/
00645     if (numDigits > 9) {
00646         numDigits = 9;
00647         while (numDigits > 0 && buffer[ptPos + numDigits] == '0')
00648             --numDigits;
00649     }
00650     numDigits -= exponent;
00651     return numDigits;
00652 }
00653 
00654 /*---------------------------------------------------------------------------
00655   Platform-specific Implementations
00656   Try these, and if they don't work on your platform, then special case your
00657   platform with new implementations.
00658   ---------------------------------------------------------------------------*/
00659 
00660 /* Time zone utilities */
00661 void 
00662 uprv_tzset()
00663 {
00664 #ifdef U_TZSET
00665     U_TZSET();
00666 #else
00667     /* no initialization*/
00668 #endif
00669 }
00670 
00671 int32_t 
00672 uprv_timezone()
00673 {
00674 #ifdef U_TIMEZONE
00675     return U_TIMEZONE;
00676 #else
00677     time_t t, t1, t2;
00678     struct tm tmrec;
00679     UBool dst_checked;
00680     int32_t tdiff = 0;
00681 
00682     time(&t);
00683     memcpy( &tmrec, localtime(&t), sizeof(tmrec) );
00684     dst_checked = (tmrec.tm_isdst != 0); /* daylight savings time is checked*/
00685     t1 = mktime(&tmrec);                 /* local time in seconds*/
00686     memcpy( &tmrec, gmtime(&t), sizeof(tmrec) );
00687     t2 = mktime(&tmrec);                 /* GMT (or UTC) in seconds*/
00688     tdiff = t2 - t1;
00689     /* imitate NT behaviour, which returns same timezone offset to GMT for 
00690        winter and summer*/
00691     if (dst_checked)
00692         tdiff += 3600;
00693     return tdiff;
00694 #endif
00695 }
00696 
00697 char* 
00698 uprv_tzname(int n)
00699 {
00700 #ifdef U_TZNAME
00701     return U_TZNAME[n];
00702 #else
00703     return "";
00704 #endif
00705 }
00706 
00707 /* Get and set the ICU data directory --------------------------------------- */
00708 
00709 static UBool
00710 gHaveDataDirectory=FALSE;
00711 
00712 static char
00713 gDataDirectory[1024];
00714 
00715 /*
00716  * Here, we use a mutex to make sure that setting the data directory
00717  * is thread-safe; however, reading it after calling u_getDataDirectory()
00718  * may still occur while it is (re)set and is therefore not thread-safe.
00719  * The best is to not call it after the initialization.
00720  */
00721 U_CAPI void U_EXPORT2
00722 u_setDataDirectory(const char *directory) {
00723     if(directory!=NULL) {
00724         int length=uprv_strlen(directory);
00725 
00726         if(length<sizeof(gDataDirectory)-1) {
00727             umtx_lock(NULL);
00728             if(length==0) {
00729                 *gDataDirectory=0;
00730             } else {
00731                 uprv_memcpy(gDataDirectory, directory, length);
00732 
00733                 /* terminate the directory with a separator (/ or \) */
00734                 if(gDataDirectory[length-1]!=U_FILE_SEP_CHAR) {
00735                     gDataDirectory[length++]=U_FILE_SEP_CHAR;
00736                 }
00737 
00738                 /* zero-terminate it */
00739                 gDataDirectory[length]=0;
00740             }
00741             gHaveDataDirectory=TRUE;
00742             umtx_unlock(NULL);
00743         }
00744     }
00745 }
00746 
00747 
00748 #ifndef ICU_DATA_DIR
00749 
00750 # if defined(XP_MAC)
00751 /*
00752   We need FSpGetFullPath() from Apple Sample Code's "MoreFiles". Look in:
00753     http://developer.apple.com/samplecode/Sample_Code/Files/MoreFiles.htm
00754   and replace the following function..
00755 */
00756 
00757  /* Dummy FSpGetFullPath */
00758 pascal  OSErr   FSpGetFullPath(const FSSpec *spec,
00759                                                            short *fullPathLength,
00760                                                            Handle *fullPath)
00761 {
00762     *fullPath = NULL;
00763     *fullPathLength = 0;
00764     return fnfErr; 
00765 }
00766 # endif /* XP_MAC */
00767 
00768 /*
00769  * get the system drive or volume path
00770  * (Windows: e.g. "C:" or "D:")
00771  * do not terminate with a U_FILE_SEP_CHAR separator
00772  * return the length of the path, or 0 if none
00773  */
00774 static int
00775 getSystemPath(char *path, int size) {
00776 #if defined(XP_MAC)
00777     int16_t volNum;
00778     path[0]=0;
00779     OSErr err=GetVol((unsigned char*)path, &volNum);
00780     if(err==noErr) {
00781         int length=(uint8_t)path[0];
00782         if(length>0) {
00783             /* convert the Pascal string to a C string */
00784             uprv_memmove(path, path+1, length);
00785             path[length]=0;
00786         }
00787         return length;
00788     }
00789 
00790 #elif defined(WIN32)
00791     if(GetSystemDirectory(path, size)>=2 && path[1]==':') {
00792         /* remove the rest of the path - "\\winnt\\system32" or similar */
00793         path[2]=0;
00794         return 2;
00795     }
00796 
00797 #elif defined(OS2)
00798     APIRET rc;
00799     ULONG bootDrive=0;  /* 1=A, 2=B, 3=C, ... */
00800 
00801     rc=DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, (PVOID)&bootDrive, sizeof(ULONG));
00802     if(rc==NO_ERROR) {
00803         /* convert the numeric boot drive to a string */
00804         path[0]='A'+bootDrive-1;
00805         path[1]=':';
00806         path[2]=0;
00807         return 2;
00808     }
00809 #endif
00810 
00811     return 0;
00812 }
00813 
00814 #endif /* ICU_DATA_DIR not defined */
00815 
00816 /*
00817  * get the path to the ICU dynamic library
00818  * do not terminate with a U_FILE_SEP_CHAR separator
00819  * return the length of the path, or 0 if none
00820  */
00821 static int
00822 getLibraryPath(char *path, int size) {
00823 #ifdef WIN32
00824     HINSTANCE mod=GetModuleHandle("icuuc.dll");
00825     if(mod!=NULL) {
00826         if(GetModuleFileName(mod, path, size)>0) {
00827             /* remove the basename and the last file separator */
00828             char *lastSep=uprv_strrchr(path, U_FILE_SEP_CHAR);
00829             if(lastSep!=NULL) {
00830                 *lastSep=0;
00831                 return lastSep-path;
00832             }
00833         }
00834     }
00835 
00836 #elif defined(OS2)
00837     HMODULE mod=NULLHANDLE;
00838     APIRET rc=DosQueryModuleHandle("icuuc.dll", &mod);
00839     if(rc==NO_ERROR) {
00840         rc=DosQueryModuleName(mod, (LONG)size, path);
00841         if(rc==NO_ERROR) {
00842             /* remove the basename and the last file separator */
00843             char *lastSep=uprv_strrchr(path, U_FILE_SEP_CHAR);
00844             if(lastSep!=NULL) {
00845                 *lastSep=0;
00846                 return lastSep-path;
00847             }
00848         }
00849     }
00850 
00851 #elif defined(U_SOLARIS)
00852     void *handle=dlopen(U_COMMON_LIBNAME, RTLD_LAZY); /* "libicu-uc.so" */
00853     if(handle!=NULL) {
00854         Link_map *p=NULL;
00855         char *s;
00856         int rc, length=0;
00857 
00858         /* get the Link_map list */
00859         rc=dlinfo(handle, RTLD_DI_LINKMAP, (void *)&p);
00860         if(rc>=0) {
00861             /* search for the list item for the library itself */
00862             while(p!=NULL) {
00863                s=uprv_strstr(p->l_name, U_COMMON_LIBNAME); /* "libicu-uc.so" */
00864                 if(s!=NULL) {
00865                     if(s>p->l_name) {
00866                         /* copy the path, without the basename and the last separator */
00867                         length=(s-p->l_name)-1;
00868                         if(0<length && length<size) {
00869                             uprv_memcpy(path, p->l_name, length);
00870                             path[length]=0;
00871                         } else {
00872                             length=0;
00873                         }
00874                     }
00875                     break;
00876                 }
00877                 p=p->l_next;
00878             }
00879         }
00880         dlclose(handle);
00881         return length;
00882     }
00883 
00884 #elif defined(AIX)
00885     void *handle=(void*)load(U_COMMON_LIBNAME, L_LIBPATH_EXEC, "."); /* "libicu-uc.a" */
00886     if(handle!=NULL) {
00887         uint8_t buffer[4096];
00888         struct ld_info *p=NULL;
00889         char *s;
00890         int rc, length=0;
00891 
00892         /* copy the linked list of loaded libraries into the buffer */
00893         rc=loadquery(L_GETINFO, buffer, sizeof(buffer));
00894         if(rc>=0) {
00895             /* search for the list item for the library itself */
00896             p=(struct ld_info *)buffer;
00897             for(;;) {
00898                 /* advance (ignore the first list item) */
00899                 if(p->ldinfo_next==0) {
00900                     break;
00901                 }
00902                 p=(struct ld_info *)((uint8_t *)p+p->ldinfo_next);
00903 
00904                 s=uprv_strstr(p->ldinfo_filename, U_COMMON_LIBNAME); /*  "libicuuc.a"    */
00905                 if(s!=NULL) {
00906                     if(s>p->ldinfo_filename) {
00907                         /* copy the path, without the basename and the last separator */
00908                         length=(s-p->ldinfo_filename)-1;
00909                         if(0<length && length<size) {
00910                             uprv_memcpy(path, p->ldinfo_filename, length);
00911                             path[length]=0;
00912                         } else {
00913                             length=0;
00914                         }
00915                     }
00916                     break;
00917                 }
00918                 /* p=p->l_next; */
00919             }
00920         }
00921         unload(handle);
00922         return length;
00923     }
00924 
00925 #elif defined(HPUX)
00926     {
00927         struct shl_descriptor *p=NULL;
00928         char *s;
00929         int i=1, rc, length=0;
00930 
00931         /* walk the list of shared libraries */
00932         /* search for the list item for the library itself */
00933         for(;;) {
00934             rc=shl_get(i, &p);
00935             if(rc<0) {
00936                 break;
00937             }
00938 
00939             s=uprv_strstr(p->filename, U_COMMON_LIBNAME);
00940             if(s!=NULL) {
00941                 if(s>p->filename) {
00942                     /* copy the path, without the basename and the last separator */
00943                     length=(s-p->filename)-1;
00944                     if(0<length && length<size) {
00945                         uprv_memcpy(path, p->filename, length);
00946                         path[length]=0;
00947                     } else {
00948                         length=0;
00949                     }
00950                 }
00951                 break;
00952             }
00953             ++i;
00954         }
00955         return length;
00956     }
00957 
00958 #elif defined(OS390)
00959 #elif defined(OS400)
00960 #elif defined(XP_MAC)
00961 #elif defined(U_LINUX)
00962 #elif defined(TANDEM)
00963 #elif defined(U_POSIX)
00964 #endif
00965 
00966     return 0;
00967 }
00968 
00969 #ifdef WIN32
00970 #   define LIB_PATH_VAR "PATH"
00971 #   define LIB_FILENAME "icuuc.dll"
00972 #elif defined(U_LINUX)
00973 #   define LIB_PATH_VAR "LD_LIBRARY_PATH"
00974 #   define LIB_FILENAME "libicuuc.so"
00975 #elif defined(OS2)
00976 #   define LIB_PATH_VAR "LIBPATH"
00977 #   define LIB_FILENAME "icuuc.dll"
00978 #elif defined(OS390)
00979 #   define LIB_PATH_VAR "LIBPATH"
00980 #   define LIB_FILENAME "libicuuc.a"
00981 #elif defined(TANDEM)
00982 #   define LIB_PATH_VAR "LIBPATH"
00983 #   define LIB_FILENAME "libicuuc.a"
00984 #elif defined(OS400)
00985 #elif defined(XP_MAC)
00986 #elif defined(U_SOLARIS)
00987 #elif defined(AIX)
00988 #elif defined(HPUX)
00989 #elif defined(U_POSIX)
00990 #   define LIB_PATH_VAR "LIBPATH"
00991 #   define LIB_FILENAME "libicuuc.so"
00992 #endif
00993 
00994 /*
00995  * search for the ICU dynamic library and set the path
00996  * do not terminate with a U_FILE_SEP_CHAR separator
00997  * return the length of the path, or 0 if none
00998  */
00999 static int
01000 findLibraryPath(char *path, int size) {
01001     /* common implementation for searching the library path */
01002 #ifdef LIB_FILENAME
01003     const char *libPath=getenv(LIB_PATH_VAR);
01004 
01005     if(libPath!=NULL) {
01006         /* loop over all paths */
01007         FileStream *f;
01008         const char *end;
01009         int length;
01010 
01011         for(;;) {
01012             /* find the end of the path */
01013             end=libPath;
01014             while(*end!=0 && *end!=U_PATH_SEP_CHAR) {
01015                 ++end;
01016             }
01017 
01018             if(end!=libPath) {
01019                 /* try this non-empty path */
01020                 length=end-libPath;
01021 
01022                 /* do not terminate the path */
01023                 if(*(end-1)==U_FILE_SEP_CHAR) {
01024                     --length;
01025                 }
01026 
01027                 /* copy the path and add the library filename */
01028                 uprv_memcpy(path, libPath, length);
01029                 uprv_strcpy(path+length, U_FILE_SEP_STRING LIB_FILENAME);
01030 
01031                 /* does this file exist in this path? */
01032                 f=T_FileStream_open(path, "rb");
01033                 if(f!=NULL) {
01034                     /* yes, clean up and return */
01035                     T_FileStream_close(f);
01036                     path[length]=0;
01037                     return length;
01038                 }
01039             }
01040 
01041             if(*end==0) {
01042                 break;  /* no more path */
01043             }
01044 
01045             /* *end==U_PATH_SEP_CHAR, go to the next path */
01046             libPath=end+1;
01047         }
01048     }
01049 #endif
01050     return 0;
01051 }
01052 
01053 /* define a path for fallbacks */
01054 #ifdef WIN32
01055 #   define FALLBACK_PATH U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "data"
01056 #elif defined(XP_MAC)
01057 #   define FALLBACK_PATH U_FILE_SEP_STRING "ICU" U_FILE_SEP_STRING U_ICU_VERSION U_FILE_SEP_STRING
01058 #else
01059 #   define FALLBACK_PATH U_FILE_SEP_STRING "lib" U_FILE_SEP_STRING "icu" U_FILE_SEP_STRING U_ICU_VERSION U_FILE_SEP_STRING
01060 #endif
01061 
01062 /* #include <stdio.h> */
01063 /* #include <unistd.h> */
01064 
01065 
01066 U_CAPI const char * U_EXPORT2
01067 u_getDataDirectory(void) {
01068     /* if we have the directory, then return it immediately */
01069     if(!gHaveDataDirectory) {
01070         /* we need to look for it */
01071         char pathBuffer[1024];
01072         const char *path = NULL;
01073         int length;
01074 
01075 #       if !defined(XP_MAC)
01076             /* first try to get the environment variable */
01077             path=getenv("ICU_DATA");
01078 /*          fprintf(stderr, " ******** ICU_DATA=%s ********** \n", path); */
01079 /*          { */
01080 /*            int i; */
01081 /*            fprintf(stderr, "E=%08X\n", __environ); */
01082 /*            if(__environ) */
01083 /*            for(i=0;__environ[i] && __environ[i][0];i++) */
01084 /*              puts(__environ[i]); */
01085 /*          } */
01086 #else   /* XP_MAC */
01087                 {
01088                         OSErr myErr;
01089                         short vRef;
01090                         long  dir,newDir;
01091                 int16_t volNum;
01092                         Str255 xpath;
01093                         FSSpec spec;
01094                         short  len;
01095                         Handle full;
01096 
01097                 xpath[0]=0;
01098                 
01099             myErr = GetVol(xpath, &volNum);
01100                                 
01101                         if(myErr == noErr) {
01102                                 myErr = FindFolder(volNum, kApplicationSupportFolderType, TRUE, & vRef, &dir);
01103                                 newDir=-1;
01104                                 if (myErr == noErr) {
01105                                         myErr = 
01106                                                 DirCreate(volNum,
01107                                                                  dir,
01108                                                                  "\pICU",
01109                                                                  &newDir);      
01110                                         if( (myErr == noErr) || (myErr == dupFNErr) ) {
01111                                                 spec.vRefNum = volNum;
01112                                                 spec.parID = dir;
01113                                                 uprv_memcpy(spec.name, "\pICU", 4);
01114                                                 
01115                                                 myErr = FSpGetFullPath(&spec, &len, &full);
01116                                                 if(full != NULL)
01117                                                 {
01118                                                         HLock(full);
01119                                                         uprv_memcpy(pathBuffer,  ((char*)(*full)), len);
01120                                                         pathBuffer[len] = 0;
01121                                                         path = pathBuffer;
01122                                                         DisposeHandle(full);
01123                                                 }       
01124                                         }
01125                                 }
01126                         }
01127                 }
01128 #       endif
01129 #       ifdef WIN32
01130             /* next, try to read the path from the registry */
01131             if(path==NULL || *path==0) {
01132                 HKEY key;
01133 
01134                 if(ERROR_SUCCESS==RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\ICU\\Unicode\\Data", 0, KEY_QUERY_VALUE, &key)) {
01135                     DWORD type=REG_EXPAND_SZ, size=sizeof(pathBuffer);
01136 
01137                     if(ERROR_SUCCESS==RegQueryValueEx(key, "Path", NULL, &type, (unsigned char *)pathBuffer, &size) && size>1) {
01138                         if(type==REG_EXPAND_SZ) {
01139                             /* replace environment variable references by their values */
01140                             char temporaryPath[1024];
01141 
01142                             /* copy the path with variables to the temporary one */
01143                             uprv_memcpy(temporaryPath, pathBuffer, size);
01144 
01145                             /* do the replacement and store it in the pathBuffer */
01146                             size=ExpandEnvironmentStrings(temporaryPath, pathBuffer, sizeof(pathBuffer));
01147                             if(size>0 && size<sizeof(pathBuffer)) {
01148                                 path=pathBuffer;
01149                             }
01150                         } else if(type==REG_SZ) {
01151                             path=pathBuffer;
01152                         }
01153                     }
01154                     RegCloseKey(key);
01155                 }
01156             }
01157 #       endif
01158 
01159         /* next, try to get the path to the ICU dynamic library */
01160         if(path==NULL || *path==0) {
01161             length=getLibraryPath(pathBuffer, sizeof(pathBuffer));
01162             if(length>0) {
01163                 uprv_strcpy(pathBuffer+length, U_FILE_SEP_STRING ".." FALLBACK_PATH);
01164                 path=pathBuffer;
01165             }
01166         }
01167 
01168         /* next, search for the ICU dynamic library */
01169         if(path==NULL || *path==0) {
01170             length=findLibraryPath(pathBuffer, sizeof(pathBuffer));
01171             if(length>0) {
01172                 uprv_strcpy(pathBuffer+length, U_FILE_SEP_STRING ".." FALLBACK_PATH);
01173                 path=pathBuffer;
01174             }
01175         }
01176 
01177         /* last resort: use hardcoded path */
01178         if(path==NULL || *path==0) {
01179             /* ICU_DATA_DIR may be set as a compile option */
01180 #           ifdef ICU_DATA_DIR
01181                 path=ICU_DATA_DIR;
01182 #           else
01183                 length=getSystemPath(pathBuffer, sizeof(pathBuffer));
01184                 if(length>0) {
01185                     uprv_strcpy(pathBuffer+length, FALLBACK_PATH);
01186                     path=pathBuffer;
01187                 } else {
01188                     path=FALLBACK_PATH;
01189                 }
01190 #           endif
01191         }
01192 
01193         u_setDataDirectory(path);
01194     }
01195 
01196     /* we did set the directory if necessary */
01197     return gDataDirectory;
01198 }
01199 
01200 /* Macintosh-specific locale information ------------------------------------ */
01201 #ifdef XP_MAC
01202 
01203 struct mac_lc_rec {
01204   int32_t script;
01205   int32_t region;
01206   int32_t lang;
01207   int32_t date_region;
01208   char* posixID;
01209 };
01210 /* To do: This will be updated with a newer version from www.unicode.org web
01211    page when it's available.*/
01212 #define MAC_LC_MAGIC_NUMBER -5
01213 #define MAC_LC_INIT_NUMBER -9
01214 
01215 mac_lc_rec mac_lc_recs[] = {
01216   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 0, "en_US",  
01217   /* United States*/
01218   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 1, "fr_FR",  
01219   /* France*/
01220   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 2, "en_GB",  
01221   /* Great Britain*/
01222   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 3, "de_DE",  
01223   /* Germany*/
01224   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 4, "it_IT",  
01225   /* Italy*/
01226   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 5, "nl_NL", 
01227   /* Metherlands*/
01228   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 6, "fr_BE", 
01229   /* French for Belgium or Lxembourg*/
01230   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 7, "sv_SE", 
01231   /* Sweden*/
01232   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 9, "da_DK", 
01233   /* Denmark*/
01234   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 10, "pt_PT", 
01235   /* Portugal*/
01236   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 11, "fr_CA", 
01237   /* French Canada*/
01238   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 13, "is_IS", 
01239   /* Israel*/
01240   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 14, "ja_JP", 
01241   /* Japan*/
01242   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 15, "en_AU", 
01243   /* Australia*/
01244   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 16, "ar_AE", 
01245   /* the Arabic world (?)*/
01246   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 17, "fi_FI", 
01247   /* Finland*/
01248   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 18, "fr_CH", 
01249   /* French for Switzerland*/
01250   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 19, "de_CH", 
01251   /* German for Switzerland*/
01252   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 20, "EL_GR", 
01253   /* Greece*/
01254   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 21, "is_IS", 
01255   /* Iceland ===*/
01256   /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 22, "", 
01257     // Malta ===*/
01258   /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 23, "", 
01259     // Cyprus ===*/
01260   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 24, "tr_TR", 
01261   /* Turkey ===*/
01262   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 25, "sh_YU", 
01263   /* Croatian system for Yugoslavia*/
01264   /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 33, "", 
01265     // Hindi system for India*/
01266   /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 34, "", 
01267     // Pakistan*/
01268   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 41, "lt_LT", 
01269   /* Lithuania*/
01270   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 42, "pl_PL", 
01271   /* Poland*/
01272   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 43, "hu_HU", 
01273   /* Hungary*/
01274   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 44, "et_EE", 
01275   /* Estonia*/
01276   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 45, "lv_LV", 
01277   /* Latvia*/
01278   /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 46, "", 
01279     // Lapland  [Ask Rich for the data. HS]*/
01280   /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 47, "", 
01281     // Faeroe Islands*/
01282   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 48, "fa_IR", 
01283   /* Iran*/
01284   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 49, "ru_RU", 
01285   /* Russia*/
01286   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 50, "en_IE", 
01287   /* Ireland*/
01288   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 51, "ko_KR", 
01289   /* Korea*/
01290   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 52, "zh_CN", 
01291   /* People's Republic of China*/
01292   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 53, "zh_TW", 
01293   /* Taiwan*/
01294   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 54, "th_TH", 
01295   /* Thailand*/
01296   
01297   /* fallback is en_US*/
01298   MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 
01299   MAC_LC_MAGIC_NUMBER, "en_US"
01300 };
01301 
01302 #endif
01303 
01304 #if U_POSIX_LOCALE
01305 /* Return just the POSIX id, whatever happens to be in it */
01306 static const char *uprv_getPOSIXID()
01307 {
01308   const char* posixID = getenv("LC_ALL");
01309   if (posixID == 0)
01310     posixID = getenv("LANG");
01311   if (posixID == 0)
01312     posixID = setlocale(LC_ALL, NULL);
01313 
01314   if ( (posixID==0) || 
01315        (uprv_strcmp("C", posixID) == 0) ||
01316        (uprv_strncmp("C ", posixID, 2) == 0) )
01317   {  /* HPUX returns 'C C C C C C C' */
01318     posixID = "en_US";
01319   }
01320   return posixID;
01321 }
01322 #endif
01323 
01324 const char* 
01325 uprv_getDefaultLocaleID()
01326 {
01327 #if U_POSIX_LOCALE
01328   char *correctedPOSIXLocale = 0;
01329   const char* posixID = uprv_getPOSIXID();
01330   char *p;
01331 
01332   /* Format: (no spaces)
01333      ll [ _CC ] [ . MM ] [ @ VV]
01334 
01335      l = lang, C = ctry, M = charmap, V = variant
01336   */
01337 
01338   if((p = uprv_strchr(posixID, '.')) != NULL)
01339   {
01340     /* assume new locale can't be larger than old one? */
01341     correctedPOSIXLocale = uprv_malloc(uprv_strlen(posixID));
01342     uprv_strncpy(correctedPOSIXLocale, posixID, p-posixID);
01343     correctedPOSIXLocale[p-posixID] = 0;
01344 
01345     posixID = correctedPOSIXLocale;
01346   }
01347   
01348   if((p = uprv_strchr(posixID, '@')) != NULL)
01349   {
01350     if(correctedPOSIXLocale == NULL) {
01351       correctedPOSIXLocale = uprv_malloc(uprv_strlen(posixID));
01352       uprv_strncpy(correctedPOSIXLocale, posixID, p-posixID);
01353       correctedPOSIXLocale[p-posixID] = 0;
01354     }
01355     p++;
01356 
01357     /* Take care of any special cases here.. */
01358     if(!uprv_strcmp(p, "nynorsk"))
01359       {
01360         p = "NY";
01361         
01362         /*      Should we assume no_NO_NY instead of possible no__NY?
01363          * if(!uprv_strcmp(correctedPOSIXLocale, "no")) {
01364          *         uprv_strcpy(correctedPOSIXLocale, "no_NO");
01365          *         }
01366          */
01367       }
01368 
01369     if(uprv_strchr(correctedPOSIXLocale,'_') == NULL)
01370       uprv_strcat(correctedPOSIXLocale, "__"); /* aa@b -> aa__b */
01371     else
01372       uprv_strcat(correctedPOSIXLocale, "_"); /* aa_CC@b -> aa_CC_b */
01373     uprv_strcat(correctedPOSIXLocale, p);
01374 
01375     /* Should there be a map from 'no@nynorsk' -> no_NO_NY here?
01376        How about 'russian' -> 'ru'?
01377     */
01378 
01379     posixID = correctedPOSIXLocale;
01380   }
01381   
01382   return posixID;
01383 
01384 #elif defined(WIN32)
01385     UErrorCode status = U_ZERO_ERROR;
01386     LCID id = GetThreadLocale();
01387     const char* locID = T_convertToPosix(id, &status);
01388 
01389     if (U_FAILURE(status)) {
01390         locID = "en_US";
01391     }
01392     return locID;
01393 
01394 #elif defined(XP_MAC)
01395   int32_t script = MAC_LC_INIT_NUMBER; 
01396   /* = IntlScript(); or GetScriptManagerVariable(smSysScript);*/
01397   int32_t region = MAC_LC_INIT_NUMBER; 
01398   /* = GetScriptManagerVariable(smRegionCode);*/
01399   int32_t lang = MAC_LC_INIT_NUMBER;   
01400   /* = GetScriptManagerVariable(smScriptLang);*/
01401   int32_t date_region = MAC_LC_INIT_NUMBER;
01402   char* posixID = 0;
01403   Intl1Hndl ih;
01404   
01405   ih = (Intl1Hndl) GetIntlResource(1);
01406   if (ih)
01407     date_region = ((uint16_t)(*ih)->intl1Vers) >> 8;
01408   
01409   int32_t count = sizeof(mac_lc_recs) / sizeof(mac_lc_rec);
01410   for (int32_t i = 0; i < count; i++) {
01411     if ( ((mac_lc_recs[i].script == MAC_LC_MAGIC_NUMBER)      
01412       || (mac_lc_recs[i].script == script))
01413      && ((mac_lc_recs[i].region == MAC_LC_MAGIC_NUMBER)
01414          || (mac_lc_recs[i].region == region))
01415      && ((mac_lc_recs[i].lang == MAC_LC_MAGIC_NUMBER)
01416          || (mac_lc_recs[i].lang == lang))
01417      && ((mac_lc_recs[i].date_region == MAC_LC_MAGIC_NUMBER) 
01418          || (mac_lc_recs[i].date_region == date_region))
01419      ) {
01420       posixID = mac_lc_recs[i].posixID;
01421       break;
01422     }
01423   }
01424   
01425   return posixID;
01426 
01427 #elif defined(OS2)
01428     char * locID;
01429 
01430     locID = getenv("LC_ALL");
01431     if (!locID || !*locID)
01432         locID = getenv("LANG");
01433     if (!locID || !*locID) {
01434         locID = "C";
01435     }
01436     if (!stricmp(locID, "c") || !stricmp(locID, "posix") ||
01437         !stricmp(locID, "univ"))
01438         locID = "en_US";
01439     return locID;
01440 
01441 #elif defined(OS400)
01442     /* Todo: TBD needs to be implemented */
01443     return "";
01444 
01445 #endif
01446 
01447 }
01448 
01449 /* end of platform-specific implementation */
01450 
01451 double 
01452 uprv_nextDouble(double d, UBool next)
01453 {
01454 #if IEEE_754
01455   int32_t highBits;
01456   uint32_t lowBits;
01457   int32_t highMagnitude;
01458   uint32_t lowMagnitude;
01459   double result;
01460   uint32_t *highResult, *lowResult;
01461   uint32_t signBit;
01462 
01463   /* filter out NaN's */
01464   if (uprv_isNaN(d)) {
01465     return d;
01466   }
01467   
01468   /* zero's are also a special case */
01469   if (d == 0.0) {
01470     double smallestPositiveDouble = 0.0;
01471     uint32_t *plowBits = 
01472       (uint32_t *)u_bottomNBytesOfDouble(&smallestPositiveDouble, 
01473                      sizeof(uint32_t));
01474     
01475     *plowBits = 1;
01476     
01477     if (next) {
01478       return smallestPositiveDouble;
01479     } else {
01480       return -smallestPositiveDouble;
01481     }
01482   }
01483   
01484   /* if we get here, d is a nonzero value */
01485   
01486   /* hold all bits for later use */
01487   highBits = *(int32_t*)u_topNBytesOfDouble(&d, sizeof(uint32_t));
01488   lowBits = *(uint32_t*)u_bottomNBytesOfDouble(&d, sizeof(uint32_t));
01489   
01490   /* strip off the sign bit */
01491   highMagnitude = highBits & ~SIGN;
01492   lowMagnitude = lowBits;
01493   
01494   /* if next double away from zero, increase magnitude */
01495   if ((highBits >= 0) == next) {
01496     if (highMagnitude != 0x7FF00000L || lowMagnitude != 0x00000000L) {
01497       lowMagnitude += 1;
01498       if (lowMagnitude == 0) {
01499     highMagnitude += 1;
01500       }
01501     }
01502   }
01503   /* else decrease magnitude */
01504   else {
01505     lowMagnitude -= 1;
01506     if (lowMagnitude > lowBits) {
01507       highMagnitude -= 1;
01508     }
01509   }
01510   
01511   /* construct result and return */
01512   signBit = highBits & SIGN;
01513   highResult = (uint32_t *)u_topNBytesOfDouble(&result, sizeof(uint32_t));
01514   lowResult  = (uint32_t *)u_bottomNBytesOfDouble(&result, sizeof(uint32_t));
01515   
01516   *highResult = signBit | highMagnitude;
01517   *lowResult  = lowMagnitude;
01518   return result;
01519 #else
01520 
01521   /* This is the portable implementation...*/
01522   /* a small coefficient within the precision of the mantissa*/
01523   static const double smallValue = 1e-10;  
01524   double epsilon = ((d<0)?-d:d) * smallValue; /* first approximation*/
01525   double last_eps, sum;
01526 
01527   if (epsilon == 0)
01528     epsilon = smallValue; /* for very small d's*/
01529   if (!next)
01530     epsilon = -epsilon;
01531   /* avoid higher precision possibly used for temporay values*/
01532 
01533   last_eps = epsilon * 2.0;
01534   sum = d + epsilon;
01535 
01536   while ((sum != d) && (epsilon != last_eps)) {
01537     last_eps = epsilon;
01538     epsilon /= 2.0;
01539     sum = d + epsilon;
01540   }
01541   return d + last_eps;
01542 #endif
01543 }
01544 
01545 static char*
01546 u_topNBytesOfDouble(double* d, int n)
01547 {
01548   return U_IS_BIG_ENDIAN ? (char*)d : (char*)(d + 1) - n;
01549 }
01550 
01551 static char* u_bottomNBytesOfDouble(double* d, int n)
01552 {
01553   return U_IS_BIG_ENDIAN ? (char*)(d + 1) - n : (char*)d;
01554 }
01555 
01556 U_CAPI const char *
01557 uprv_defaultCodePageForLocale(const char *locale);
01558 
01559 const char* uprv_getDefaultCodepage()
01560 {
01561 #if defined(OS400)
01562   return "ibm-37";
01563 
01564 #elif defined(OS390)
01565   return "ibm-1047-s390";
01566 
01567 #elif defined(XP_MAC)
01568   return "ibm-1275"; /* Macintosh Roman. There must be a better way. fixme! */
01569 
01570 #elif defined(WIN32)
01571   static char tempString[10] = "";
01572   static char codepage[12]={ "cp" };
01573   uprv_strcpy(codepage+2, _itoa(GetACP(), tempString, 10));
01574   return codepage;
01575 
01576 #elif U_POSIX_LOCALE
01577     static char codesetName[100];
01578     char *name = NULL;
01579     char *euro = NULL;
01580     const char *localeName = NULL;
01581     const char *defaultTable = NULL;
01582  
01583     uprv_memset(codesetName, 0, 100);
01584     localeName = uprv_getPOSIXID();
01585     if (localeName != NULL) 
01586     {
01587         uprv_strcpy(codesetName, localeName);
01588         if  ((name = (uprv_strchr(codesetName, (int) '.'))) != NULL) 
01589         {
01590             /* strip the locale name and look at the suffix only */
01591             name++;
01592             if ((euro  = (uprv_strchr(name, (int)'@'))) != NULL)
01593             {
01594                *euro  = 0;
01595             }
01596             /* if we can find the codset name from setlocale, return that. */
01597             if (uprv_strlen(name) != 0) 
01598             {
01599                 return name;
01600             }
01601         } 
01602     }
01603 
01604     /* otherwise, try CTYPE */
01605 
01606     uprv_memset(codesetName, 0, 100);
01607     localeName = setlocale(LC_CTYPE, "");
01608     if (localeName != NULL) 
01609     {
01610         uprv_strcpy(codesetName, localeName);
01611         if  ((name = (uprv_strchr(codesetName, (int) '.'))) != NULL) 
01612         {
01613             /* strip the locale name and look at the suffix only */
01614             name++;
01615             if ((euro  = (uprv_strchr(name, (int)'@'))) != NULL)
01616             {
01617                *euro  = 0;
01618             }
01619             /* if we can find the codset name from setlocale, return that. */
01620             if (uprv_strlen(name) != 0) 
01621             {
01622                 return name;
01623             }
01624         } 
01625     }
01626     if (strlen(codesetName) != 0) 
01627     {
01628         uprv_memset(codesetName, 0, 100);
01629     }
01630 #if U_HAVE_NL_LANGINFO_CODESET
01631      {
01632         const char *codeset = nl_langinfo(U_NL_LANGINFO_CODESET);
01633         if (codeset != NULL) {
01634             uprv_strcpy(codesetName, codeset);
01635         }
01636     }
01637 #endif
01638     if (uprv_strlen(codesetName) == 0) 
01639     {
01640         /* look up in srl's table */
01641         defaultTable = uprv_defaultCodePageForLocale(localeName);
01642         if (defaultTable != NULL)
01643         {
01644             uprv_strcpy(codesetName, defaultTable);
01645         } 
01646         else
01647         {
01648             /* if the table lookup failed, return latin1. */
01649             uprv_strcpy(codesetName, "LATIN_1");
01650         }
01651     }
01652     return codesetName;
01653 #else
01654   return "LATIN_1";
01655 #endif
01656 }
01657 
01658 #if U_CHARSET_FAMILY==U_EBCDIC_FAMILY
01659 #ifdef OS390
01660 /*
01661  * These maps for ASCII to/from EBCDIC are from
01662  * "UTF-EBCDIC - EBCDIC-Friendly Unicode (or UCS) Transformation Format"
01663  * at http://www.unicode.org/unicode/reports/tr16/
01664  * (which should reflect codepage 1047)
01665  * but modified to explicitly exclude the variant
01666  * control and graphical characters that are in ASCII-based
01667  * codepages at 0x80 and above.
01668  * Also, unlike in Version 6.0 of the UTR on UTF-EBCDIC,
01669  * the Line Feed mapping varies according to the environment.
01670  *
01671  * These tables do not establish a converter or a codepage.
01672  */
01673 
01674     /* on S/390 Open Edition, ASCII 0xa (LF) maps to 0x15 and ISO-8 0x85 maps to 0x25 */
01675 #   define E_LF 0x15
01676 #   define A_15 0x0a
01677 #   define A_25 0x00
01678 
01679 #   if 0
01680         /* the CDRA variation of 1047 is not currently used - see tables in #else below */
01681         /* in standard EBCDIC (CDRA), ASCII 0xa (LF) maps to 0x25 and ISO-8 0x85 maps to 0x15 */
01682 #       define E_LF 0x25
01683 #       define A_15 0x00
01684 #       define A_25 0x0a
01685 #   endif
01686 
01687 static uint8_t asciiFromEbcdic[256]={
01688     0x00, 0x01, 0x02, 0x03, 0x00, 0x09, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
01689     0x10, 0x11, 0x12, 0x13, 0x00, A_15, 0x08, 0x00, 0x18, 0x19, 0x00, 0x00, 0x1C, 0x1D, 0x1E, 0x1F,
01690     0x00, 0x00, 0x00, 0x00, 0x00, A_25, 0x17, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x06, 0x07,
01691     0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x14, 0x15, 0x00, 0x1A,
01692     0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
01693     0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
01694     0x2D, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
01695     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
01696     0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
01697     0x00, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
01698     0x00, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00,
01699     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00,
01700     0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
01701     0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
01702     0x5C, 0x00, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
01703     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
01704 };
01705 
01706 static uint8_t ebcdicFromAscii[256]={
01707     0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, 0x16, 0x05, E_LF, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
01708     0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, 0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F,
01709     0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
01710     0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
01711     0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
01712     0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D,
01713     0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
01714     0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
01715     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01716     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01717     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01718     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01719     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01720     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01721     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01722     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
01723 };
01724 
01725 #else
01726 /*
01727  * These maps for ASCII to/from EBCDIC were generated
01728  * using the ICU converter for codepage 37 on 2000-may-22.
01729  * They explicitly exclude the variant
01730  * control and graphical characters that are in ASCII-based
01731  * codepages at 0x80 and above.
01732  *
01733  * These tables do not establish a converter or a codepage.
01734  */
01735 
01736 static uint8_t asciiFromEbcdic[256]={
01737     0x00, 0x01, 0x02, 0x03, 0x00, 0x09, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
01738     0x10, 0x11, 0x12, 0x13, 0x00, 0x00, 0x08, 0x00, 0x18, 0x19, 0x00, 0x00, 0x1c, 0x1d, 0x1e, 0x1f,
01739     0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x17, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x06, 0x07,
01740     0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x14, 0x15, 0x00, 0x1a,
01741     0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x3c, 0x28, 0x2b, 0x7c,
01742     0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x00,
01743     0x2d, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x25, 0x5f, 0x3e, 0x3f,
01744     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22,
01745     0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
01746     0x00, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
01747     0x00, 0x7e, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
01748     0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x5d, 0x00, 0x00, 0x00, 0x00,
01749     0x7b, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
01750     0x7d, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
01751     0x5c, 0x00, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
01752     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
01753 };
01754 
01755 static uint8_t ebcdicFromAscii[256]={
01756     0x00, 0x01, 0x02, 0x03, 0x37, 0x2d, 0x2e, 0x2f, 0x16, 0x05, 0x25, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
01757     0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26, 0x18, 0x19, 0x3f, 0x27, 0x1c, 0x1d, 0x1e, 0x1f,
01758     0x40, 0x5a, 0x7f, 0x7b, 0x5b, 0x6c, 0x50, 0x7d, 0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61,
01759     0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0x7a, 0x5e, 0x4c, 0x7e, 0x6e, 0x6f,
01760     0x7c, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
01761     0xd7, 0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xba, 0xe0, 0xbb, 0xb0, 0x6d,
01762     0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
01763     0x97, 0x98, 0x99, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xc0, 0x4f, 0xd0, 0xa1, 0x07,
01764     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01765     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01766     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01767     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01768     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01769     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01770     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01771     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
01772 };
01773 
01774 #endif
01775 
01776 #endif
01777 
01778 U_CAPI void U_EXPORT2
01779 u_charsToUChars(const char *cs, UChar *us, UTextOffset length) {
01780     while(length>0) {
01781 #if U_CHARSET_FAMILY==U_ASCII_FAMILY
01782         *us++=(UChar)(uint8_t)(*cs++);
01783 #elif U_CHARSET_FAMILY==U_EBCDIC_FAMILY
01784         *us++=(UChar)asciiFromEbcdic[(uint8_t)(*cs++)];
01785 #else
01786 #   error U_CHARSET_FAMILY is not valid
01787 #endif
01788         --length;
01789     }
01790 }
01791 
01792 U_CAPI void U_EXPORT2
01793 u_UCharsToChars(const UChar *us, char *cs, UTextOffset length) {
01794     while(length>0) {
01795 #if U_CHARSET_FAMILY==U_ASCII_FAMILY
01796         *cs++=(char)(*us++);
01797 #elif U_CHARSET_FAMILY==U_EBCDIC_FAMILY
01798         *cs++=(char)ebcdicFromAscii[(uint8_t)(*us++)];
01799 #else
01800 #   error U_CHARSET_FAMILY is not valid
01801 #endif
01802         --length;
01803     }
01804 }
01805 
01806 U_CFUNC void
01807 u_versionFromString(UVersionInfo versionArray, const char *versionString) {
01808     char *end;
01809     uint16_t part=0;
01810 
01811     if(versionArray==NULL) {
01812         return;
01813     }
01814 
01815     if(versionString!=NULL) {
01816         for(;;) {
01817             versionArray[part]=(uint8_t)uprv_strtoul(versionString, &end, 10);
01818             if(end==versionString || ++part==U_MAX_VERSION_LENGTH || *end!=U_VERSION_DELIMITER) {
01819                 break;
01820             }
01821             versionString=end+1;
01822         }
01823     }
01824 
01825     while(part<U_MAX_VERSION_LENGTH) {
01826         versionArray[part++]=0;
01827     }
01828 }
01829 
01830 U_CAPI void U_EXPORT2
01831 u_versionToString(UVersionInfo versionArray, char *versionString) {
01832     uint16_t count, part;
01833     uint8_t field;
01834 
01835     if(versionString==NULL) {
01836         return;
01837     }
01838 
01839     if(versionArray==NULL) {
01840         versionString[0]=0;
01841         return;
01842     }
01843 
01844     /* count how many fields need to be written */
01845     for(count=4; count>0 && versionArray[count-1]==0; --count) {}
01846 
01847     if(count>0) {
01848         /* write the first part */
01849         /* write the decimal field value */
01850         field=versionArray[0];
01851         if(field>=100) {
01852             *versionString++=(char)('0'+field/100);
01853             field%=100;
01854         }
01855         if(field>=10) {
01856             *versionString++=(char)('0'+field/10);
01857             field%=10;
01858         }
01859         *versionString++=(char)('0'+field);
01860 
01861         /* write the following parts */
01862         for(part=1; part<count; ++part) {
01863             /* write a dot first */
01864             *versionString++=U_VERSION_DELIMITER;
01865 
01866             /* write the decimal field value */
01867             field=versionArray[part];
01868             if(field>=100) {
01869                 *versionString++=(char)('0'+field/100);
01870                 field%=100;
01871             }
01872             if(field>=10) {
01873                 *versionString++=(char)('0'+field/10);
01874                 field%=10;
01875             }
01876             *versionString++=(char)('0'+field);
01877         }
01878     }
01879 
01880     /* NUL-terminate */
01881     *versionString=0;
01882 }
01883 
01884 U_CAPI void U_EXPORT2
01885 u_getVersion(UVersionInfo versionArray) {
01886     u_versionFromString(versionArray, U_ICU_VERSION);
01887 }
01888 
01889 /* u_errorName() ------------------------------------------------------------ */
01890 
01891 static const char *
01892 _uErrorInfoName[U_ERROR_INFO_LIMIT-U_ERROR_INFO_START]={
01893     "U_USING_FALLBACK_ERROR",
01894     "U_USING_DEFAULT_ERROR"
01895 };
01896 
01897 static const char *
01898 _uErrorName[U_ERROR_LIMIT]={
01899     "U_ZERO_ERROR",
01900 
01901     "U_ILLEGAL_ARGUMENT_ERROR",
01902     "U_MISSING_RESOURCE_ERROR",
01903     "U_INVALID_FORMAT_ERROR",
01904     "U_FILE_ACCESS_ERROR",
01905     "U_INTERNAL_PROGRAM_ERROR",
01906     "U_MESSAGE_PARSE_ERROR",
01907     "U_MEMORY_ALLOCATION_ERROR",
01908     "U_INDEX_OUTOFBOUNDS_ERROR",
01909     "U_PARSE_ERROR",
01910     "U_INVALID_CHAR_FOUND",
01911     "U_TRUNCATED_CHAR_FOUND",
01912     "U_ILLEGAL_CHAR_FOUND",
01913     "U_INVALID_TABLE_FORMAT",
01914     "U_INVALID_TABLE_FILE",
01915     "U_BUFFER_OVERFLOW_ERROR",
01916     "U_UNSUPPORTED_ERROR",
01917     "U_RESOURCE_TYPE_MISMATCH",
01918     "U_ILLEGAL_ESCAPE_SEQUENCE", 
01919     "U_UNSUPPORTED_ESCAPE_SEQUENCE"
01920 };
01921 
01922 U_CAPI const char * U_EXPORT2
01923 u_errorName(UErrorCode code) {
01924     if(code>=0 && code<U_ERROR_LIMIT) {
01925         return _uErrorName[code];
01926     } else if(code>=U_ERROR_INFO_START && code<U_ERROR_INFO_LIMIT) {
01927         return _uErrorInfoName[code-U_ERROR_INFO_START];
01928     } else {
01929         return "[BOGUS UErrorCode]";
01930     }
01931 }
01932 
01933 struct
01934 {
01935   char loc[20];
01936   char charmap[40];
01937 } 
01938 _localeToDefaultCharmapTable [] =
01939 {
01940 /*
01941   See:         http://czyborra.com/charsets/iso8859.html
01942 */
01943 
01944 /* xx_XX locales first, so they will match: */
01945  { "zh_CN", "gb2312" },  /* Chinese (Simplified) */
01946  { "zh_TW", "Big5" },    /* Chinese (Traditional) */
01947 
01948  { "af", "iso-8859-1" },  /* Afrikaans */
01949  { "ar", "iso-8859-6" },  /* Arabic */
01950  { "be", "iso-8859-5" },  /* Byelorussian */
01951  { "bg", "iso-8859-5" },  /* Bulgarian */
01952  { "ca", "iso-8859-1" },  /* Catalan */
01953  { "cs", "iso-8859-2" },  /* Czech */
01954  { "da", "iso-8859-1" },  /* Danish */
01955  { "de", "iso-8859-1" },  /* German */
01956  { "el", "iso-8859-7" },  /* Greek */ 
01957  { "en", "iso-8859-1" },  /* English */
01958  { "eo", "iso-8859-3" },  /* Esperanto */
01959  { "es", "iso-8859-1" },  /* Spanish */
01960  { "et", "iso-8859-4" },  /* Estonian  */
01961  { "eu", "iso-8859-1" },  /* basque */
01962  { "fi", "iso-8859-1" },  /* Finnish */
01963  { "fo", "iso-8859-1" },  /* faroese */
01964  { "fr", "iso-8859-1" },  /* French */
01965  { "ga", "iso-8859-1" },  /* Irish (Gaelic) */
01966  { "gd", "iso-8859-1" },  /* Scottish */
01967  { "he", "iso-8859-8" },  /* hebrew */
01968  { "hr", "iso-8859-2" },  /* Croatian */
01969  { "hu", "iso-8859-2" },  /* Hungarian */
01970  { "in", "iso-8859-1" },  /* Indonesian */
01971  { "is", "iso-8859-1" },  /* Icelandic */
01972  { "it", "iso-8859-1" },  /* Italian  */
01973  { "iw", "iso-8859-8" },  /* hebrew */
01974  { "ja", "Shift_JIS"  },  /* Japanese [was: ja_JP ] */
01975  { "ji", "iso-8859-8" },  /* Yiddish */
01976  { "kl", "iso-8859-4" },  /* Greenlandic */
01977  { "ko", "euc-kr"     },  /* korean [was: ko_KR ] */
01978  { "lt", "iso-8859-4" },  /* Lithuanian */
01979  { "lv", "iso-8859-4" },  /* latvian (lettish) */
01980  { "mk", "iso-8859-5" },  /* Macedonian */
01981  { "mt", "iso-8859-3" },  /* Maltese  */
01982  { "nl", "iso-8859-1" },  /* dutch */
01983  { "no", "iso-8859-1" },  /* Norwegian */
01984  { "pl", "iso-8859-2" },  /* Polish */
01985  { "pt", "iso-8859-1" },  /* Portugese */
01986  { "rm", "iso-8859-1" },  /* Rhaeto-romance */
01987  { "ro", "iso-8859-2" },  /* Romanian */
01988  { "ru", "iso-8859-5" },  /* Russian */
01989  { "sk", "iso-8859-2" },  /* Slovak  */
01990  { "sl", "iso-8859-2" },  /* Slovenian */
01991  { "sq", "iso-8859-1" },  /* albanian */
01992  { "sr", "iso-8859-5" },  /* Serbian */
01993  { "sv", "iso-8859-1" },  /* Swedish */
01994  { "sw", "iso-8859-1" },  /* Swahili */
01995  { "th", "tis-620"    },  /* Thai [windows-874] */
01996  { "tr", "iso-8859-9" },  /* Turkish */
01997  { "uk", "iso-8859-5" },  /* pre 1990 Ukranian... see: <http://czyborra.com/charsets/cyrillic.html#KOI8-U>  */
01998  { "zh", "Big-5"      },  /* Chinese (Traditional) */
01999  {  "",  ""           }
02000 };
02001 
02002 /* Not-used list, overridden old data  */
02003 #if 0
02004  { "ar", "ibm-1256" }, /* arabic */
02005  { "ko", "ibm-949" }, /* korean  */
02006  { "ru", "ibm-878" }, /* Russian- koi8-r */
02007  { "sk", "ibm-912" }, 
02008 #endif
02009 
02010 U_CAPI const char *
02011 uprv_defaultCodePageForLocale(const char *locale)
02012 {
02013   int32_t i;
02014   int32_t locale_len;
02015 
02016   if (locale == NULL) 
02017   {
02018     return NULL;
02019   }
02020   locale_len = uprv_strlen(locale);
02021 
02022   if(locale_len < 2)
02023     {
02024       return NULL; /* non existent. Not a complete check, but it will
02025                     * make sure that 'c' doesn't match catalan, etc.
02026                     **/
02027     }
02028 
02029   for(i=0; _localeToDefaultCharmapTable[i].loc[0]; i++)
02030   {
02031     if(uprv_strncmp(locale, _localeToDefaultCharmapTable[i].loc, 
02032                     uprv_min(locale_len, 
02033                              uprv_strlen(_localeToDefaultCharmapTable[i].loc)))
02034        == 0)
02035     {
02036       return _localeToDefaultCharmapTable[i].charmap;
02037     }
02038   }
02039 
02040   return NULL;
02041 }
02042 

Generated at Tue Dec 5 10:47:50 2000 for ICU by doxygen1.2.3 written by Dimitri van Heesch, © 1997-2000