diff options
Diffstat (limited to 'tqtinterface/qt4/src/tools/tqlocale.cpp')
| -rw-r--r-- | tqtinterface/qt4/src/tools/tqlocale.cpp | 6311 | 
1 files changed, 6311 insertions, 0 deletions
| diff --git a/tqtinterface/qt4/src/tools/tqlocale.cpp b/tqtinterface/qt4/src/tools/tqlocale.cpp new file mode 100644 index 0000000..26a3230 --- /dev/null +++ b/tqtinterface/qt4/src/tools/tqlocale.cpp @@ -0,0 +1,6311 @@ +/**************************************************************************** +** +** Implementation of the TQLocale class +** +** Copyright (C) 2010 Timothy Pearson and (C) 1992-2008 Trolltech ASA. +** +** This file is part of the tools module of the TQt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.TQPL +** included in the packaging of this file.  Licensees holding valid TQt +** Commercial licenses may use this file in accordance with the TQt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include <sys/types.h> +#include <ctype.h> +#include <float.h> +#include <limits.h> +#include <math.h> +#include <stdlib.h> + +#include "tqlocale.h" +#include "tqlocale_p.h" +#include "tqnamespace.h" + +#ifdef TQT_TQLOCALE_USES_FCVT +# include <tqmutex.h> +# include <private/tqmutexpool_p.h> +#endif + +#if defined (TQ_OS_WIN) +#   include <windows.h> +#   undef NAN        // we want to use our fallback on Windows +#   undef INFINITY +#endif + +#ifdef TQ_OS_LINUX +#    include <fenv.h> +#endif + +#if !defined( TQWS ) && defined( TQ_OS_MAC ) +#   include <Carbon/Carbon.h> +#endif + +#if defined (TQ_OS_SOLARIS) +#   include <ieeefp.h> +#endif + +#if defined (TQ_OS_OSF) && (defined(__DECC) || defined(__DECCXX)) +#   define INFINITY DBL_INFINITY +#   define NAN DBL_TQNAN +#endif + +#if (defined(TQ_CC_GNU) && defined(TQ_OS_WIN)) || __GNUC__ == 4 || defined(TQT_TQLOCALE_NEEDS_VOLATILE) +#   define NEEDS_VOLATILE volatile +#else +#   define NEEDS_VOLATILE +#endif + +enum { +    LittleEndian, +    BigEndian + +#ifdef TQ_BYTE_ORDER +#  if TQ_BYTE_ORDER == TQ_BIG_ENDIAN +    , ByteOrder = BigEndian +#  elif TQ_BYTE_ORDER == TQ_LITTLE_ENDIAN +    , ByteOrder = LittleEndian +#  else +#    error "undefined byte order" +#  endif +}; +#else +}; +static const unsigned int one = 1; +static const bool ByteOrder = ((*((unsigned char *) &one) == 0) ? BigEndian : LittleEndian); +#endif + +#if !defined(INFINITY) +static const unsigned char be_inf_bytes[] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 }; +static const unsigned char le_inf_bytes[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f }; +static inline double inf() +{ +    return (ByteOrder == BigEndian ? +            *((const double *) be_inf_bytes) : +            *((const double *) le_inf_bytes)); +} +#   define INFINITY (::inf()) +#endif + +#if !defined(NAN) +static const unsigned char be_nan_bytes[] = { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 }; +static const unsigned char le_nan_bytes[] = { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f }; +static inline double nan() +{ +    return (ByteOrder == BigEndian ? +            *((const double *) be_nan_bytes) : +            *((const double *) le_nan_bytes)); +} +#   define NAN (::nan()) +#endif + +// We can't rely on -NAN, since all operations on a NAN should return a NAN. +static const unsigned char be_neg_nan_bytes[] = { 0xff, 0xf8, 0, 0, 0, 0, 0, 0 }; +static const unsigned char le_neg_nan_bytes[] = { 0, 0, 0, 0, 0, 0, 0xf8, 0xff }; +static inline double negNan() +{ +    return (ByteOrder == BigEndian ? +            *((const double *) be_neg_nan_bytes) : +            *((const double *) le_neg_nan_bytes)); +} + +// Sizes as defined by the ISO C99 standard - fallback +#ifndef LLONG_MAX +#   define LLONG_MAX TQ_INT64_C(9223372036854775807) +#endif +#ifndef LLONG_MIN +#   define LLONG_MIN (-LLONG_MAX - TQ_INT64_C(1)) +#endif +#ifndef ULLONG_MAX +#   define ULLONG_MAX TQ_UINT64_C(0xffffffffffffffff) +#endif + +#ifndef TQT_TQLOCALE_USES_FCVT +static char *qdtoa(double d, int mode, int ndigits, int *decpt, +                        int *sign, char **rve, char **digits_str); +static char *_qdtoa(double d, int mode, int ndigits, int *decpt, +                        int *sign, char **rve, char **digits_str); +static double qstrtod(const char *s00, char const **se, bool *ok); +#endif +static TQ_LLONG qstrtoll(const char *nptr, const char **endptr, register int base, bool *ok); +static TQ_ULLONG qstrtoull(const char *nptr, const char **endptr, register int base, bool *ok); + +static inline bool compareBits(double d1, double d2) +{ +    return memcmp((const char*)&d1, (const char*)&d2, sizeof(double)) == 0; +} + +static inline bool qIsInf(double d) +{ +    return compareBits(d, INFINITY) || compareBits(d, -INFINITY); +} + +static inline bool qIsNan(double d) +{ +    return compareBits(d, NAN) || compareBits(d, negNan()); +} + +static const uint locale_index[] = { +     0, // unused +     0, // C +     0, // Abkhazian +     0, // Afan +     0, // Afar +     1, // Afrikaans +     2, // Albanian +     0, // Amharic +     3, // Arabic +    19, // Armenian +     0, // Assamese +     0, // Aymara +    20, // Azerbaijani +     0, // Bashkir +    21, // Basque +    22, // Bengali +     0, // Bhutani +     0, // Bihari +     0, // Bislama +     0, // Breton +    23, // Bulgarian +     0, // Burmese +    24, // Byelorussian +     0, // Cambodian +    25, // Catalan +    26, // Chinese +     0, // Corsican +    31, // Croatian +    32, // Czech +    33, // Danish +    34, // Dutch +    36, // English +     0, // Esperanto +    48, // Estonian +    49, // Faroese +     0, // Fiji +    50, // Finnish +    51, // French +     0, // Frisian +     0, // Gaelic +    57, // Galician +    58, // Georgian +    59, // German +    64, // Greek +     0, // Greenlandic +     0, // Guarani +    65, // Gujarati +     0, // Hausa +    66, // Hebrew +    67, // Hindi +    68, // Hungarian +    69, // Icelandic +    70, // Indonesian +     0, // Interlingua +     0, // Interlingue +     0, // Inuktitut +     0, // Inupiak +     0, // Irish +    71, // Italian +    73, // Japanese +     0, // Javanese +    74, // Kannada +     0, // Kashmiri +    75, // Kazakh +     0, // Kinyarwanda +    76, // Kirghiz +    77, // Korean +     0, // Kurdish +     0, // Kurundi +     0, // Laothian +     0, // Latin +    78, // Latvian +     0, // Lingala +    79, // Lithuanian +    80, // Macedonian +     0, // Malagasy +    81, // Malay +     0, // Malayalam +     0, // Maltese +     0, // Maori +    83, // Marathi +     0, // Moldavian +    84, // Mongolian +     0, // Nauru +     0, // Nepali +    85, // Norwegian +     0, // Occitan +     0, // Oriya +     0, // Pashto +    86, // Persian +    87, // Polish +    88, // Portuguese +    90, // Punjabi +     0, // Quechua +     0, // RhaetoRomance +    91, // Romanian +    92, // Russian +     0, // Samoan +     0, // Sangho +    93, // Sanskrit +     0, // Serbian +     0, // SerboCroatian +     0, // Sesotho +     0, // Setswana +     0, // Shona +     0, // Sindhi +     0, // Singhalese +     0, // Siswati +    94, // Slovak +    95, // Slovenian +     0, // Somali +    96, // Spanish +     0, // Sundanese +   115, // Swahili +   116, // Swedish +     0, // Tagalog +     0, // Tajik +   118, // Tamil +     0, // Tatar +   119, // Telugu +   120, // Thai +     0, // Tibetan +     0, // Tigrinya +     0, // Tonga +     0, // Tsonga +   121, // Turkish +     0, // Turkmen +     0, // Twi +     0, // Uigur +   122, // Ukrainian +   123, // Urdu +   124, // Uzbek +   125, // Vietnamese +     0, // Volapuk +     0, // Welsh +     0, // Wolof +     0, // Xhosa +     0, // Yiddish +     0, // Yoruba +     0, // Zhuang +     0, // Zulu +     0  // trailing 0 +}; + +static const TQLocalePrivate locale_data[] = { +//      lang   terr    dec  group   list  prcnt   zero  minus    exp +    {      1,     0,    46,    44,    59,    37,    48,    45,   101 }, // C/AnyCountry +    {      5,   195,    46,    44,    44,    37,    48,    45,    101 }, // Afrikaans/SouthAfrica +    {      6,     2,    44,    46,    59,    37,    48,    45,    101 }, // Albanian/Albania +    {      8,   186,    46,    44,    59,    37,  1632,    45,    101 }, // Arabic/SaudiArabia +    {      8,     3,    46,    44,    59,    37,    48,    45,    101 }, // Arabic/Algeria +    {      8,    17,    46,    44,    59,    37,  1632,    45,    101 }, // Arabic/Bahrain +    {      8,    64,    46,    44,    59,    37,  1632,    45,    101 }, // Arabic/Egypt +    {      8,   103,    46,    44,    59,    37,  1632,    45,    101 }, // Arabic/Iraq +    {      8,   109,    46,    44,    59,    37,  1632,    45,    101 }, // Arabic/Jordan +    {      8,   115,    46,    44,    59,    37,  1632,    45,    101 }, // Arabic/Kuwait +    {      8,   119,    46,    44,    59,    37,  1632,    45,    101 }, // Arabic/Lebanon +    {      8,   122,    46,    44,    59,    37,    48,    45,    101 }, // Arabic/LibyanArabJamahiriya +    {      8,   145,    46,    44,    59,    37,    48,    45,    101 }, // Arabic/Morocco +    {      8,   162,    46,    44,    59,    37,  1632,    45,    101 }, // Arabic/Oman +    {      8,   175,    46,    44,    59,    37,  1632,    45,    101 }, // Arabic/Qatar +    {      8,   207,    46,    44,    59,    37,  1632,    45,    101 }, // Arabic/SyrianArabRepublic +    {      8,   216,    46,    44,    59,    37,    48,    45,    101 }, // Arabic/Tunisia +    {      8,   223,    46,    44,    59,    37,  1632,    45,    101 }, // Arabic/UnitedArabEmirates +    {      8,   237,    46,    44,    59,    37,  1632,    45,    101 }, // Arabic/Yemen +    {      9,    11,    46,    44,    44,    37,    48,    45,    101 }, // Armenian/Armenia +    {     12,    15,    44,   160,    59,    37,    48,    45,    101 }, // Azerbaijani/Azerbaijan +    {     14,   197,    44,    46,    59,    37,    48,    45,    101 }, // Basque/Spain +    {     15,   100,    46,    44,    59,    37,    48,    45,    101 }, // Bengali/India +    {     20,    33,    44,   160,    59,    37,    48,    45,    101 }, // Bulgarian/Bulgaria +    {     22,    20,    44,   160,    59,    37,    48,    45,    101 }, // Byelorussian/Belarus +    {     24,   197,    44,    46,    59,    37,    48,    45,    101 }, // Catalan/Spain +    {     25,    44,    46,    44,    44,    37,    48,    45,    101 }, // Chinese/China +    {     25,    97,    46,    44,    44,    37,    48,    45,    101 }, // Chinese/HongKong +    {     25,   126,    46,    44,    44,    37,    48,    45,    101 }, // Chinese/Macau +    {     25,   190,    46,    44,    44,    37,    48,    45,    101 }, // Chinese/Singapore +    {     25,   208,    46,    44,    44,    37,    48,    45,    101 }, // Chinese/Taiwan +    {     27,    54,    44,    46,    59,    37,    48,    45,    101 }, // Croatian/Croatia +    {     28,    57,    44,   160,    59,    37,    48,    45,    101 }, // Czech/CzechRepublic +    {     29,    58,    44,    46,    59,    37,    48,    45,    101 }, // Danish/Denmark +    {     30,   151,    44,    46,    59,    37,    48,    45,    101 }, // Dutch/Netherlands +    {     30,    21,    44,    46,    59,    37,    48,    45,    101 }, // Dutch/Belgium +    {     31,   225,    46,    44,    44,    37,    48,    45,    101 }, // English/UnitedStates +    {     31,    13,    46,    44,    44,    37,    48,    45,    101 }, // English/Australia +    {     31,    22,    46,    44,    59,    37,    48,    45,    101 }, // English/Belize +    {     31,    38,    46,    44,    44,    37,    48,    45,    101 }, // English/Canada +    {     31,   104,    46,    44,    44,    37,    48,    45,    101 }, // English/Ireland +    {     31,   107,    46,    44,    44,    37,    48,    45,    101 }, // English/Jamaica +    {     31,   154,    46,    44,    44,    37,    48,    45,    101 }, // English/NewZealand +    {     31,   170,    46,    44,    44,    37,    48,    45,    101 }, // English/Philippines +    {     31,   195,    46,    44,    44,    37,    48,    45,    101 }, // English/SouthAfrica +    {     31,   215,    46,    44,    59,    37,    48,    45,    101 }, // English/TrinidadAndTobago +    {     31,   224,    46,    44,    44,    37,    48,    45,    101 }, // English/UnitedKingdom +    {     31,   240,    46,    44,    44,    37,    48,    45,    101 }, // English/Zimbabwe +    {     33,    68,    44,   160,    59,    37,    48,    45,    101 }, // Estonian/Estonia +    {     34,    71,    44,    46,    59,    37,    48,    45,    101 }, // Faroese/FaroeIslands +    {     36,    73,    44,   160,    59,    37,    48,    45,    101 }, // Finnish/Finland +    {     37,    74,    44,   160,    59,    37,    48,    45,    101 }, // French/France +    {     37,    21,    44,    46,    59,    37,    48,    45,    101 }, // French/Belgium +    {     37,    38,    44,   160,    59,    37,    48,    45,    101 }, // French/Canada +    {     37,   125,    44,   160,    59,    37,    48,    45,    101 }, // French/Luxembourg +    {     37,   142,    44,   160,    59,    37,    48,    45,    101 }, // French/Monaco +    {     37,   206,    46,    39,    59,    37,    48,    45,    101 }, // French/Switzerland +    {     40,   197,    44,    46,    44,    37,    48,    45,    101 }, // Galician/Spain +    {     41,    81,    44,   160,    59,    37,    48,    45,    101 }, // Georgian/Georgia +    {     42,    82,    44,    46,    59,    37,    48,    45,    101 }, // German/Germany +    {     42,    14,    44,    46,    59,    37,    48,    45,    101 }, // German/Austria +    {     42,   123,    46,    39,    59,    37,    48,    45,    101 }, // German/Liechtenstein +    {     42,   125,    44,    46,    59,    37,    48,    45,    101 }, // German/Luxembourg +    {     42,   206,    46,    39,    59,    37,    48,    45,    101 }, // German/Switzerland +    {     43,    85,    44,    46,    59,    37,    48,    45,    101 }, // Greek/Greece +    {     46,   100,    46,    44,    44,    37,  2790,    45,    101 }, // Gujarati/India +    {     48,   105,    46,    44,    44,    37,    48,    45,    101 }, // Hebrew/Israel +    {     49,   100,    46,    44,    44,    37,    48,    45,    101 }, // Hindi/India +    {     50,    98,    44,   160,    59,    37,    48,    45,    101 }, // Hungarian/Hungary +    {     51,    99,    44,    46,    59,    37,    48,    45,    101 }, // Icelandic/Iceland +    {     52,   101,    44,    46,    59,    37,    48,    45,    101 }, // Indonesian/Indonesia +    {     58,   106,    44,    46,    59,    37,    48,    45,    101 }, // Italian/Italy +    {     58,   206,    46,    39,    59,    37,    48,    45,    101 }, // Italian/Switzerland +    {     59,   108,    46,    44,    44,    37,    48,    45,    101 }, // Japanese/Japan +    {     61,   100,    46,    44,    44,    37,  3302,    45,    101 }, // Kannada/India +    {     63,   110,    44,   160,    59,    37,    48,    45,    101 }, // Kazakh/Kazakhstan +    {     65,   116,    44,   160,    59,    37,    48,    45,    101 }, // Kirghiz/Kyrgyzstan +    {     66,   114,    46,    44,    44,    37,    48,    45,    101 }, // Korean/RepublicOfKorea +    {     71,   118,    44,   160,    59,    37,    48,    45,    101 }, // Latvian/Latvia +    {     73,   124,    44,    46,    59,    37,    48,    45,    101 }, // Lithuanian/Lithuania +    {     74,   127,    44,    46,    59,    37,    48,    45,    101 }, // Macedonian/Macedonia +    {     76,   130,    44,    46,    59,    37,    48,    45,    101 }, // Malay/Malaysia +    {     76,    32,    44,    46,    59,    37,    48,    45,    101 }, // Malay/BruneiDarussalam +    {     80,   100,    46,    44,    44,    37,  2406,    45,    101 }, // Marathi/India +    {     82,   143,    44,   160,    59,    37,    48,    45,    101 }, // Mongolian/Mongolia +    {     85,   161,    44,   160,    59,    37,    48,    45,    101 }, // Norwegian/Norway +    {     89,   102,    46,    44,    59,    37,  1776,    45,    101 }, // Persian/Iran +    {     90,   172,    44,   160,    59,    37,    48,    45,    101 }, // Polish/Poland +    {     91,   173,    44,    46,    59,    37,    48,    45,    101 }, // Portuguese/Portugal +    {     91,    30,    44,    46,    59,    37,    48,    45,    101 }, // Portuguese/Brazil +    {     92,   100,    46,    44,    44,    37,  2662,    45,    101 }, // Punjabi/India +    {     95,   177,    44,    46,    59,    37,    48,    45,    101 }, // Romanian/Romania +    {     96,   178,    44,   160,    59,    37,    48,    45,    101 }, // Russian/RussianFederation +    {     99,   100,    46,    44,    44,    37,  2406,    45,    101 }, // Sanskrit/India +    {    108,   191,    44,   160,    59,    37,    48,    45,    101 }, // Slovak/Slovakia +    {    109,   192,    44,    46,    59,    37,    48,    45,    101 }, // Slovenian/Slovenia +    {    111,   197,    44,    46,    59,    37,    48,    45,    101 }, // Spanish/Spain +    {    111,    10,    44,    46,    44,    37,    48,    45,    101 }, // Spanish/Argentina +    {    111,    26,    44,    46,    44,    37,    48,    45,    101 }, // Spanish/Bolivia +    {    111,    43,    44,    46,    44,    37,    48,    45,    101 }, // Spanish/Chile +    {    111,    47,    44,    46,    44,    37,    48,    45,    101 }, // Spanish/Colombia +    {    111,    52,    44,    46,    44,    37,    48,    45,    101 }, // Spanish/CostaRica +    {    111,    61,    46,    44,    44,    37,    48,    45,    101 }, // Spanish/DominicanRepublic +    {    111,    63,    44,    46,    44,    37,    48,    45,    101 }, // Spanish/Ecuador +    {    111,    65,    46,    44,    44,    37,    48,    45,    101 }, // Spanish/ElSalvador +    {    111,    90,    46,    44,    44,    37,    48,    45,    101 }, // Spanish/Guatemala +    {    111,    96,    46,    44,    44,    37,    48,    45,    101 }, // Spanish/Honduras +    {    111,   139,    46,    44,    44,    37,    48,    45,    101 }, // Spanish/Mexico +    {    111,   155,    46,    44,    44,    37,    48,    45,    101 }, // Spanish/Nicaragua +    {    111,   166,    46,    44,    44,    37,    48,    45,    101 }, // Spanish/Panama +    {    111,   168,    44,    46,    44,    37,    48,    45,    101 }, // Spanish/Paraguay +    {    111,   169,    46,    44,    44,    37,    48,    45,    101 }, // Spanish/Peru +    {    111,   174,    46,    44,    44,    37,    48,    45,    101 }, // Spanish/PuertoRico +    {    111,   227,    44,    46,    44,    37,    48,    45,    101 }, // Spanish/Uruguay +    {    111,   231,    44,    46,    44,    37,    48,    45,    101 }, // Spanish/Venezuela +    {    113,   111,    46,    44,    44,    37,    48,    45,    101 }, // Swahili/Kenya +    {    114,   205,    44,   160,    59,    37,    48,    45,    101 }, // Swedish/Sweden +    {    114,    73,    44,   160,    59,    37,    48,    45,    101 }, // Swedish/Finland +    {    117,   100,    46,    44,    44,    37,    48,    45,    101 }, // Tamil/India +    {    119,   100,    46,    44,    44,    37,  3174,    45,    101 }, // Telugu/India +    {    120,   211,    46,    44,    44,    37,  3664,    45,    101 }, // Thai/Thailand +    {    125,   217,    44,    46,    59,    37,    48,    45,    101 }, // Turkish/Turkey +    {    129,   222,    44,   160,    59,    37,    48,    45,    101 }, // Ukrainian/Ukraine +    {    130,   163,    46,    44,    59,    37,  1776,    45,    101 }, // Urdu/Pakistan +    {    131,   228,    44,   160,    59,    37,    48,    45,    101 }, // Uzbek/Uzbekistan +    {    132,   232,    44,    46,    44,    37,    48,    45,    101 }, // Vietnamese/VietNam +    {      0,     0,     0,     0,     0,     0,     0,     0,     0 }  // trailing 0s +}; + +static const char language_name_list[] = +"Default\0" +"C\0" +"Abkhazian\0" +"Afan\0" +"Afar\0" +"Afrikaans\0" +"Albanian\0" +"Amharic\0" +"Arabic\0" +"Armenian\0" +"Assamese\0" +"Aymara\0" +"Azerbaijani\0" +"Bashkir\0" +"Basque\0" +"Bengali\0" +"Bhutani\0" +"Bihari\0" +"Bislama\0" +"Breton\0" +"Bulgarian\0" +"Burmese\0" +"Byelorussian\0" +"Cambodian\0" +"Catalan\0" +"Chinese\0" +"Corsican\0" +"Croatian\0" +"Czech\0" +"Danish\0" +"Dutch\0" +"English\0" +"Esperanto\0" +"Estonian\0" +"Faroese\0" +"Fiji\0" +"Finnish\0" +"French\0" +"Frisian\0" +"Gaelic\0" +"Galician\0" +"Georgian\0" +"German\0" +"Greek\0" +"Greenlandic\0" +"Guarani\0" +"Gujarati\0" +"Hausa\0" +"Hebrew\0" +"Hindi\0" +"Hungarian\0" +"Icelandic\0" +"Indonesian\0" +"Interlingua\0" +"Interlingue\0" +"Inuktitut\0" +"Inupiak\0" +"Irish\0" +"Italian\0" +"Japanese\0" +"Javanese\0" +"Kannada\0" +"Kashmiri\0" +"Kazakh\0" +"Kinyarwanda\0" +"Kirghiz\0" +"Korean\0" +"Kurdish\0" +"Kurundi\0" +"Laothian\0" +"Latin\0" +"Latvian\0" +"Lingala\0" +"Lithuanian\0" +"Macedonian\0" +"Malagasy\0" +"Malay\0" +"Malayalam\0" +"Maltese\0" +"Maori\0" +"Marathi\0" +"Moldavian\0" +"Mongolian\0" +"Nauru\0" +"Nepali\0" +"Norwegian\0" +"Occitan\0" +"Oriya\0" +"Pashto\0" +"Persian\0" +"Polish\0" +"Portuguese\0" +"Punjabi\0" +"Quechua\0" +"RhaetoRomance\0" +"Romanian\0" +"Russian\0" +"Samoan\0" +"Sangho\0" +"Sanskrit\0" +"Serbian\0" +"SerboCroatian\0" +"Sesotho\0" +"Setswana\0" +"Shona\0" +"Sindhi\0" +"Singhalese\0" +"Siswati\0" +"Slovak\0" +"Slovenian\0" +"Somali\0" +"Spanish\0" +"Sundanese\0" +"Swahili\0" +"Swedish\0" +"Tagalog\0" +"Tajik\0" +"Tamil\0" +"Tatar\0" +"Telugu\0" +"Thai\0" +"Tibetan\0" +"Tigrinya\0" +"Tonga\0" +"Tsonga\0" +"Turkish\0" +"Turkmen\0" +"Twi\0" +"Uigur\0" +"Ukrainian\0" +"Urdu\0" +"Uzbek\0" +"Vietnamese\0" +"Volapuk\0" +"Welsh\0" +"Wolof\0" +"Xhosa\0" +"Yiddish\0" +"Yoruba\0" +"Zhuang\0" +"Zulu\0"; + +static const uint language_name_index[] = { +     0,// Unused +     8,// C +    10,// Abkhazian +    20,// Afan +    25,// Afar +    30,// Afrikaans +    40,// Albanian +    49,// Amharic +    57,// Arabic +    64,// Armenian +    73,// Assamese +    82,// Aymara +    89,// Azerbaijani +   101,// Bashkir +   109,// Basque +   116,// Bengali +   124,// Bhutani +   132,// Bihari +   139,// Bislama +   147,// Breton +   154,// Bulgarian +   164,// Burmese +   172,// Byelorussian +   185,// Cambodian +   195,// Catalan +   203,// Chinese +   211,// Corsican +   220,// Croatian +   229,// Czech +   235,// Danish +   242,// Dutch +   248,// English +   256,// Esperanto +   266,// Estonian +   275,// Faroese +   283,// Fiji +   288,// Finnish +   296,// French +   303,// Frisian +   311,// Gaelic +   318,// Galician +   327,// Georgian +   336,// German +   343,// Greek +   349,// Greenlandic +   361,// Guarani +   369,// Gujarati +   378,// Hausa +   384,// Hebrew +   391,// Hindi +   397,// Hungarian +   407,// Icelandic +   417,// Indonesian +   428,// Interlingua +   440,// Interlingue +   452,// Inuktitut +   462,// Inupiak +   470,// Irish +   476,// Italian +   484,// Japanese +   493,// Javanese +   502,// Kannada +   510,// Kashmiri +   519,// Kazakh +   526,// Kinyarwanda +   538,// Kirghiz +   546,// Korean +   553,// Kurdish +   561,// Kurundi +   569,// Laothian +   578,// Latin +   584,// Latvian +   592,// Lingala +   600,// Lithuanian +   611,// Macedonian +   622,// Malagasy +   631,// Malay +   637,// Malayalam +   647,// Maltese +   655,// Maori +   661,// Marathi +   669,// Moldavian +   679,// Mongolian +   689,// Nauru +   695,// Nepali +   702,// Norwegian +   712,// Occitan +   720,// Oriya +   726,// Pashto +   733,// Persian +   741,// Polish +   748,// Portuguese +   759,// Punjabi +   767,// Quechua +   775,// RhaetoRomance +   789,// Romanian +   798,// Russian +   806,// Samoan +   813,// Sangho +   820,// Sanskrit +   829,// Serbian +   837,// SerboCroatian +   851,// Sesotho +   859,// Setswana +   868,// Shona +   874,// Sindhi +   881,// Singhalese +   892,// Siswati +   900,// Slovak +   907,// Slovenian +   917,// Somali +   924,// Spanish +   932,// Sundanese +   942,// Swahili +   950,// Swedish +   958,// Tagalog +   966,// Tajik +   972,// Tamil +   978,// Tatar +   984,// Telugu +   991,// Thai +   996,// Tibetan +  1004,// Tigrinya +  1013,// Tonga +  1019,// Tsonga +  1026,// Turkish +  1034,// Turkmen +  1042,// Twi +  1046,// Uigur +  1052,// Ukrainian +  1062,// Urdu +  1067,// Uzbek +  1073,// Vietnamese +  1084,// Volapuk +  1092,// Welsh +  1098,// Wolof +  1104,// Xhosa +  1110,// Yiddish +  1118,// Yoruba +  1125,// Zhuang +  1132// Zulu +}; + +static const char country_name_list[] = +"Default\0" +"Afghanistan\0" +"Albania\0" +"Algeria\0" +"AmericanSamoa\0" +"Andorra\0" +"Angola\0" +"Anguilla\0" +"Antarctica\0" +"AntiguaAndBarbuda\0" +"Argentina\0" +"Armenia\0" +"Aruba\0" +"Australia\0" +"Austria\0" +"Azerbaijan\0" +"Bahamas\0" +"Bahrain\0" +"Bangladesh\0" +"Barbados\0" +"Belarus\0" +"Belgium\0" +"Belize\0" +"Benin\0" +"Bermuda\0" +"Bhutan\0" +"Bolivia\0" +"BosniaAndHerzegowina\0" +"Botswana\0" +"BouvetIsland\0" +"Brazil\0" +"BritishIndianOceanTerritory\0" +"BruneiDarussalam\0" +"Bulgaria\0" +"BurkinaFaso\0" +"Burundi\0" +"Cambodia\0" +"Cameroon\0" +"Canada\0" +"CapeVerde\0" +"CaymanIslands\0" +"CentralAfricanRepublic\0" +"Chad\0" +"Chile\0" +"China\0" +"ChristmasIsland\0" +"CocosIslands\0" +"Colombia\0" +"Comoros\0" +"DetqmocraticRepublicOfCongo\0" +"PeoplesRepublicOfCongo\0" +"CookIslands\0" +"CostaRica\0" +"IvoryCoast\0" +"Croatia\0" +"Cuba\0" +"Cyprus\0" +"CzechRepublic\0" +"Denmark\0" +"Djibouti\0" +"Dominica\0" +"DominicanRepublic\0" +"EastTimor\0" +"Ecuador\0" +"Egypt\0" +"ElSalvador\0" +"EquatorialGuinea\0" +"Eritrea\0" +"Estonia\0" +"Ethiopia\0" +"FalklandIslands\0" +"FaroeIslands\0" +"Fiji\0" +"Finland\0" +"France\0" +"MetropolitanFrance\0" +"FrenchGuiana\0" +"FrenchPolynesia\0" +"FrenchSouthernTerritories\0" +"Gabon\0" +"Gambia\0" +"Georgia\0" +"Germany\0" +"Ghana\0" +"Gibraltar\0" +"Greece\0" +"Greenland\0" +"Grenada\0" +"Guadeloupe\0" +"Guam\0" +"Guatemala\0" +"Guinea\0" +"GuineaBissau\0" +"Guyana\0" +"Haiti\0" +"HeardAndMcDonaldIslands\0" +"Honduras\0" +"HongKong\0" +"Hungary\0" +"Iceland\0" +"India\0" +"Indonesia\0" +"Iran\0" +"Iraq\0" +"Ireland\0" +"Israel\0" +"Italy\0" +"Jamaica\0" +"Japan\0" +"Jordan\0" +"Kazakhstan\0" +"Kenya\0" +"Kiribati\0" +"DetqmocraticRepublicOfKorea\0" +"RepublicOfKorea\0" +"Kuwait\0" +"Kyrgyzstan\0" +"Lao\0" +"Latvia\0" +"Lebanon\0" +"Lesotho\0" +"Liberia\0" +"LibyanArabJamahiriya\0" +"Liechtenstein\0" +"Lithuania\0" +"Luxembourg\0" +"Macau\0" +"Macedonia\0" +"Madagascar\0" +"Malawi\0" +"Malaysia\0" +"Maldives\0" +"Mali\0" +"Malta\0" +"MarshallIslands\0" +"Martinique\0" +"Mauritania\0" +"Mauritius\0" +"Mayotte\0" +"Mexico\0" +"Micronesia\0" +"Moldova\0" +"Monaco\0" +"Mongolia\0" +"Montserrat\0" +"Morocco\0" +"Mozambique\0" +"Myanmar\0" +"Namibia\0" +"Nauru\0" +"Nepal\0" +"Netherlands\0" +"NetherlandsAntilles\0" +"NewCaledonia\0" +"NewZealand\0" +"Nicaragua\0" +"Niger\0" +"Nigeria\0" +"Niue\0" +"NorfolkIsland\0" +"NorthernMarianaIslands\0" +"Norway\0" +"Oman\0" +"Pakistan\0" +"Palau\0" +"PalestinianTerritory\0" +"Panama\0" +"PapuaNewGuinea\0" +"Paraguay\0" +"Peru\0" +"Philippines\0" +"Pitcairn\0" +"Poland\0" +"Portugal\0" +"PuertoRico\0" +"Qatar\0" +"Reunion\0" +"Romania\0" +"RussianFederation\0" +"Rwanda\0" +"SaintKittsAndNevis\0" +"StLucia\0" +"StVincentAndTheGrenadines\0" +"Samoa\0" +"SanMarino\0" +"SaoTomeAndPrincipe\0" +"SaudiArabia\0" +"Senegal\0" +"Seychelles\0" +"SierraLeone\0" +"Singapore\0" +"Slovakia\0" +"Slovenia\0" +"SolomonIslands\0" +"Somalia\0" +"SouthAfrica\0" +"SouthGeorgiaAndTheSouthSandwichIslands\0" +"Spain\0" +"SriLanka\0" +"StHelena\0" +"StPierreAndMiquelon\0" +"Sudan\0" +"Suriname\0" +"SvalbardAndJanMayenIslands\0" +"Swaziland\0" +"Sweden\0" +"Switzerland\0" +"SyrianArabRepublic\0" +"Taiwan\0" +"Tajikistan\0" +"Tanzania\0" +"Thailand\0" +"Togo\0" +"Tokelau\0" +"Tonga\0" +"TrinidadAndTobago\0" +"Tunisia\0" +"Turkey\0" +"Turkmenistan\0" +"TurksAndCaicosIslands\0" +"Tuvalu\0" +"Uganda\0" +"Ukraine\0" +"UnitedArabEmirates\0" +"UnitedKingdom\0" +"UnitedStates\0" +"UnitedStatesMinorOutlyingIslands\0" +"Uruguay\0" +"Uzbekistan\0" +"Vanuatu\0" +"VaticanCityState\0" +"Venezuela\0" +"VietNam\0" +"BritishVirginIslands\0" +"USVirginIslands\0" +"WallisAndFutunaIslands\0" +"WesternSahara\0" +"Yemen\0" +"Yugoslavia\0" +"Zambia\0" +"Zimbabwe\0"; + +static const uint country_name_index[] = { +     0,// AnyCountry +     8,// Afghanistan +    20,// Albania +    28,// Algeria +    36,// AmericanSamoa +    50,// Andorra +    58,// Angola +    65,// Anguilla +    74,// Antarctica +    85,// AntiguaAndBarbuda +   103,// Argentina +   113,// Armenia +   121,// Aruba +   127,// Australia +   137,// Austria +   145,// Azerbaijan +   156,// Bahamas +   164,// Bahrain +   172,// Bangladesh +   183,// Barbados +   192,// Belarus +   200,// Belgium +   208,// Belize +   215,// Benin +   221,// Bermuda +   229,// Bhutan +   236,// Bolivia +   244,// BosniaAndHerzegowina +   265,// Botswana +   274,// BouvetIsland +   287,// Brazil +   294,// BritishIndianOceanTerritory +   322,// BruneiDarussalam +   339,// Bulgaria +   348,// BurkinaFaso +   360,// Burundi +   368,// Cambodia +   377,// Cameroon +   386,// Canada +   393,// CapeVerde +   403,// CaymanIslands +   417,// CentralAfricanRepublic +   440,// Chad +   445,// Chile +   451,// China +   457,// ChristmasIsland +   473,// CocosIslands +   486,// Colombia +   495,// Comoros +   503,// DetqmocraticRepublicOfCongo +   529,// PeoplesRepublicOfCongo +   552,// CookIslands +   564,// CostaRica +   574,// IvoryCoast +   585,// Croatia +   593,// Cuba +   598,// Cyprus +   605,// CzechRepublic +   619,// Denmark +   627,// Djibouti +   636,// Dominica +   645,// DominicanRepublic +   663,// EastTimor +   673,// Ecuador +   681,// Egypt +   687,// ElSalvador +   698,// EquatorialGuinea +   715,// Eritrea +   723,// Estonia +   731,// Ethiopia +   740,// FalklandIslands +   756,// FaroeIslands +   769,// Fiji +   774,// Finland +   782,// France +   789,// MetropolitanFrance +   808,// FrenchGuiana +   821,// FrenchPolynesia +   837,// FrenchSouthernTerritories +   863,// Gabon +   869,// Gambia +   876,// Georgia +   884,// Germany +   892,// Ghana +   898,// Gibraltar +   908,// Greece +   915,// Greenland +   925,// Grenada +   933,// Guadeloupe +   944,// Guam +   949,// Guatemala +   959,// Guinea +   966,// GuineaBissau +   979,// Guyana +   986,// Haiti +   992,// HeardAndMcDonaldIslands +  1016,// Honduras +  1025,// HongKong +  1034,// Hungary +  1042,// Iceland +  1050,// India +  1056,// Indonesia +  1066,// Iran +  1071,// Iraq +  1076,// Ireland +  1084,// Israel +  1091,// Italy +  1097,// Jamaica +  1105,// Japan +  1111,// Jordan +  1118,// Kazakhstan +  1129,// Kenya +  1135,// Kiribati +  1144,// DetqmocraticRepublicOfKorea +  1170,// RepublicOfKorea +  1186,// Kuwait +  1193,// Kyrgyzstan +  1204,// Lao +  1208,// Latvia +  1215,// Lebanon +  1223,// Lesotho +  1231,// Liberia +  1239,// LibyanArabJamahiriya +  1260,// Liechtenstein +  1274,// Lithuania +  1284,// Luxembourg +  1295,// Macau +  1301,// Macedonia +  1311,// Madagascar +  1322,// Malawi +  1329,// Malaysia +  1338,// Maldives +  1347,// Mali +  1352,// Malta +  1358,// MarshallIslands +  1374,// Martinique +  1385,// Mauritania +  1396,// Mauritius +  1406,// Mayotte +  1414,// Mexico +  1421,// Micronesia +  1432,// Moldova +  1440,// Monaco +  1447,// Mongolia +  1456,// Montserrat +  1467,// Morocco +  1475,// Mozambique +  1486,// Myanmar +  1494,// Namibia +  1502,// Nauru +  1508,// Nepal +  1514,// Netherlands +  1526,// NetherlandsAntilles +  1546,// NewCaledonia +  1559,// NewZealand +  1570,// Nicaragua +  1580,// Niger +  1586,// Nigeria +  1594,// Niue +  1599,// NorfolkIsland +  1613,// NorthernMarianaIslands +  1636,// Norway +  1643,// Oman +  1648,// Pakistan +  1657,// Palau +  1663,// PalestinianTerritory +  1684,// Panama +  1691,// PapuaNewGuinea +  1706,// Paraguay +  1715,// Peru +  1720,// Philippines +  1732,// Pitcairn +  1741,// Poland +  1748,// Portugal +  1757,// PuertoRico +  1768,// Qatar +  1774,// Reunion +  1782,// Romania +  1790,// RussianFederation +  1808,// Rwanda +  1815,// SaintKittsAndNevis +  1834,// StLucia +  1842,// StVincentAndTheGrenadines +  1868,// Samoa +  1874,// SanMarino +  1884,// SaoTomeAndPrincipe +  1903,// SaudiArabia +  1915,// Senegal +  1923,// Seychelles +  1934,// SierraLeone +  1946,// Singapore +  1956,// Slovakia +  1965,// Slovenia +  1974,// SolomonIslands +  1989,// Somalia +  1997,// SouthAfrica +  2009,// SouthGeorgiaAndTheSouthSandwichIslands +  2048,// Spain +  2054,// SriLanka +  2063,// StHelena +  2072,// StPierreAndMiquelon +  2092,// Sudan +  2098,// Suriname +  2107,// SvalbardAndJanMayenIslands +  2134,// Swaziland +  2144,// Sweden +  2151,// Switzerland +  2163,// SyrianArabRepublic +  2182,// Taiwan +  2189,// Tajikistan +  2200,// Tanzania +  2209,// Thailand +  2218,// Togo +  2223,// Tokelau +  2231,// Tonga +  2237,// TrinidadAndTobago +  2255,// Tunisia +  2263,// Turkey +  2270,// Turkmenistan +  2283,// TurksAndCaicosIslands +  2305,// Tuvalu +  2312,// Uganda +  2319,// Ukraine +  2327,// UnitedArabEmirates +  2346,// UnitedKingdom +  2360,// UnitedStates +  2373,// UnitedStatesMinorOutlyingIslands +  2406,// Uruguay +  2414,// Uzbekistan +  2425,// Vanuatu +  2433,// VaticanCityState +  2450,// Venezuela +  2460,// VietNam +  2468,// BritishVirginIslands +  2489,// USVirginIslands +  2505,// WallisAndFutunaIslands +  2528,// WesternSahara +  2542,// Yemen +  2548,// Yugoslavia +  2559,// Zambia +  2566// Zimbabwe +}; + +static const char language_code_list[] = +"  " // Unused +"  " // C +"ab" // Abkhazian +"om" // Afan +"aa" // Afar +"af" // Afrikaans +"sq" // Albanian +"am" // Amharic +"ar" // Arabic +"hy" // Armenian +"as" // Assamese +"ay" // Aymara +"az" // Azerbaijani +"ba" // Bashkir +"eu" // Basque +"bn" // Bengali +"dz" // Bhutani +"bh" // Bihari +"bi" // Bislama +"br" // Breton +"bg" // Bulgarian +"my" // Burmese +"be" // Byelorussian +"km" // Cambodian +"ca" // Catalan +"zh" // Chinese +"co" // Corsican +"hr" // Croatian +"cs" // Czech +"da" // Danish +"nl" // Dutch +"en" // English +"eo" // Esperanto +"et" // Estonian +"fo" // Faroese +"fj" // Fiji +"fi" // Finnish +"fr" // French +"fy" // Frisian +"gd" // Gaelic +"gl" // Galician +"ka" // Georgian +"de" // German +"el" // Greek +"kl" // Greenlandic +"gn" // Guarani +"gu" // Gujarati +"ha" // Hausa +"he" // Hebrew +"hi" // Hindi +"hu" // Hungarian +"is" // Icelandic +"id" // Indonesian +"ia" // Interlingua +"ie" // Interlingue +"iu" // Inuktitut +"ik" // Inupiak +"ga" // Irish +"it" // Italian +"ja" // Japanese +"jv" // Javanese +"kn" // Kannada +"ks" // Kashmiri +"kk" // Kazakh +"rw" // Kinyarwanda +"ky" // Kirghiz +"ko" // Korean +"ku" // Kurdish +"rn" // Kurundi +"lo" // Laothian +"la" // Latin +"lv" // Latvian +"ln" // Lingala +"lt" // Lithuanian +"mk" // Macedonian +"mg" // Malagasy +"ms" // Malay +"ml" // Malayalam +"mt" // Maltese +"mi" // Maori +"mr" // Marathi +"mo" // Moldavian +"mn" // Mongolian +"na" // Nauru +"ne" // Nepali +"no" // Norwegian +"oc" // Occitan +"or" // Oriya +"ps" // Pashto +"fa" // Persian +"pl" // Polish +"pt" // Portuguese +"pa" // Punjabi +"qu" // Quechua +"rm" // RhaetoRomance +"ro" // Romanian +"ru" // Russian +"sm" // Samoan +"sg" // Sangho +"sa" // Sanskrit +"sr" // Serbian +"sh" // SerboCroatian +"st" // Sesotho +"tn" // Setswana +"sn" // Shona +"sd" // Sindhi +"si" // Singhalese +"ss" // Siswati +"sk" // Slovak +"sl" // Slovenian +"so" // Somali +"es" // Spanish +"su" // Sundanese +"sw" // Swahili +"sv" // Swedish +"tl" // Tagalog +"tg" // Tajik +"ta" // Tamil +"tt" // Tatar +"te" // Telugu +"th" // Thai +"bo" // Tibetan +"ti" // Tigrinya +"to" // Tonga +"ts" // Tsonga +"tr" // Turkish +"tk" // Turkmen +"tw" // Twi +"ug" // Uigur +"uk" // Ukrainian +"ur" // Urdu +"uz" // Uzbek +"vi" // Vietnamese +"vo" // Volapuk +"cy" // Welsh +"wo" // Wolof +"xh" // Xhosa +"yi" // Yiddish +"yo" // Yoruba +"za" // Zhuang +"zu" // Zulu +; + +static const char country_code_list[] = +"  " // AnyLanguage +"AF" // Afghanistan +"AL" // Albania +"DZ" // Algeria +"AS" // AmericanSamoa +"AD" // Andorra +"AO" // Angola +"AI" // Anguilla +"AQ" // Antarctica +"AG" // AntiguaAndBarbuda +"AR" // Argentina +"AM" // Armenia +"AW" // Aruba +"AU" // Australia +"AT" // Austria +"AZ" // Azerbaijan +"BS" // Bahamas +"BH" // Bahrain +"BD" // Bangladesh +"BB" // Barbados +"BY" // Belarus +"BE" // Belgium +"BZ" // Belize +"BJ" // Benin +"BM" // Bermuda +"BT" // Bhutan +"BO" // Bolivia +"BA" // BosniaAndHerzegowina +"BW" // Botswana +"BV" // BouvetIsland +"BR" // Brazil +"IO" // BritishIndianOceanTerritory +"BN" // BruneiDarussalam +"BG" // Bulgaria +"BF" // BurkinaFaso +"BI" // Burundi +"KH" // Cambodia +"CM" // Cameroon +"CA" // Canada +"CV" // CapeVerde +"KY" // CaymanIslands +"CF" // CentralAfricanRepublic +"TD" // Chad +"CL" // Chile +"CN" // China +"CX" // ChristmasIsland +"CC" // CocosIslands +"CO" // Colombia +"KM" // Comoros +"CD" // DetqmocraticRepublicOfCongo +"CG" // PeoplesRepublicOfCongo +"CK" // CookIslands +"CR" // CostaRica +"CI" // IvoryCoast +"HR" // Croatia +"CU" // Cuba +"CY" // Cyprus +"CZ" // CzechRepublic +"DK" // Denmark +"DJ" // Djibouti +"DM" // Dominica +"DO" // DominicanRepublic +"TL" // EastTimor +"EC" // Ecuador +"EG" // Egypt +"SV" // ElSalvador +"GQ" // EquatorialGuinea +"ER" // Eritrea +"EE" // Estonia +"ET" // Ethiopia +"FK" // FalklandIslands +"FO" // FaroeIslands +"FJ" // Fiji +"FI" // Finland +"FR" // France +"FX" // MetropolitanFrance +"GF" // FrenchGuiana +"PF" // FrenchPolynesia +"TF" // FrenchSouthernTerritories +"GA" // Gabon +"GM" // Gambia +"GE" // Georgia +"DE" // Germany +"GH" // Ghana +"GI" // Gibraltar +"GR" // Greece +"GL" // Greenland +"GD" // Grenada +"GP" // Guadeloupe +"GU" // Guam +"GT" // Guatemala +"GN" // Guinea +"GW" // GuineaBissau +"GY" // Guyana +"HT" // Haiti +"HM" // HeardAndMcDonaldIslands +"HN" // Honduras +"HK" // HongKong +"HU" // Hungary +"IS" // Iceland +"IN" // India +"ID" // Indonesia +"IR" // Iran +"IQ" // Iraq +"IE" // Ireland +"IL" // Israel +"IT" // Italy +"JM" // Jamaica +"JP" // Japan +"JO" // Jordan +"KZ" // Kazakhstan +"KE" // Kenya +"KI" // Kiribati +"KP" // DetqmocraticRepublicOfKorea +"KR" // RepublicOfKorea +"KW" // Kuwait +"KG" // Kyrgyzstan +"LA" // Lao +"LV" // Latvia +"LB" // Lebanon +"LS" // Lesotho +"LR" // Liberia +"LY" // LibyanArabJamahiriya +"LI" // Liechtenstein +"LT" // Lithuania +"LU" // Luxembourg +"MO" // Macau +"MK" // Macedonia +"MG" // Madagascar +"MW" // Malawi +"MY" // Malaysia +"MV" // Maldives +"ML" // Mali +"MT" // Malta +"MH" // MarshallIslands +"MQ" // Martinique +"MR" // Mauritania +"MU" // Mauritius +"YT" // Mayotte +"MX" // Mexico +"FM" // Micronesia +"MD" // Moldova +"MC" // Monaco +"MN" // Mongolia +"MS" // Montserrat +"MA" // Morocco +"MZ" // Mozambique +"MM" // Myanmar +"NA" // Namibia +"NR" // Nauru +"NP" // Nepal +"NL" // Netherlands +"AN" // NetherlandsAntilles +"NC" // NewCaledonia +"NZ" // NewZealand +"NI" // Nicaragua +"NE" // Niger +"NG" // Nigeria +"NU" // Niue +"NF" // NorfolkIsland +"MP" // NorthernMarianaIslands +"NO" // Norway +"OM" // Oman +"PK" // Pakistan +"PW" // Palau +"PS" // PalestinianTerritory +"PA" // Panama +"PG" // PapuaNewGuinea +"PY" // Paraguay +"PE" // Peru +"PH" // Philippines +"PN" // Pitcairn +"PL" // Poland +"PT" // Portugal +"PR" // PuertoRico +"QA" // Qatar +"RE" // Reunion +"RO" // Romania +"RU" // RussianFederation +"RW" // Rwanda +"KN" // SaintKittsAndNevis +"LC" // StLucia +"VC" // StVincentAndTheGrenadines +"WS" // Samoa +"SM" // SanMarino +"ST" // SaoTomeAndPrincipe +"SA" // SaudiArabia +"SN" // Senegal +"SC" // Seychelles +"SL" // SierraLeone +"SG" // Singapore +"SK" // Slovakia +"SI" // Slovenia +"SB" // SolomonIslands +"SO" // Somalia +"ZA" // SouthAfrica +"GS" // SouthGeorgiaAndTheSouthSandwichIslands +"ES" // Spain +"LK" // SriLanka +"SH" // StHelena +"PM" // StPierreAndMiquelon +"SD" // Sudan +"SR" // Suriname +"SJ" // SvalbardAndJanMayenIslands +"SZ" // Swaziland +"SE" // Sweden +"CH" // Switzerland +"SY" // SyrianArabRepublic +"TW" // Taiwan +"TJ" // Tajikistan +"TZ" // Tanzania +"TH" // Thailand +"TG" // Togo +"TK" // Tokelau +"TO" // Tonga +"TT" // TrinidadAndTobago +"TN" // Tunisia +"TR" // Turkey +"TM" // Turkmenistan +"TC" // TurksAndCaicosIslands +"TV" // Tuvalu +"UG" // Uganda +"UA" // Ukraine +"AE" // UnitedArabEmirates +"GB" // UnitedKingdom +"US" // UnitedStates +"UM" // UnitedStatesMinorOutlyingIslands +"UY" // Uruguay +"UZ" // Uzbekistan +"VU" // Vanuatu +"VA" // VaticanCityState +"VE" // Venezuela +"VN" // VietNam +"VG" // BritishVirginIslands +"VI" // USVirginIslands +"WF" // WallisAndFutunaIslands +"EH" // WesternSahara +"YE" // Yemen +"YU" // Yugoslavia +"ZM" // Zambia +"ZW" // Zimbabwe +; + +static TQLocale::Language codeToLanguage(const TQString &code) +{ +    if (code.length() != 2) +        return TQLocale::C; + +    ushort uc1 = code.tqunicode()[0].tqunicode(); +    ushort uc2 = code.tqunicode()[1].tqunicode(); + +    const char *c = language_code_list; +    for (; *c != 0; c += 2) { +        if (uc1 == (unsigned char)c[0] && uc2 == (unsigned char)c[1]) +            return (TQLocale::Language) ((c - language_code_list)/2); +    } + +    return TQLocale::C; +} + +static TQLocale::Country codeToCountry(const TQString &code) +{ +    if (code.length() != 2) +        return TQLocale::AnyCountry; + +    ushort uc1 = code.tqunicode()[0].tqunicode(); +    ushort uc2 = code.tqunicode()[1].tqunicode(); + +    const char *c = country_code_list; +    for (; *c != 0; c += 2) { +        if (uc1 == (unsigned char)c[0] && uc2 == (unsigned char)c[1]) +            return (TQLocale::Country) ((c - country_code_list)/2); +    } + +    return TQLocale::AnyCountry; +} + +static TQString languageToCode(TQLocale::Language language) +{ +    if (language == TQLocale::C) +            return "C"; + +    TQString code; +    code.setLength(2); +    const char *c = language_code_list + 2*(uint)language; +    code[0] = c[0]; +    code[1] = c[1]; +    return code; +} + +static TQString countryToCode(TQLocale::Country country) +{ +    if (country == TQLocale::AnyCountry) +        return TQString::null; + +    TQString code; +    code.setLength(2); +    const char *c = country_code_list + 2*(uint)country; +    code[0] = c[0]; +    code[1] = c[1]; +    return code; +} + +const TQLocalePrivate *TQLocale::default_d = 0; + +TQString TQLocalePrivate::infinity() const +{ +    return TQString::tqfromLatin1("inf"); +} + +TQString TQLocalePrivate::nan() const +{ +    return TQString::tqfromLatin1("nan"); +} + +#if defined(TQ_OS_WIN) +/* Win95 doesn't have a function to return the ISO lang/country name of the user's locale. +   Instead it can return a "Windows code". This maps windows codes to ISO country names. */ + +struct WindowsToISOListElt { +    int windows_code; +    char iso_name[6]; +}; + +static const WindowsToISOListElt windows_to_iso_list[] = { +    { 0x0401, "ar_SA" }, +    { 0x0402, "bg\0  " }, +    { 0x0403, "ca\0  " }, +    { 0x0404, "zh_TW" }, +    { 0x0405, "cs\0  " }, +    { 0x0406, "da\0  " }, +    { 0x0407, "de\0  " }, +    { 0x0408, "el\0  " }, +    { 0x0409, "en_US" }, +    { 0x040a, "es\0  " }, +    { 0x040b, "fi\0  " }, +    { 0x040c, "fr\0  " }, +    { 0x040d, "he\0  " }, +    { 0x040e, "hu\0  " }, +    { 0x040f, "is\0  " }, +    { 0x0410, "it\0  " }, +    { 0x0411, "ja\0  " }, +    { 0x0412, "ko\0  " }, +    { 0x0413, "nl\0  " }, +    { 0x0414, "no\0  " }, +    { 0x0415, "pl\0  " }, +    { 0x0416, "pt_BR" }, +    { 0x0418, "ro\0  " }, +    { 0x0419, "ru\0  " }, +    { 0x041a, "hr\0  " }, +    { 0x041c, "sq\0  " }, +    { 0x041d, "sv\0  " }, +    { 0x041e, "th\0  " }, +    { 0x041f, "tr\0  " }, +    { 0x0420, "ur\0  " }, +    { 0x0421, "in\0  " }, +    { 0x0422, "uk\0  " }, +    { 0x0423, "be\0  " }, +    { 0x0425, "et\0  " }, +    { 0x0426, "lv\0  " }, +    { 0x0427, "lt\0  " }, +    { 0x0429, "fa\0  " }, +    { 0x042a, "vi\0  " }, +    { 0x042d, "eu\0  " }, +    { 0x042f, "mk\0  " }, +    { 0x0436, "af\0  " }, +    { 0x0438, "fo\0  " }, +    { 0x0439, "hi\0  " }, +    { 0x043e, "ms\0  " }, +    { 0x0458, "mt\0  " }, +    { 0x0801, "ar_IQ" }, +    { 0x0804, "zh_CN" }, +    { 0x0807, "de_CH" }, +    { 0x0809, "en_GB" }, +    { 0x080a, "es_MX" }, +    { 0x080c, "fr_BE" }, +    { 0x0810, "it_CH" }, +    { 0x0812, "ko\0  " }, +    { 0x0813, "nl_BE" }, +    { 0x0814, "no\0  " }, +    { 0x0816, "pt\0  " }, +    { 0x081a, "sr\0  " }, +    { 0x081d, "sv_FI" }, +    { 0x0c01, "ar_EG" }, +    { 0x0c04, "zh_HK" }, +    { 0x0c07, "de_AT" }, +    { 0x0c09, "en_AU" }, +    { 0x0c0a, "es\0  " }, +    { 0x0c0c, "fr_CA" }, +    { 0x0c1a, "sr\0  " }, +    { 0x1001, "ar_LY" }, +    { 0x1004, "zh_SG" }, +    { 0x1007, "de_LU" }, +    { 0x1009, "en_CA" }, +    { 0x100a, "es_GT" }, +    { 0x100c, "fr_CH" }, +    { 0x1401, "ar_DZ" }, +    { 0x1407, "de_LI" }, +    { 0x1409, "en_NZ" }, +    { 0x140a, "es_CR" }, +    { 0x140c, "fr_LU" }, +    { 0x1801, "ar_MA" }, +    { 0x1809, "en_IE" }, +    { 0x180a, "es_PA" }, +    { 0x1c01, "ar_TN" }, +    { 0x1c09, "en_ZA" }, +    { 0x1c0a, "es_DO" }, +    { 0x2001, "ar_OM" }, +    { 0x2009, "en_JM" }, +    { 0x200a, "es_VE" }, +    { 0x2401, "ar_YE" }, +    { 0x2409, "en\0  " }, +    { 0x240a, "es_CO" }, +    { 0x2801, "ar_SY" }, +    { 0x2809, "en_BZ" }, +    { 0x280a, "es_PE" }, +    { 0x2c01, "ar_JO" }, +    { 0x2c09, "en_TT" }, +    { 0x2c0a, "es_AR" }, +    { 0x3001, "ar_LB" }, +    { 0x300a, "es_EC" }, +    { 0x3401, "ar_KW" }, +    { 0x340a, "es_CL" }, +    { 0x3801, "ar_AE" }, +    { 0x380a, "es_UY" }, +    { 0x3c01, "ar_BH" }, +    { 0x3c0a, "es_PY" }, +    { 0x4001, "ar_QA" }, +    { 0x400a, "es_BO" }, +    { 0x440a, "es_SV" }, +    { 0x480a, "es_HN" }, +    { 0x4c0a, "es_NI" }, +    { 0x500a, "es_PR" } +}; + +static const int windows_to_iso_count +    = sizeof(windows_to_iso_list)/sizeof(WindowsToISOListElt); + +static const char *winLangCodeToIsoName(int code) +{ +    int cmp = code - windows_to_iso_list[0].windows_code; +    if (cmp < 0) +        return 0; + +    if (cmp == 0) +        return windows_to_iso_list[0].iso_name; + +    int begin = 0; +    int end = windows_to_iso_count; + +    while (end - begin > 1) { +        uint mid = (begin + end)/2; + +        const WindowsToISOListElt *elt = windows_to_iso_list + mid; +        int cmp = code - elt->windows_code; +        if (cmp < 0) +            end = mid; +        else if (cmp > 0) +            begin = mid; +        else +            return elt->iso_name; +    } + +    return 0; + +} +#endif // TQ_OS_WIN + +const char* TQLocalePrivate::systemLocaleName() +{ +    static TQCString lang; +    lang = getenv( "LANG" ); + +#if !defined( TQWS ) && defined( TQ_OS_MAC ) +    if ( !lang.isEmpty() ) +        return lang; + +    char mac_ret[255]; +    if(!LocaleRefGetPartString(NULL, kLocaleLanguageMask | kLocaleRegionMask, 255, mac_ret)) +        lang = mac_ret; +#endif + +#if defined(TQ_WS_WIN) +    if ( !lang.isEmpty() ) { +        long id = 0; +        bool ok = false; +        id = qstrtoll(lang.data(), 0, 0, &ok); +        if ( !ok || id == 0 || id < INT_MIN || id > INT_MAX ) +            return lang; +        else +            return winLangCodeToIsoName( (int)id ); +    } + +    if (qWinVersion() == TQt::WV_95) { +        lang = winLangCodeToIsoName(GetUserDefaultLangID()); +    } else { +        TQT_WA( { +            wchar_t out[256]; +            TQString language; +            TQString sublanguage; +            if ( GetLocaleInfoW( LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME , out, 255 ) ) +                language = TQString::fromUcs2( (ushort*)out ); +            if ( GetLocaleInfoW( LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, out, 255 ) ) +                sublanguage = TQString::fromUcs2( (ushort*)out ).lower(); +            lang = language; +            if ( sublanguage != language && !sublanguage.isEmpty() ) +                lang += "_" + sublanguage.upper(); +        } , { +            char out[256]; +            TQString language; +            TQString sublanguage; +            if ( GetLocaleInfoA( LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, out, 255 ) ) +                language = TQString::fromLocal8Bit( out ); +            if ( GetLocaleInfoA( LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, out, 255 ) ) +                sublanguage = TQString::fromLocal8Bit( out ).lower(); +            lang = language; +            if ( sublanguage != language && !sublanguage.isEmpty() ) +                lang += "_" + sublanguage.upper(); +        } ); +    } +#endif +    if ( lang.isEmpty() ) +        lang = "C"; + +    return lang; +} + +static const TQLocalePrivate *tqfindLocale(TQLocale::Language language, +                                            TQLocale::Country country) +{ +    unsigned language_id = (unsigned)language; +    unsigned country_id = (unsigned)country; + +    uint idx = locale_index[language_id]; + +    const TQLocalePrivate *d = locale_data + idx; + +    if (idx == 0) // default language has no associated country +        return d; + +    if (country == TQLocale::AnyCountry) +        return d; + +    TQ_ASSERT(d->languageId() == language_id); + +    while (d->languageId() == language_id +                && d->countryId() != country_id) +        ++d; + +    if (d->countryId() == country_id +            && d->languageId() == language_id) +        return d; + +    return locale_data + idx; +} + +/*! +    \class TQLocale +    \brief The TQLocale class converts between numbers and their +    string representations in various languages. + +    \reentrant +    \ingroup text + +    It is initialized with a country/language pair in its constructor +    and offers number-to-string and string-to-number conversion +    functions simmilar to those in TQString. + +    \code +    TQLocale egyptian(TQLocale::Arabic, TQLocale::Egypt); +    TQString s1 = egyptian.toString(1.571429E+07, 'e'); +    TQString s2 = egyptian.toString(10); + +    double d = egyptian.toDouble(s1); +    int s2 = egyptian.toInt(s2); +    \endcode + +    TQLocale supports the concept of a default locale, which is +    determined from the system's locale settings at application +    startup. The default locale can be changed by calling the +    static member setDefault(). The default locale has the +    following effects: + +    \list +    \i If a TQLocale object is constructed with the default constructor, +       it will use the default locale's settings. +    \i TQString::toDouble() interprets the string according to the default +       locale. If this fails, it falls back on the "C" locale. +    \i TQString::arg() uses the default locale to format a number when +       its position specifier in the format string tqcontains an 'L', +       e.g. "%L1". +    \endlist + +    \code +    TQLocale::setDefault(TQLocale(TQLocale::Hebrew, TQLocale::Israel)); +    TQLocale hebrew; // Constructs a default TQLocale +    TQString s1 = hebrew.toString(15714.3, 'e'); + +    bool ok; +    double d; + +    TQLocale::setDefault(TQLocale::C); +    d = TQString( "1234,56" ).toDouble(&ok); // ok == false +    d = TQString( "1234.56" ).toDouble(&ok); // ok == true, d == 1234.56 + +    TQLocale::setDefault(TQLocale::German); +    d = TQString( "1234,56" ).toDouble(&ok); // ok == true, d == 1234.56 +    d = TQString( "1234.56" ).toDouble(&ok); // ok == true, d == 1234.56 + +    TQLocale::setDefault(TQLocale(TQLocale::English, TQLocale::UnitedStates)); +    str = TQString( "%1 %L2 %L3" ) +            .arg( 12345 ) +            .arg( 12345 ) +            .arg( 12345, 0, 16 ); +    // str == "12345 12,345 3039" +    \endcode + +    When a language/country pair is specified in the constructor, one +    of three things can happen: + +    \list +    \i If the language/country pair is found in the database, it is used. +    \i If the language is found but the country is not, or if the country +       is \c AnyCountry, the language is used with the most +       appropriate available country (for example, Germany for German), +    \i If neither the language nor the country are found, TQLocale +       defaults to the default locale (see setDefault()). +    \endlist + +    The "C" locale is identical to English/UnitedStates. + +    Use language() and country() to determine the actual language and +    country values used. + +    An alternative method for constructing a TQLocale object is by +    specifying the locale name. + +    \code +    TQLocale korean("ko"); +    TQLocale swiss("de_CH"); +    \endcode + +    This constructor converts the locale name to a language/country +    pair; it does not use the system locale database. + +    All the methods in TQLocale, with the exception of setDefault(), +    are reentrant. + +    \sa TQString::toDouble() TQString::arg() + +    The double-to-string and string-to-double conversion functions are +    covered by the following licenses: + +    \legalese + +    Copyright (c) 1991 by AT&T. + +    Permission to use, copy, modify, and distribute this software for any +    purpose without fee is hereby granted, provided that this entire notice +    is included in all copies of any software which is or includes a copy +    or modification of this software and in all copies of the supporting +    documentation for such software. + +    THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED +    WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR AT&T MAKES ANY +    REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY +    OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + +    This product includes software developed by the University of +    California, Berkeley and its contributors. +*/ + +/*! +    \enum TQLocale::Language + +    This enumerated type is used to specify a language. + +    \value C Identical to English/UnitedStates +    \value Abkhazian +    \value Afan +    \value Afar +    \value Afrikaans +    \value Albanian +    \value Amharic +    \value Arabic +    \value Armenian +    \value Assamese +    \value Aymara +    \value Azerbaijani +    \value Bashkir +    \value Basque +    \value Bengali +    \value Bhutani +    \value Bihari +    \value Bislama +    \value Breton +    \value Bulgarian +    \value Burmese +    \value Byelorussian +    \value Cambodian +    \value Catalan +    \value Chinese +    \value Corsican +    \value Croatian +    \value Czech +    \value Danish +    \value Dutch +    \value English +    \value Esperanto +    \value Estonian +    \value Faroese +    \value FijiLanguage +    \value Finnish +    \value French +    \value Frisian +    \value Gaelic +    \value Galician +    \value Georgian +    \value German +    \value Greek +    \value Greenlandic +    \value Guarani +    \value Gujarati +    \value Hausa +    \value Hebrew +    \value Hindi +    \value Hungarian +    \value Icelandic +    \value Indonesian +    \value Interlingua +    \value Interlingue +    \value Inuktitut +    \value Inupiak +    \value Irish +    \value Italian +    \value Japanese +    \value Javanese +    \value Kannada +    \value Kashmiri +    \value Kazakh +    \value Kinyarwanda +    \value Kirghiz +    \value Korean +    \value Kurdish +    \value Kurundi +    \value Laothian +    \value Latin +    \value Latvian +    \value Lingala +    \value Lithuanian +    \value Macedonian +    \value Malagasy +    \value Malay +    \value Malayalam +    \value Maltese +    \value Maori +    \value Marathi +    \value Moldavian +    \value Mongolian +    \value NauruLanguage +    \value Nepali +    \value Norwegian +    \value Occitan +    \value Oriya +    \value Pashto +    \value Persian +    \value Polish +    \value Portuguese +    \value Punjabi +    \value Quechua +    \value RhaetoRomance +    \value Romanian +    \value Russian +    \value Samoan +    \value Sangho +    \value Sanskrit +    \value Serbian +    \value SerboCroatian +    \value Sesotho +    \value Setswana +    \value Shona +    \value Sindhi +    \value Singhalese +    \value Siswati +    \value Slovak +    \value Slovenian +    \value Somali +    \value Spanish +    \value Sundanese +    \value Swahili +    \value Swedish +    \value Tagalog +    \value Tajik +    \value Tamil +    \value Tatar +    \value Telugu +    \value Thai +    \value Tibetan +    \value Tigrinya +    \value TongaLanguage +    \value Tsonga +    \value Turkish +    \value Turkmen +    \value Twi +    \value Uigur +    \value Ukrainian +    \value Urdu +    \value Uzbek +    \value Vietnamese +    \value Volapuk +    \value Welsh +    \value Wolof +    \value Xhosa +    \value Yiddish +    \value Yoruba +    \value Zhuang +    \value Zulu +*/ + +/*! +    \enum TQLocale::Country + +    This enumerated type is used to specify a country. + +    \value AnyCountry +    \value Afghanistan +    \value Albania +    \value Algeria +    \value AmericanSamoa +    \value Andorra +    \value Angola +    \value Anguilla +    \value Antarctica +    \value AntiguaAndBarbuda +    \value Argentina +    \value Armenia +    \value Aruba +    \value Australia +    \value Austria +    \value Azerbaijan +    \value Bahamas +    \value Bahrain +    \value Bangladesh +    \value Barbados +    \value Belarus +    \value Belgium +    \value Belize +    \value Benin +    \value Bermuda +    \value Bhutan +    \value Bolivia +    \value BosniaAndHerzegowina +    \value Botswana +    \value BouvetIsland +    \value Brazil +    \value BritishIndianOceanTerritory +    \value BruneiDarussalam +    \value Bulgaria +    \value BurkinaFaso +    \value Burundi +    \value Cambodia +    \value Cameroon +    \value Canada +    \value CapeVerde +    \value CaymanIslands +    \value CentralAfricanRepublic +    \value Chad +    \value Chile +    \value China +    \value ChristmasIsland +    \value CocosIslands +    \value Colombia +    \value Comoros +    \value DetqmocraticRepublicOfCongo +    \value PeoplesRepublicOfCongo +    \value CookIslands +    \value CostaRica +    \value IvoryCoast +    \value Croatia +    \value Cuba +    \value Cyprus +    \value CzechRepublic +    \value Denmark +    \value Djibouti +    \value Dominica +    \value DominicanRepublic +    \value EastTimor +    \value Ecuador +    \value Egypt +    \value ElSalvador +    \value EquatorialGuinea +    \value Eritrea +    \value Estonia +    \value Ethiopia +    \value FalklandIslands +    \value FaroeIslands +    \value FijiCountry +    \value Finland +    \value France +    \value MetropolitanFrance +    \value FrenchGuiana +    \value FrenchPolynesia +    \value FrenchSouthernTerritories +    \value Gabon +    \value Gambia +    \value Georgia +    \value Germany +    \value Ghana +    \value Gibraltar +    \value Greece +    \value Greenland +    \value Grenada +    \value Guadeloupe +    \value Guam +    \value Guatemala +    \value Guinea +    \value GuineaBissau +    \value Guyana +    \value Haiti +    \value HeardAndMcDonaldIslands +    \value Honduras +    \value HongKong +    \value Hungary +    \value Iceland +    \value India +    \value Indonesia +    \value Iran +    \value Iraq +    \value Ireland +    \value Israel +    \value Italy +    \value Jamaica +    \value Japan +    \value Jordan +    \value Kazakhstan +    \value Kenya +    \value Kiribati +    \value DetqmocraticRepublicOfKorea +    \value RepublicOfKorea +    \value Kuwait +    \value Kyrgyzstan +    \value Lao +    \value Latvia +    \value Lebanon +    \value Lesotho +    \value Liberia +    \value LibyanArabJamahiriya +    \value Liechtenstein +    \value Lithuania +    \value Luxembourg +    \value Macau +    \value Macedonia +    \value Madagascar +    \value Malawi +    \value Malaysia +    \value Maldives +    \value Mali +    \value Malta +    \value MarshallIslands +    \value Martinique +    \value Mauritania +    \value Mauritius +    \value Mayotte +    \value Mexico +    \value Micronesia +    \value Moldova +    \value Monaco +    \value Mongolia +    \value Montserrat +    \value Morocco +    \value Mozambique +    \value Myanmar +    \value Namibia +    \value NauruCountry +    \value Nepal +    \value Netherlands +    \value NetherlandsAntilles +    \value NewCaledonia +    \value NewZealand +    \value Nicaragua +    \value Niger +    \value Nigeria +    \value Niue +    \value NorfolkIsland +    \value NorthernMarianaIslands +    \value Norway +    \value Oman +    \value Pakistan +    \value Palau +    \value PalestinianTerritory +    \value Panama +    \value PapuaNewGuinea +    \value Paraguay +    \value Peru +    \value Philippines +    \value Pitcairn +    \value Poland +    \value Portugal +    \value PuertoRico +    \value Qatar +    \value Reunion +    \value Romania +    \value RussianFederation +    \value Rwanda +    \value SaintKittsAndNevis +    \value StLucia +    \value StVincentAndTheGrenadines +    \value Samoa +    \value SanMarino +    \value SaoTomeAndPrincipe +    \value SaudiArabia +    \value Senegal +    \value Seychelles +    \value SierraLeone +    \value Singapore +    \value Slovakia +    \value Slovenia +    \value SolomonIslands +    \value Somalia +    \value SouthAfrica +    \value SouthGeorgiaAndTheSouthSandwichIslands +    \value Spain +    \value SriLanka +    \value StHelena +    \value StPierreAndMiquelon +    \value Sudan +    \value Suriname +    \value SvalbardAndJanMayenIslands +    \value Swaziland +    \value Sweden +    \value Switzerland +    \value SyrianArabRepublic +    \value Taiwan +    \value Tajikistan +    \value Tanzania +    \value Thailand +    \value Togo +    \value Tokelau +    \value TongaCountry +    \value TrinidadAndTobago +    \value Tunisia +    \value Turkey +    \value Turkmenistan +    \value TurksAndCaicosIslands +    \value Tuvalu +    \value Uganda +    \value Ukraine +    \value UnitedArabEmirates +    \value UnitedKingdom +    \value UnitedStates +    \value UnitedStatesMinorOutlyingIslands +    \value Uruguay +    \value Uzbekistan +    \value Vanuatu +    \value VaticanCityState +    \value Venezuela +    \value VietNam +    \value BritishVirginIslands +    \value USVirginIslands +    \value WallisAndFutunaIslands +    \value WesternSahara +    \value Yemen +    \value Yugoslavia +    \value Zambia +    \value Zimbabwe +*/ + +/*! +    Constructs a TQLocale object with the specified \a name, +    which has the format +    "language[_country][.codeset][@modifier]" or "C", where: + +    \list +    \i language is a lowercase, two-letter, ISO 639 language code, +    \i territory is an uppercase, two-letter, ISO 3166 country code, +    \i and codeset and modifier are ignored. +    \endlist + +    If the string violates the locale format, or language is not +    a valid ISO 369 code, the "C" locale is used instead. If country +    is not present, or is not a valid ISO 3166 code, the most +    appropriate country is chosen for the specified language. + +    The language and country codes are converted to their respective +    \c Language and \c Country enums. After this conversion is +    performed the constructor behaves exactly like TQLocale(Country, +    Language). + +    This constructor is much slower than TQLocale(Country, Language). + +    \sa name() +*/ + +TQLocale::TQLocale(const TQString &name) +{ +    Language lang = C; +    Country cntry = AnyCountry; + +    uint l = name.length(); + +    do { +        if (l < 2) +            break; + +        const TQChar *uc = name.tqunicode(); +        if (l > 2 +                    && uc[2] != '_' +                && uc[2] != '.' +                && uc[2] != '@') +            break; + +        lang = codeToLanguage(name.mid(0, 2)); +        if (lang == C) +            break; + +        if (l == 2 || uc[2] == '.' || uc[2] == '@') +            break; + +        // we have uc[2] == '_' +        if (l < 5) +            break; + +        if (l > 5 && uc[5] != '.' && uc[5] != '@') +            break; + +        cntry = codeToCountry(name.mid(3, 2)); +    } while (FALSE); + +    d = tqfindLocale(lang, cntry); +} + +/*! +    Constructs a TQLocale object initialized with the default locale. + +    \sa setDefault() +*/ + +TQLocale::TQLocale() +{ +    if (default_d == 0) +        default_d = system().d; + +    d = default_d; +} + +/*! +    Constructs a TQLocale object with the specified \a language and \a +    country. + +    \list +    \i If the language/country pair is found in the database, it is used. +    \i If the language is found but the country is not, or if the country +       is \c AnyCountry, the language is used with the most +       appropriate available country (for example, Germany for German), +    \i If neither the language nor the country are found, TQLocale +       defaults to the default locale (see setDefault()). +    \endlist + +    The language and country that are actually used can be queried +    using language() and country(). + +    \sa setDefault() language() country() +*/ + +TQLocale::TQLocale(Language language, Country country) +{ +    d = tqfindLocale(language, country); + +    // If not found, should default to system +    if (d->languageId() == TQLocale::C && language != TQLocale::C) { +        if (default_d == 0) +            default_d = system().d; + +        d = default_d; +    } +} + +/*! +    Constructs a TQLocale object as a copy of \a other. +*/ + +TQLocale::TQLocale(const TQLocale &other) +{ +    d = other.d; +} + +/*! +    Assigns \a other to this TQLocale object and returns a reference +    to this TQLocale object. +*/ + +TQLocale &TQLocale::operator=(const TQLocale &other) +{ +    d = other.d; +    return *this; +} + +/*! +    \nonreentrant + +    Sets the global default locale to \a locale. These +    values are used when a TQLocale object is constructed with +    no arguments. If this function is not called, the system's +    locale is used. + +    \warning In a multithreaded application, the default locale +    should be set at application startup, before any non-GUI threads +    are created. + +    \sa system() c() +*/ + +void TQLocale::setDefault(const TQLocale &locale) +{ +    default_d = locale.d; +} + +/*! +    Returns the language of this locale. + +    \sa TQLocale() +*/ +TQLocale::Language TQLocale::language() const +{ +    return (Language)d->languageId(); +} + +/*! +    Returns the country of this locale. + +    \sa TQLocale() +*/ +TQLocale::Country TQLocale::country() const +{ +    return (Country)d->countryId(); +} + +/*! +    Returns the language and country of this locale as a +    string of the form "language_country", where +    language is a lowercase, two-letter ISO 639 language code, +    and country is an uppercase, two-letter ISO 3166 country code. + +    \sa TQLocale() +*/ + +TQString TQLocale::name() const +{ +    Language l = language(); + +    TQString result = languageToCode(l); + +    if (l == C) +        return result; + +    Country c = country(); +    if (c == AnyCountry) +        return result; + +    result.append('_'); +    result.append(countryToCode(c)); + +    return result; +} + +/*! +    Returns a TQString containing the name of \a language. +*/ + +TQString TQLocale::languageToString(Language language) +{ +    if ((uint)language > (uint)TQLocale::LastLanguage) +            return "Unknown"; +    return language_name_list + language_name_index[(uint)language]; +} + +/*! +    Returns a TQString containing the name of \a country. +*/ + +TQString TQLocale::countryToString(Country country) +{ +    if ((uint)country > (uint)TQLocale::LastCountry) +            return "Unknown"; +    return country_name_list + country_name_index[(uint)country]; +} + +/*! +    Returns the short int represented by the localized string \a s, or +    0 if the conversion failed. + +    If \a ok is not 0, reports failure by setting +    *ok to false and success by setting *ok to true. + +    This function ignores leading and trailing whitespace. + +    \sa toString() +*/ + +short TQLocale::toShort(const TQString &s, bool *ok) const +{ +    TQ_LLONG i = toLongLong(s, ok); +    if (i < SHRT_MIN || i > SHRT_MAX) { +        if (ok != 0) +            *ok = FALSE; +        return 0; +    } +    return (short) i; +} + +/*! +    Returns the unsigned short int represented by the localized string +    \a s, or 0 if the conversion failed. + +    If \a ok is not 0, reports failure by setting +    *ok to false and success by setting *ok to true. + +    This function ignores leading and trailing whitespace. + +    \sa toString() +*/ + +ushort TQLocale::toUShort(const TQString &s, bool *ok) const +{ +    TQ_ULLONG i = toULongLong(s, ok); +    if (i > USHRT_MAX) { +        if (ok != 0) +            *ok = FALSE; +        return 0; +    } +    return (ushort) i; +} + +/*! +    Returns the int represented by the localized string \a s, or 0 if +    the conversion failed. + +    If \a ok is not 0, reports failure by setting *ok to false and +    success by setting *ok to true. + +    This function ignores leading and trailing whitespace. + +    \sa toString() +*/ + +int TQLocale::toInt(const TQString &s, bool *ok) const +{ +    TQ_LLONG i = toLongLong(s, ok); +    if (i < INT_MIN || i > INT_MAX) { +        if (ok != 0) +            *ok = FALSE; +        return 0; +    } +    return (int) i; +} + +/*! +    Returns the unsigned int represented by the localized string \a s, +    or 0 if the conversion failed. + +    If \a ok is not 0, reports failure by setting +    *ok to false and success by setting *ok to true. + +    This function ignores leading and trailing whitespace. + +    \sa toString() +*/ + +uint TQLocale::toUInt(const TQString &s, bool *ok) const +{ +    TQ_ULLONG i = toULongLong(s, ok); +    if (i > UINT_MAX) { +        if (ok != 0) +            *ok = FALSE; +        return 0; +    } +    return (uint) i; +} + +/*! +    Returns the long int represented by the localized string \a s, or +    0 if the conversion failed. + +    If \a ok is not 0, reports failure by setting +    *ok to false and success by setting *ok to true. + +    This function ignores leading and trailing whitespace. + +    \sa toString() +*/ + +TQ_LONG TQLocale::toLong(const TQString &s, bool *ok) const +{ +    TQ_LLONG i = toLongLong(s, ok); +    if (i < LONG_MIN || i > LONG_MAX) { +        if (ok != 0) +            *ok = FALSE; +        return 0; +    } +    return (TQ_LONG) i; +} + +/*! +    Returns the unsigned long int represented by the localized string +    \a s, or 0 if the conversion failed. + +    If \a ok is not 0, reports failure by setting +    *ok to false and success by setting *ok to true. + +    This function ignores leading and trailing whitespace. + +    \sa toString() +*/ + +TQ_ULONG TQLocale::toULong(const TQString &s, bool *ok) const +{ +    TQ_ULLONG i = toULongLong(s, ok); +    if (i > ULONG_MAX) { +        if (ok != 0) +            *ok = FALSE; +        return 0; +    } +    return (TQ_ULONG) i; +} + +/*! +    Returns the long long int represented by the localized string \a +    s, or 0 if the conversion failed. + +    If \a ok is not 0, reports failure by setting +    *ok to false and success by setting *ok to true. + +    This function ignores leading and trailing whitespace. + +    \sa toString() +*/ + + +TQ_LLONG TQLocale::toLongLong(const TQString &s, bool *ok) const +{ +    return d->stringToLongLong(s, 0, ok, TQLocalePrivate::ParseGroupSeparators); +} + +/*! +    Returns the unsigned long long int represented by the localized +    string \a s, or 0 if the conversion failed. + +    If \a ok is not 0, reports failure by setting +    *ok to false and success by setting *ok to true. + +    This function ignores leading and trailing whitespace. + +    \sa toString() +*/ + + +TQ_ULLONG TQLocale::toULongLong(const TQString &s, bool *ok) const +{ +    return d->stringToUnsLongLong(s, 0, ok, TQLocalePrivate::ParseGroupSeparators); +} + +/*! +    Returns the float represented by the localized string \a s, or 0.0 +    if the conversion failed. + +    If \a ok is not 0, reports failure by setting +    *ok to false and success by setting *ok to true. + +    This function ignores leading and trailing whitespace. + +    \sa toString() +*/ + +#define TQT_MAX_FLOAT 3.4028234663852886e+38 + +float TQLocale::toFloat(const TQString &s, bool *ok) const +{ +    bool myOk; +    double d = toDouble(s, &myOk); +    if (!myOk || d > TQT_MAX_FLOAT || d < -TQT_MAX_FLOAT) { +        if (ok != 0) +            *ok = FALSE; +        return 0.0; +    } +    if (ok != 0) +        *ok = TRUE; +    return (float) d; +} + +/*! +    Returns the double represented by the localized string \a s, or +    0.0 if the conversion failed. + +    If \a ok is not 0, reports failure by setting +    *ok to false and success by setting *ok to true. + +    Unlike TQString::toDouble(), this function does not fall back to +    the "C" locale if the string cannot be interpreted in this +    locale. + +    \code +        bool ok; +        double d; + +        TQLocale c(TQLocale::C); +        d = c.toDouble( "1234.56", &ok );  // ok == true, d == 1234.56 +        d = c.toDouble( "1,234.56", &ok ); // ok == true, d == 1234.56 +        d = c.toDouble( "1234,56", &ok );  // ok == false + +        TQLocale german(TQLocale::German); +        d = german.toDouble( "1234,56", &ok );  // ok == true, d == 1234.56 +        d = german.toDouble( "1.234,56", &ok ); // ok == true, d == 1234.56 +        d = german.toDouble( "1234.56", &ok );  // ok == false + +        d = german.toDouble( "1.234", &ok );    // ok == true, d == 1234.0 +    \endcode + +    Notice that the last conversion returns 1234.0, because '.' is the +    thousands group separator in the German locale. + +    This function ignores leading and trailing whitespace. + +    \sa toString() TQString::toDouble() +*/ + +double TQLocale::toDouble(const TQString &s, bool *ok) const +{ +    return d->stringToDouble(s, ok, TQLocalePrivate::ParseGroupSeparators); +} + +/*! +    Returns a localized string representation of \a i. + +    \sa toLongLong() +*/ + +TQString TQLocale::toString(TQ_LLONG i) const +{ +    return d->longLongToString(i, -1, 10, -1, TQLocalePrivate::ThousandsGroup); +} + +/*! +    \overload + +    \sa toULongLong() +*/ + +TQString TQLocale::toString(TQ_ULLONG i) const +{ +    return d->unsLongLongToString(i, -1, 10, -1, TQLocalePrivate::ThousandsGroup); +} + +static bool qIsUpper(char c) +{ +    return c >= 'A' && c <= 'Z'; +} + +static char qToLower(char c) +{ +    if (c >= 'A' && c <= 'Z') +        return c - 'A' + 'a'; +    else +        return c; +} + +/*! +    \overload + +    \a f and \a prec have the same meaning as in TQString::number(double, char, int). + +    \sa toDouble() +*/ + +TQString TQLocale::toString(double i, char f, int prec) const +{ +    TQLocalePrivate::DoubleForm form = TQLocalePrivate::DFDecimal; +    uint flags = 0; + +    if (qIsUpper(f)) +        flags = TQLocalePrivate::CapitalEorX; +    f = qToLower(f); + +    switch (f) { +        case 'f': +            form = TQLocalePrivate::DFDecimal; +            break; +        case 'e': +            form = TQLocalePrivate::DFExponent; +            break; +        case 'g': +            form = TQLocalePrivate::DFSignificantDigits; +            break; +        default: +            break; +    } + +    flags |= TQLocalePrivate::ThousandsGroup; +    return d->doubleToString(i, prec, form, -1, flags); +} + +/*! +    \fn TQLocale TQLocale::c() + +    Returns a TQLocale object initialized to the "C" locale. + +    \sa system() +*/ + +/*! +    Returns a TQLocale object initialized to the system locale. +*/ + +TQLocale TQLocale::system() +{ +#ifdef TQ_OS_UNIX +    const char *s = getenv("LC_NUMERIC"); +    if (s == 0) +        s = getenv("LC_ALL"); +    if (s != 0) +            return TQLocale(s); +#endif +    return TQLocale(TQLocalePrivate::systemLocaleName()); +} + +/*! +\fn TQString TQLocale::toString(short i) const + +\overload + +\sa toShort() +*/ + +/*! +\fn TQString TQLocale::toString(ushort i) const + +\overload + +\sa toUShort() +*/ + +/*! +\fn TQString TQLocale::toString(int i) const + +\overload + +\sa toInt() +*/ + +/*! +\fn TQString TQLocale::toString(uint i) const + +\overload + +\sa toUInt() +*/ + +/*! +\fn TQString TQLocale::toString(TQ_LONG i) const + +\overload + +\sa  toLong() +*/ + +/*! +\fn TQString TQLocale::toString(TQ_ULONG i) const + +\overload + +\sa toULong() +*/ + +/*! +\fn TQString TQLocale::toString(float i, char f = 'g', int prec = 6) const + +\overload + +\a f and \a prec have the same meaning as in TQString::number(double, char, int). + +\sa toDouble() +*/ + + +bool TQLocalePrivate::isDigit(TQChar d) const +{ +    return zero().tqunicode() <= d.tqunicode() +            && zero().tqunicode() + 10 > d.tqunicode(); +} + +static char digitToCLocale(TQChar zero, TQChar d) +{ +    if (zero.tqunicode() <= d.tqunicode() +            && zero.tqunicode() + 10 > d.tqunicode()) +        return '0' + d.tqunicode() - zero.tqunicode(); + +    qWarning("TQLocalePrivate::digitToCLocale(): bad digit: row=%d, cell=%d", d.row(), d.cell()); +    return TQChar(0); +} + +static TQString qulltoa(TQ_ULLONG l, int base, const TQLocalePrivate &locale) +{ +    TQChar buff[65]; // length of MAX_ULLONG in base 2 +    TQChar *p = buff + 65; + +    if (base != 10 || locale.zero().tqunicode() == '0') { +        while (l != 0) { +            int c = l % base; + +            --p; + +            if (c < 10) +                *p = '0' + c; +            else +                *p = c - 10 + 'a'; + +            l /= base; +        } +    } +    else { +        while (l != 0) { +            int c = l % base; + +            *(--p) = locale.zero().tqunicode() + c; + +            l /= base; +        } +    } + +    return TQString(p, 65 - (p - buff)); +} + +static TQString qlltoa(TQ_LLONG l, int base, const TQLocalePrivate &locale) +{ +    return qulltoa(l < 0 ? -l : l, base, locale); +} + +enum PrecisionMode { +    PMDecimalDigits =             0x01, +    PMSignificantDigits =   0x02, +    PMChopTrailingZeros =   0x03 +}; + +static TQString &decimalForm(TQString &digits, int decpt, uint precision, +                            PrecisionMode pm, +                            bool always_show_decpt, +                            bool thousands_group, +                            const TQLocalePrivate &locale) +{ +    if (decpt < 0) { +        for (int i = 0; i < -decpt; ++i) +            digits.prepend(locale.zero()); +        decpt = 0; +    } +    else if ((uint)decpt > digits.length()) { +        for (uint i = digits.length(); i < (uint)decpt; ++i) +            digits.append(locale.zero()); +    } + +    if (pm == PMDecimalDigits) { +        uint decimal_digits = digits.length() - decpt; +        for (uint i = decimal_digits; i < precision; ++i) +            digits.append(locale.zero()); +    } +    else if (pm == PMSignificantDigits) { +        for (uint i = digits.length(); i < precision; ++i) +            digits.append(locale.zero()); +    } +    else { // pm == PMChopTrailingZeros +    } + +    if (always_show_decpt || (uint)decpt < digits.length()) +        digits.insert(decpt, locale.decimal()); + +    if (thousands_group) { +        for (int i = decpt - 3; i > 0; i -= 3) +            digits.insert(i, locale.group()); +    } + +    if (decpt == 0) +        digits.prepend(locale.zero()); + +    return digits; +} + +static TQString &exponentForm(TQString &digits, int decpt, uint precision, +                                PrecisionMode pm, +                                bool always_show_decpt, +                                const TQLocalePrivate &locale) +{ +    int exp = decpt - 1; + +    if (pm == PMDecimalDigits) { +        for (uint i = digits.length(); i < precision + 1; ++i) +            digits.append(locale.zero()); +    } +    else if (pm == PMSignificantDigits) { +        for (uint i = digits.length(); i < precision; ++i) +            digits.append(locale.zero()); +    } +    else { // pm == PMChopTrailingZeros +    } + +    if (always_show_decpt || digits.length() > 1) +        digits.insert(1, locale.decimal()); + +    digits.append(locale.exponential()); +    digits.append(locale.longLongToString(exp, 2, 10, +                    -1, TQLocalePrivate::AlwaysShowSign)); + +    return digits; +} + +static bool isZero(double d) +{ +    uchar *ch = (uchar *)&d; +    if (ByteOrder == BigEndian) { +        return !(ch[0] & 0x7F || ch[1] || ch[2] || ch[3] || ch[4] || ch[5] || ch[6] || ch[7]); +    } else { +        return !(ch[7] & 0x7F || ch[6] || ch[5] || ch[4] || ch[3] || ch[2] || ch[1] || ch[0]); +    } +} + +TQString TQLocalePrivate::doubleToString(double d, +                                        int precision, +                                        DoubleForm form, +                                        int width, +                                        unsigned flags) const +{ +    if (precision == -1) +        precision = 6; +    if (width == -1) +        width = 0; + +    bool negative = FALSE; +    bool special_number = FALSE; // nan, +/-inf +    TQString num_str; + +#ifdef TQ_OS_WIN +    // Detect special numbers (nan, +/-inf) +    if (qIsInf(d)) { +        num_str = infinity(); +        special_number = TRUE; +        negative = d < 0; +    } else if (qIsNan(d)) { +        num_str = nan(); +        special_number = TRUE; +    } +#else +    // Comparing directly to INFINITY gives weird results on some systems. +    double tmp_infinity = INFINITY; + +    // Detect special numbers (nan, +/-inf) +    if (d == tmp_infinity || d == -tmp_infinity) { +        num_str = infinity(); +        special_number = TRUE; +        negative = d < 0; +    } else if (qIsNan(d)) { +        num_str = nan(); +        special_number = TRUE; +    } +#endif + +    // Handle normal numbers +    if (!special_number) { +        int decpt, sign; +        TQString digits; + +#ifdef TQT_TQLOCALE_USES_FCVT +#ifdef TQT_THREAD_SUPPORT +        static bool dummy_for_mutex; +        TQMutex *fcvt_mutex =  tqt_global_mutexpool ? tqt_global_mutexpool->get( &dummy_for_mutex ) : 0; +# define FCVT_LOCK if (fcvt_mutex) fcvt_mutex->lock() +# define FCVT_UNLOCK if (fcvt_mutex) fcvt_mutex->unlock() +#else +# define FCVT_LOCK +# define FCVT_UNLOCK +#endif +        if (form == DFDecimal) { +            FCVT_LOCK; +            digits = fcvt(d, precision, &decpt, &sign); +            FCVT_UNLOCK; +        } else { +            int pr = precision; +            if (form == DFExponent) +                ++pr; +            else if (form == DFSignificantDigits && pr == 0) +                pr = 1; +            FCVT_LOCK; +            digits = ecvt(d, pr, &decpt, &sign); +            FCVT_UNLOCK; + +            // Chop trailing zeros +            if (digits.length() > 0) { +                int last_nonzero_idx = digits.length() - 1; +                while (last_nonzero_idx > 0 +                       && digits.tqunicode()[last_nonzero_idx] == '0') +                    --last_nonzero_idx; +                digits.truncate(last_nonzero_idx + 1); +            } + +        } + +#else +        int mode; +        if (form == DFDecimal) +            mode = 3; +        else +            mode = 2; + +        /* This next bit is a bit quirky. In DFExponent form, the precision +           is the number of digits after decpt. So that would suggest using +           mode=3 for qdtoa. But qdtoa behaves strangely when mode=3 and +           precision=0. So we get around this by using mode=2 and reasoning +           that we want precision+1 significant digits, since the decimal +           point in this mode is always after the first digit. */ +        int pr = precision; +        if (form == DFExponent) +            ++pr; + +        char *rve = 0; +        char *buff = 0; +        digits = qdtoa(d, mode, pr, &decpt, &sign, &rve, &buff); +        if (buff != 0) +            free(buff); +#endif // TQT_TQLOCALE_USES_FCVT + +        if (zero().tqunicode() != '0') { +            for (uint i = 0; i < digits.length(); ++i) +                    digits.ref(i).unicode() += zero().tqunicode() - '0'; +        } + +        bool always_show_decpt = flags & Alternate; +        switch (form) { +            case DFExponent: { +                num_str = exponentForm(digits, decpt, precision, PMDecimalDigits, +                                                    always_show_decpt, *this); +                break; +            } +            case DFDecimal: { +                num_str = decimalForm(digits, decpt, precision, PMDecimalDigits, +                                        always_show_decpt, flags & ThousandsGroup, +                                        *this); +                break; +            } +            case DFSignificantDigits: { +                PrecisionMode mode = (flags & Alternate) ? +                            PMSignificantDigits : PMChopTrailingZeros; + +                if (decpt != (int)digits.length() && (decpt <= -4 || decpt > (int)precision)) +                    num_str = exponentForm(digits, decpt, precision, mode, +                                                    always_show_decpt, *this); +                else +                    num_str = decimalForm(digits, decpt, precision, mode, +                                            always_show_decpt, flags & ThousandsGroup, +                                            *this); +                break; +            } +        } + +        negative = sign != 0 && !isZero(d); +    } + +    // pad with zeros. LeftAdjusted overrides this flag). Also, we don't +    // pad special numbers +    if (flags & TQLocalePrivate::ZeroPadded +            && !(flags & TQLocalePrivate::LeftAdjusted) +            && !special_number) { +        int num_pad_chars = width - (int)num_str.length(); +        // leave space for the sign +        if (negative +                || flags & TQLocalePrivate::AlwaysShowSign +                || flags & TQLocalePrivate::BlankBeforePositive) +            --num_pad_chars; + +        for (int i = 0; i < num_pad_chars; ++i) +            num_str.prepend(zero()); +    } + +    // add sign +    if (negative) +        num_str.prepend(minus()); +    else if (flags & TQLocalePrivate::AlwaysShowSign) +        num_str.prepend(plus()); +    else if (flags & TQLocalePrivate::BlankBeforePositive) +            num_str.prepend(' '); + +    if (flags & TQLocalePrivate::CapitalEorX) +            num_str = num_str.upper(); + +    return num_str; +} + +TQString TQLocalePrivate::longLongToString(TQ_LLONG l, int precision, +                                            int base, int width, +                                            unsigned flags) const +{ +    bool precision_not_specified = FALSE; +    if (precision == -1) { +        precision_not_specified = TRUE; +        precision = 1; +    } + +    bool negative = l < 0; +    if (base != 10) { +        // these are not suported by sprintf for octal and hex +        flags &= ~AlwaysShowSign; +        flags &= ~BlankBeforePositive; +        negative = FALSE; // neither are negative numbers +    } + +    TQString num_str; +    if (base == 10) +        num_str = qlltoa(l, base, *this); +    else +        num_str = qulltoa(l, base, *this); + +    uint cnt_thousand_sep = 0; +    if (flags & ThousandsGroup && base == 10) { +        for (int i = (int)num_str.length() - 3; i > 0; i -= 3) { +            num_str.insert(i, group()); +            ++cnt_thousand_sep; +        } +    } + +    for (int i = num_str.length()/* - cnt_thousand_sep*/; i < precision; ++i) +            num_str.prepend(base == 10 ? zero() : TQChar('0')); + +    if (flags & Alternate +            && base == 8 +            && (num_str.isEmpty() +                        || num_str[0].unicode() != '0')) +            num_str.prepend('0'); + +    // LeftAdjusted overrides this flag ZeroPadded. sprintf only padds +    // when precision is not specified in the format string +    bool zero_padded = flags & ZeroPadded +                        && !(flags & LeftAdjusted) +                        && precision_not_specified; + +    if (zero_padded) { +        int num_pad_chars = width - (int)num_str.length(); + +        // leave space for the sign +        if (negative +                || flags & AlwaysShowSign +                || flags & BlankBeforePositive) +            --num_pad_chars; + +        // leave space for optional '0x' in hex form +        if (base == 16 +                && flags & Alternate +                && l != 0) +            num_pad_chars -= 2; + +        for (int i = 0; i < num_pad_chars; ++i) +            num_str.prepend(base == 10 ? zero() : TQChar('0')); +    } + +    if (base == 16 +            && flags & Alternate +            && l != 0) +            num_str.prepend("0x"); + +    // add sign +    if (negative) +        num_str.prepend(minus()); +    else if (flags & AlwaysShowSign) +            num_str.prepend(base == 10 ? plus() : TQChar('+')); +    else if (flags & BlankBeforePositive) +            num_str.prepend(' '); + +    if (flags & CapitalEorX) +            num_str = num_str.upper(); + +    return num_str; +} + +TQString TQLocalePrivate::unsLongLongToString(TQ_ULLONG l, int precision, +                                            int base, int width, +                                            unsigned flags) const +{ +    bool precision_not_specified = FALSE; +    if (precision == -1) { +        precision_not_specified = TRUE; +        precision = 1; +    } + +    TQString num_str = qulltoa(l, base, *this); + +    uint cnt_thousand_sep = 0; +    if (flags & ThousandsGroup && base == 10) { +        for (int i = (int)num_str.length() - 3; i > 0; i -=3) { +            num_str.insert(i, group()); +            ++cnt_thousand_sep; +        } +    } + +    for (int i = num_str.length()/* - cnt_thousand_sep*/; i < precision; ++i) +            num_str.prepend(base == 10 ? zero() : TQChar('0')); + +    if (flags & Alternate +            && base == 8 +            && (num_str.isEmpty() +                        || num_str[0].unicode() != '0')) +            num_str.prepend('0'); + +    // LeftAdjusted overrides this flag ZeroPadded. sprintf only padds +    // when precision is not specified in the format string +    bool zero_padded = flags & ZeroPadded +                        && !(flags & LeftAdjusted) +                        && precision_not_specified; + +    if (zero_padded) { +        int num_pad_chars = width - (int)num_str.length(); + +        // leave space for optional '0x' in hex form +        if (base == 16 +                && flags & Alternate +                && l != 0) +            num_pad_chars -= 2; + +        for (int i = 0; i < num_pad_chars; ++i) +            num_str.prepend(base == 10 ? zero() : TQChar('0')); +    } + +    if (base == 16 +            && flags & Alternate +            && l != 0) +            num_str.prepend("0x"); + +    if (flags & CapitalEorX) +            num_str = num_str.upper(); + +    return num_str; +} + +static inline bool isLatin1Digit(const TQChar &c) +{ +    return c.tqunicode() >= '0' && c.tqunicode() <= '9'; +} + +// Removes thousand-group separators, ie. the ',' in "1,234,567.89e-5" +bool TQLocalePrivate::removeGroupSeparators(TQString &num_str) const +{ +    int group_cnt = 0; // counts number of group chars +    int decpt_idx = -1; + +    // Find the decimal point and check if there are any group chars +    uint i = 0; +    for (; i < num_str.length(); ++i) { +            TQChar c = num_str.tqunicode()[i]; + +        if (c.tqunicode() == ',') { +            // check that there are digits before and after the separator +            if (i == 0 || !isLatin1Digit(num_str.tqunicode()[i - 1])) +                return FALSE; +            if (i == num_str.length() + 1 || !isLatin1Digit(num_str.tqunicode()[i + 1])) +                return FALSE; +            ++group_cnt; +        } +        else if (c.tqunicode() == '.') { +            // Fail if more than one decimal points +            if (decpt_idx != -1) +                return FALSE; +            decpt_idx = i; +        } else if (c.tqunicode() == 'e' || c.tqunicode() == 'E') { +            // an 'e' or 'E' - if we have not encountered a decimal +            // point, this is where it "is". +            if (decpt_idx == -1) +                decpt_idx = i; +        } +    } + +    // If no group chars, we're done +    if (group_cnt == 0) +        return TRUE; + +    // No decimal point means that it "is" at the end of the string +    if (decpt_idx == -1) +            decpt_idx = num_str.length(); + +    i = 0; +    while (i < num_str.length() && group_cnt > 0) { +            TQChar c = num_str.tqunicode()[i]; + +        if (c.tqunicode() == ',') { +            // Don't allow group chars after the decimal point +            if ((int)i > decpt_idx) +                return FALSE; + +            // Check that it is placed correctly relative to the decpt +            if ((decpt_idx - i) % 4 != 0) +                return FALSE; + +            // Remove it +            num_str.remove(i, 1); + +            --group_cnt; +            --decpt_idx; // adjust decpt_idx +        } else { +            // Check that we are not missing a separator +            if ((int)i < decpt_idx && (decpt_idx - i) % 4 == 0) +                return FALSE; +            ++i; +        } +    } + +    return TRUE; +} + +static void stripWhiteSpaceInPlace(TQString &s) +{ +    uint i = 0; +    while (i < s.length() && s.tqunicode()[i].isSpace()) +            ++i; +    if (i > 0) +            s.remove(0, i); + +    i = s.length(); + +    if (i == 0) +            return; +    --i; +    while (i > 0 && s.tqunicode()[i].isSpace()) +            --i; +    if (i + 1 < s.length()) +            s.truncate(i + 1); +} + +/* +    Converts a number in locale to its representation in the C locale. +    Only has to guarantee that a string that is a correct representation of +    a number will be converted. If junk is passed in, junk will be passed +    out and the error will be detected during the actual conversion to a +    number. We can't detect junk here, since we don't even know the base +    of the number. +*/ +bool TQLocalePrivate::numberToCLocale(TQString &l_num, +                                        GroupSeparatorMode group_sep_mode) const +{ +    stripWhiteSpaceInPlace(l_num); + +    if (l_num.isEmpty()) +        return FALSE; + +    for (uint idx = 0; idx < l_num.length(); ++idx) { +        TQChar c = l_num.ref(idx); + +        if (isDigit(c)) +            c = digitToCLocale(zero(), c); +        else if (c == plus()) +            c = '+'; +        else if (c == minus()) +            c = '-'; +        else if (c == decimal()) +            c = '.'; +        else if (c == group()) +            c = ','; +        // In several languages group() is the char 0xA0, which looks like a space. +        // People use a regular space instead of it and complain it doesn't work. +        else if (group().tqunicode() == 0xA0 && c.tqunicode() == ' ') +            c = ','; +        else if (c == exponential() || c == exponential().upper()) +                c = 'e'; +        else if (c == list()) +                c = ';'; +        else if (c == percent()) +            c = '%'; +        else if (c.tqunicode() >= 'A' && c.tqunicode() <= 'Z') +            c = c.lower(); +        else if (c.tqunicode() >= 'a' && c.tqunicode() <= 'z') +            ; // do nothing +        else +            return FALSE; +    } + +    if (group_sep_mode == ParseGroupSeparators +                && !removeGroupSeparators(l_num)) +            return FALSE; + +    return TRUE; +} + +double TQLocalePrivate::stringToDouble(TQString num, +                                        bool *ok, +                                        GroupSeparatorMode group_sep_mode) const +{ +    if (!numberToCLocale(num, group_sep_mode)) { +        if (ok != 0) +            *ok = FALSE; +        return 0.0; +    } + +    if (ok != 0) +        *ok = TRUE; + +    if (num == "nan") +        return NAN; + +    if (num == "+inf" +                || num == "inf") +        return INFINITY; + +    if (num == "-inf") +        return -INFINITY; + +    bool _ok; +    const char *num_buff = num.latin1(); + +#ifdef TQT_TQLOCALE_USES_FCVT +    char *endptr; +    double d = strtod(num_buff, &endptr); +    _ok = TRUE; +#else +    const char *endptr; +    double d = qstrtod(num_buff, &endptr, &_ok); +#endif + +    if (!_ok || *endptr != '\0') { +        if (ok != 0) +            *ok = FALSE; +        return 0.0; +    } +    else +        return d; +} + +TQ_LLONG TQLocalePrivate::stringToLongLong(TQString num, int base, +                                    bool *ok, +                                    GroupSeparatorMode group_sep_mode) const +{ +    if (!numberToCLocale(num, group_sep_mode)) { +        if (ok != 0) +            *ok = FALSE; +        return 0; +    } + +    bool _ok; +    const char *endptr; +    const char *num_buff = num.latin1(); +    TQ_LLONG l = qstrtoll(num_buff, &endptr, base, &_ok); + +    if (!_ok || *endptr != '\0') { +        if (ok != 0) +            *ok = FALSE; +        return 0; +    } + +    if (ok != 0) +        *ok = TRUE; +    return l; +} + +TQ_ULLONG TQLocalePrivate::stringToUnsLongLong(TQString num, int base, +                                    bool *ok, +                                    GroupSeparatorMode group_sep_mode) const +{ +    if (!numberToCLocale(num, group_sep_mode)) { +        if (ok != 0) +            *ok = FALSE; +        return 0; +    } + +    bool _ok; +    const char *endptr; +    const char *num_buff = num.latin1(); +    TQ_ULLONG l = qstrtoull(num_buff, &endptr, base, &_ok); + +    if (!_ok || *endptr != '\0') { +        if (ok != 0) +            *ok = FALSE; +        return 0; +    } + +    if (ok != 0) +        *ok = TRUE; +    return l; +} + +/*- + * Copyright (c) 1992, 1993 + *        The Regents of the University of California.  All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + *    must display the following acknowledgement: + *        This product includes software developed by the University of + *        California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + *    may be used to endorse or promote products derived from this software + *    without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSETQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +// static char sccsid[] = "@(#)strtouq.c        8.1 (Berkeley) 6/4/93"; +//  "$FreeBSD: src/lib/libc/stdlib/strtoull.c,v 1.5.2.1 2001/03/02 09:45:20 obrien Exp $"; + +/* + * Convert a string to an TQ_ULLONG integer. + * + * Ignores `locale' stuff.  Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +static TQ_ULLONG qstrtoull(const char *nptr, const char **endptr, register int base, bool *ok) +{ +    register const char *s = nptr; +    register TQ_ULLONG acc; +    register unsigned char c; +    register TQ_ULLONG qbase, cutoff; +    register int neg, any, cutlim; + +    if (ok != 0) +        *ok = TRUE; + +    /* +     * See strtoq for comments as to the logic used. +     */ +    s = nptr; +    do { +        c = *s++; +    } while (isspace(c)); +    if (c == '-') { +        if (ok != 0) +            *ok = FALSE; +        if (endptr != 0) +            *endptr = s - 1; +        return 0; +    } else { +        neg = 0; +        if (c == '+') +            c = *s++; +    } +    if ((base == 0 || base == 16) && +        c == '0' && (*s == 'x' || *s == 'X')) { +        c = s[1]; +        s += 2; +        base = 16; +    } +    if (base == 0) +        base = c == '0' ? 8 : 10; +    qbase = (unsigned)base; +    cutoff = (TQ_ULLONG)ULLONG_MAX / qbase; +    cutlim = (TQ_ULLONG)ULLONG_MAX % qbase; +    for (acc = 0, any = 0;; c = *s++) { +        if (!isascii(c)) +            break; +        if (isdigit(c)) +            c -= '0'; +        else if (isalpha(c)) +            c -= isupper(c) ? 'A' - 10 : 'a' - 10; +        else +            break; +        if (c >= base) +            break; +        if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) +            any = -1; +        else { +            any = 1; +            acc *= qbase; +            acc += c; +        } +    } +    if (any < 0) { +        acc = ULLONG_MAX; +        if (ok != 0) +            *ok = FALSE; +    } +    else if (neg) +        acc = (~acc) + 1; +    if (endptr != 0) +        *endptr = (char *)(any ? s - 1 : nptr); +    return (acc); +} + + +//  "$FreeBSD: src/lib/libc/stdlib/strtoll.c,v 1.5.2.1 2001/03/02 09:45:20 obrien Exp $"; + + +/* + * Convert a string to a TQ_LLONG integer. + * + * Ignores `locale' stuff.  Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +static TQ_LLONG qstrtoll(const char *nptr, const char **endptr, register int base, bool *ok) +{ +    register const char *s; +    register TQ_ULLONG acc; +    register unsigned char c; +    register TQ_ULLONG qbase, cutoff; +    register int neg, any, cutlim; + +    if (ok != 0) +        *ok = TRUE; + +    /* +     * Skip white space and pick up leading +/- sign if any. +     * If base is 0, allow 0x for hex and 0 for octal, else +     * assume decimal; if base is already 16, allow 0x. +     */ +    s = nptr; +    do { +        c = *s++; +    } while (isspace(c)); +    if (c == '-') { +        neg = 1; +        c = *s++; +    } else { +        neg = 0; +        if (c == '+') +            c = *s++; +    } +    if ((base == 0 || base == 16) && +        c == '0' && (*s == 'x' || *s == 'X')) { +        c = s[1]; +        s += 2; +        base = 16; +    } +    if (base == 0) +        base = c == '0' ? 8 : 10; + +    /* +     * Compute the cutoff value between legal numbers and illegal +     * numbers.  That is the largest legal value, divided by the +     * base.  An input number that is greater than this value, if +     * followed by a legal input character, is too big.  One that +     * is equal to this value may be valid or not; the limit +     * between valid and invalid numbers is then based on the last +     * digit.  For instance, if the range for quads is +     * [-9223372036854775808..9223372036854775807] and the input base +     * is 10, cutoff will be set to 922337203685477580 and cutlim to +     * either 7 (neg==0) or 8 (neg==1), meaning that if we have +     * accumulated a value > 922337203685477580, or equal but the +     * next digit is > 7 (or 8), the number is too big, and we will +     * return a range error. +     * +     * Set any if any `digits' consumed; make it negative to indicate +     * overflow. +     */ +    qbase = (unsigned)base; +    cutoff = neg ? (TQ_ULLONG)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX +        : LLONG_MAX; +    cutlim = cutoff % qbase; +    cutoff /= qbase; +    for (acc = 0, any = 0;; c = *s++) { +        if (!isascii(c)) +            break; +        if (isdigit(c)) +            c -= '0'; +        else if (isalpha(c)) +            c -= isupper(c) ? 'A' - 10 : 'a' - 10; +        else +            break; +        if (c >= base) +            break; +        if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) +            any = -1; +        else { +            any = 1; +            acc *= qbase; +            acc += c; +        } +    } +    if (any < 0) { +        acc = neg ? LLONG_MIN : LLONG_MAX; +        if (ok != 0) +            *ok = FALSE; +    } else if (neg) { +        acc = (~acc) + 1; +    } +    if (endptr != 0) +        *endptr = (char *)(any ? s - 1 : nptr); +    return (acc); +} + +#ifndef TQT_TQLOCALE_USES_FCVT + +/*        From: NetBSD: strtod.c,v 1.26 1998/02/03 18:44:21 perry Exp */ +/* $FreeBSD: src/lib/libc/stdlib/netbsd_strtod.c,v 1.2.2.2 2001/03/02 17:14:15 tegge Exp $        */ + +/* Please send bug reports to +        David M. Gay +        AT&T Bell Laboratories, Room 2C-463 +        600 Mountain Avenue +        Murray Hill, NJ 07974-2070 +        U.S.A. +        dmg@research.att.com or research!dmg + */ + +/* strtod for IEEE-, VAX-, and IBM-arithmetic machines. + * + * This strtod returns a nearest machine number to the input decimal + * string (or sets errno to ERANGE).  With IEEE arithmetic, ties are + * broken by the IEEE round-even rule.  Otherwise ties are broken by + * biased rounding (add half and chop). + * + * Inspired loosely by William D. Clinger's paper "How to Read Floating + * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. + * + * Modifications: + * + *        1. We only require IEEE, IBM, or VAX double-precision + *                arithmetic (not IEEE double-extended). + *        2. We get by with floating-point arithmetic in a case that + *                Clinger missed -- when we're computing d * 10^n + *                for a small integer d and the integer n is not too + *                much larger than 22 (the maximum integer k for which + *                we can represent 10^k exactly), we may be able to + *                compute (d*10^k) * 10^(e-k) with just one roundoff. + *        3. Rather than a bit-at-a-time adjustment of the binary + *                result in the hard case, we use floating-point + *                arithmetic to determine the adjustment to within + *                one bit; only in really hard cases do we need to + *                compute a second residual. + *        4. Because of 3., we don't need a large table of powers of 10 + *                for ten-to-e (just some small tables, e.g. of 10^k + *                for 0 <= k <= 22). + */ + +/* + * #define IEEE_LITTLE_ENDIAN for IEEE-arithmetic machines where the least + *        significant byte has the lowest address. + * #define IEEE_BIG_ENDIAN for IEEE-arithmetic machines where the most + *        significant byte has the lowest address. + * #define Long int on machines with 32-bit ints and 64-bit longs. + * #define Sudden_Underflow for IEEE-format machines without gradual + *        underflow (i.e., that flush to zero on underflow). + * #define IBM for IBM mainframe-style floating-point arithmetic. + * #define VAX for VAX-style floating-point arithmetic. + * #define Unsigned_Shifts if >> does treats its left operand as unsigned. + * #define No_leftright to omit left-right logic in fast floating-point + *        computation of dtoa. + * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3. + * #define RND_PRODTQUOT to use rnd_prod and rnd_quot (assembly routines + *        that use extended-precision instructions to compute rounded + *        products and quotients) with IBM. + * #define ROUND_BIASED for IEEE-format with biased rounding. + * #define Inaccurate_Divide for IEEE-format with correctly rounded + *        products but inaccurate quotients, e.g., for Intel i860. + * #define Just_16 to store 16 bits per 32-bit Long when doing high-precision + *        integer arithmetic.  Whether this speeds things up or slows things + *        down depends on the machine and the number being converted. + * #define KR_headers for old-style C function headers. + * #define Bad_float_h if your system lacks a float.h or if it does not + *        define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, + *        FLT_RADIX, FLT_ROUNDS, and DBL_MAX. + * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n) + *        if memory is available and otherwise does something you deem + *        appropriate.  If MALLOC is undefined, malloc will be invoked + *        directly -- and assumed always to succeed. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: strtod.c,v 1.26 1998/02/03 18:44:21 perry Exp $"); +#endif /* LIBC_SCCS and not lint */ + +/* +#if defined(__m68k__)    || defined(__sparc__) || defined(__i386__) || \ +     defined(__mips__)    || defined(__ns32k__) || defined(__alpha__) || \ +     defined(__powerpc__) || defined(TQ_OS_WIN) || defined(TQ_OS_DARWIN) || defined(TQ_OS_MACX) || \ +     defined(mips) || defined(TQ_OS_AIX) || defined(TQ_OS_SOLARIS) +#           define IEEE_BIG_OR_LITTLE_ENDIAN 1 +#endif +*/ + +// *All* of our architectures have IEEE arithmetic, don't they? +#define IEEE_BIG_OR_LITTLE_ENDIAN 1 + +#ifdef __arm32__ +/* + * Although the CPU is little endian the FP has different + * byte and word endianness. The byte order is still little endian + * but the word order is big endian. + */ +#define IEEE_BIG_OR_LITTLE_ENDIAN +#endif + +#ifdef vax +#define VAX +#endif + +#define Long        TQ_INT32 +#define ULong        TQ_UINT32 + +#define MALLOC malloc +#define CONST const + +#ifdef BSD_TQDTOA_DEBUG +#include <stdio.h> +#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} +#endif + +#ifdef Unsigned_Shifts +#define Sign_Extend(a,b) if (b < 0) a |= 0xffff0000; +#else +#define Sign_Extend(a,b) /*no-op*/ +#endif + +#if (defined(IEEE_BIG_OR_LITTLE_ENDIAN) + defined(VAX) + defined(IBM)) != 1 +#error Exactly one of IEEE_BIG_OR_LITTLE_ENDIAN, VAX, or IBM should be defined. +#endif + +inline ULong getWord0(const NEEDS_VOLATILE double x) +{ +    const NEEDS_VOLATILE uchar *ptr = reinterpret_cast<const NEEDS_VOLATILE uchar *>(&x); +    if (ByteOrder == BigEndian) { +        return (ptr[0]<<24) + (ptr[1]<<16) + (ptr[2]<<8) + ptr[3]; +    } else { +        return (ptr[7]<<24) + (ptr[6]<<16) + (ptr[5]<<8) + ptr[4]; +    } +} + +inline void setWord0(NEEDS_VOLATILE double *x, ULong l) +{ +    NEEDS_VOLATILE uchar *ptr = reinterpret_cast<NEEDS_VOLATILE uchar *>(x); +    if (ByteOrder == BigEndian) { +        ptr[0] = (uchar)(l>>24); +        ptr[1] = (uchar)(l>>16); +        ptr[2] = (uchar)(l>>8); +        ptr[3] = (uchar)l; +    } else { +        ptr[7] = (uchar)(l>>24); +        ptr[6] = (uchar)(l>>16); +        ptr[5] = (uchar)(l>>8); +        ptr[4] = (uchar)l; +    } +} + +inline ULong getWord1(const NEEDS_VOLATILE double x) +{ +    const NEEDS_VOLATILE uchar *ptr = reinterpret_cast<const NEEDS_VOLATILE uchar *>(&x); +    if (ByteOrder == BigEndian) { +        return (ptr[4]<<24) + (ptr[5]<<16) + (ptr[6]<<8) + ptr[7]; +    } else { +        return (ptr[3]<<24) + (ptr[2]<<16) + (ptr[1]<<8) + ptr[0]; +    } +} +inline void setWord1(NEEDS_VOLATILE double *x, ULong l) +{ +    NEEDS_VOLATILE uchar *ptr = reinterpret_cast<uchar NEEDS_VOLATILE *>(x); +    if (ByteOrder == BigEndian) { +        ptr[4] = (uchar)(l>>24); +        ptr[5] = (uchar)(l>>16); +        ptr[6] = (uchar)(l>>8); +        ptr[7] = (uchar)l; +    } else { +        ptr[3] = (uchar)(l>>24); +        ptr[2] = (uchar)(l>>16); +        ptr[1] = (uchar)(l>>8); +        ptr[0] = (uchar)l; +    } +} + +static inline void Storeinc(ULong *&a, const ULong &b, const ULong &c) +{ + +    *a = (((unsigned short)b) << 16) | ((unsigned short)c); +    ++a; +} + +/* #define P DBL_MANT_DIG */ +/* Ten_pmax = floor(P*log(2)/log(5)) */ +/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ +/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ +/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ + +#if defined(IEEE_BIG_OR_LITTLE_ENDIAN) +#define Exp_shift  20 +#define Exp_shift1 20 +#define Exp_msk1    0x100000 +#define Exp_msk11   0x100000 +#define Exp_mask  0x7ff00000 +#define P 53 +#define Bias 1023 +#define IEEE_Arith +#define Emin (-1022) +#define Exp_1  0x3ff00000 +#define Exp_11 0x3ff00000 +#define Ebits 11 +#define Frac_mask  0xfffff +#define Frac_mask1 0xfffff +#define Ten_pmax 22 +#define Bletch 0x10 +#define Bndry_mask  0xfffff +#define Bndry_mask1 0xfffff +#define LSB 1 +#define Sign_bit 0x80000000 +#define Log2P 1 +#define Tiny0 0 +#define Tiny1 1 +#define Quick_max 14 +#define Int_max 14 +#define Infinite(x) (getWord0(x) == 0x7ff00000) /* sufficient test for here */ +#else +#undef  Sudden_Underflow +#define Sudden_Underflow +#ifdef IBM +#define Exp_shift  24 +#define Exp_shift1 24 +#define Exp_msk1   0x1000000 +#define Exp_msk11  0x1000000 +#define Exp_mask  0x7f000000 +#define P 14 +#define Bias 65 +#define Exp_1  0x41000000 +#define Exp_11 0x41000000 +#define Ebits 8        /* exponent has 7 bits, but 8 is the right value in b2d */ +#define Frac_mask  0xffffff +#define Frac_mask1 0xffffff +#define Bletch 4 +#define Ten_pmax 22 +#define Bndry_mask  0xefffff +#define Bndry_mask1 0xffffff +#define LSB 1 +#define Sign_bit 0x80000000 +#define Log2P 4 +#define Tiny0 0x100000 +#define Tiny1 0 +#define Quick_max 14 +#define Int_max 15 +#else /* VAX */ +#define Exp_shift  23 +#define Exp_shift1 7 +#define Exp_msk1    0x80 +#define Exp_msk11   0x800000 +#define Exp_mask  0x7f80 +#define P 56 +#define Bias 129 +#define Exp_1  0x40800000 +#define Exp_11 0x4080 +#define Ebits 8 +#define Frac_mask  0x7fffff +#define Frac_mask1 0xffff007f +#define Ten_pmax 24 +#define Bletch 2 +#define Bndry_mask  0xffff007f +#define Bndry_mask1 0xffff007f +#define LSB 0x10000 +#define Sign_bit 0x8000 +#define Log2P 1 +#define Tiny0 0x80 +#define Tiny1 0 +#define Quick_max 15 +#define Int_max 15 +#endif +#endif + +#ifndef IEEE_Arith +#define ROUND_BIASED +#endif + +#ifdef RND_PRODTQUOT +#define rounded_product(a,b) a = rnd_prod(a, b) +#define rounded_quotient(a,b) a = rnd_quot(a, b) +extern double rnd_prod(double, double), rnd_quot(double, double); +#else +#define rounded_product(a,b) a *= b +#define rounded_quotient(a,b) a /= b +#endif + +#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) +#define Big1 0xffffffff + +#ifndef Just_16 +/* When Pack_32 is not defined, we store 16 bits per 32-bit Long. + * This makes some inner loops simpler and sometimes saves work + * during multiplications, but it often seems to make things slightly + * slower.  Hence the default is now to store 32 bits per Long. + */ +#ifndef Pack_32 +#define Pack_32 +#endif +#endif + +#define Kmax 15 + +struct +Bigint { +    struct Bigint *next; +    int k, maxwds, sign, wds; +    ULong x[1]; +}; + + typedef struct Bigint Bigint; + +static Bigint *Balloc(int k) +{ +    int x; +    Bigint *rv; + +    x = 1 << k; +    rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(Long)); +    rv->k = k; +    rv->maxwds = x; +    rv->sign = rv->wds = 0; +    return rv; +} + +static void Bfree(Bigint *v) +{ +    free(v); +} + +#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \ +y->wds*sizeof(Long) + 2*sizeof(int)) + +/* multiply by m and add a */ +static Bigint *multadd(Bigint *b, int m, int a) +{ +    int i, wds; +    ULong *x, y; +#ifdef Pack_32 +    ULong xi, z; +#endif +    Bigint *b1; + +    wds = b->wds; +    x = b->x; +    i = 0; +    do { +#ifdef Pack_32 +        xi = *x; +        y = (xi & 0xffff) * m + a; +        z = (xi >> 16) * m + (y >> 16); +        a = (int)(z >> 16); +        *x++ = (z << 16) + (y & 0xffff); +#else +        y = *x * m + a; +        a = (int)(y >> 16); +        *x++ = y & 0xffff; +#endif +    } +    while(++i < wds); +    if (a) { +        if (wds >= b->maxwds) { +            b1 = Balloc(b->k+1); +            Bcopy(b1, b); +            Bfree(b); +            b = b1; +        } +        b->x[wds++] = a; +        b->wds = wds; +    } +    return b; +} + +static Bigint *s2b(CONST char *s, int nd0, int nd, ULong y9) +{ +    Bigint *b; +    int i, k; +    Long x, y; + +    x = (nd + 8) / 9; +    for(k = 0, y = 1; x > y; y <<= 1, k++) ; +#ifdef Pack_32 +    b = Balloc(k); +    b->x[0] = y9; +    b->wds = 1; +#else +    b = Balloc(k+1); +    b->x[0] = y9 & 0xffff; +    b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; +#endif + +    i = 9; +    if (9 < nd0) { +        s += 9; +        do b = multadd(b, 10, *s++ - '0'); +        while(++i < nd0); +        s++; +    } +    else +        s += 10; +    for(; i < nd; i++) +        b = multadd(b, 10, *s++ - '0'); +    return b; +} + +static int hi0bits(ULong x) +{ +    int k = 0; + +    if (!(x & 0xffff0000)) { +        k = 16; +        x <<= 16; +    } +    if (!(x & 0xff000000)) { +        k += 8; +        x <<= 8; +    } +    if (!(x & 0xf0000000)) { +        k += 4; +        x <<= 4; +    } +    if (!(x & 0xc0000000)) { +        k += 2; +        x <<= 2; +    } +    if (!(x & 0x80000000)) { +        k++; +        if (!(x & 0x40000000)) +            return 32; +    } +    return k; +} + +static int lo0bits(ULong *y) +{ +    int k; +    ULong x = *y; + +    if (x & 7) { +        if (x & 1) +            return 0; +        if (x & 2) { +            *y = x >> 1; +            return 1; +        } +        *y = x >> 2; +        return 2; +    } +    k = 0; +    if (!(x & 0xffff)) { +        k = 16; +        x >>= 16; +    } +    if (!(x & 0xff)) { +        k += 8; +        x >>= 8; +    } +    if (!(x & 0xf)) { +        k += 4; +        x >>= 4; +    } +    if (!(x & 0x3)) { +        k += 2; +        x >>= 2; +    } +    if (!(x & 1)) { +        k++; +        x >>= 1; +        if (!x & 1) +            return 32; +    } +    *y = x; +    return k; +} + +static Bigint *i2b(int i) +{ +    Bigint *b; + +    b = Balloc(1); +    b->x[0] = i; +    b->wds = 1; +    return b; +} + +static Bigint *mult(Bigint *a, Bigint *b) +{ +    Bigint *c; +    int k, wa, wb, wc; +    ULong carry, y, z; +    ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; +#ifdef Pack_32 +    ULong z2; +#endif + +    if (a->wds < b->wds) { +        c = a; +        a = b; +        b = c; +    } +    k = a->k; +    wa = a->wds; +    wb = b->wds; +    wc = wa + wb; +    if (wc > a->maxwds) +        k++; +    c = Balloc(k); +    for(x = c->x, xa = x + wc; x < xa; x++) +        *x = 0; +    xa = a->x; +    xae = xa + wa; +    xb = b->x; +    xbe = xb + wb; +    xc0 = c->x; +#ifdef Pack_32 +    for(; xb < xbe; xb++, xc0++) { +        if ((y = *xb & 0xffff) != 0) { +            x = xa; +            xc = xc0; +            carry = 0; +            do { +                z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; +                carry = z >> 16; +                z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; +                carry = z2 >> 16; +                Storeinc(xc, z2, z); +            } +            while(x < xae); +            *xc = carry; +        } +        if ((y = *xb >> 16) != 0) { +            x = xa; +            xc = xc0; +            carry = 0; +            z2 = *xc; +            do { +                z = (*x & 0xffff) * y + (*xc >> 16) + carry; +                carry = z >> 16; +                Storeinc(xc, z, z2); +                z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; +                carry = z2 >> 16; +            } +            while(x < xae); +            *xc = z2; +        } +    } +#else +    for(; xb < xbe; xc0++) { +        if (y = *xb++) { +            x = xa; +            xc = xc0; +            carry = 0; +            do { +                z = *x++ * y + *xc + carry; +                carry = z >> 16; +                *xc++ = z & 0xffff; +            } +            while(x < xae); +            *xc = carry; +        } +    } +#endif +    for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; +    c->wds = wc; +    return c; +} + +static Bigint *p5s; + +static Bigint *pow5mult(Bigint *b, int k) +{ +    Bigint *b1, *p5, *p51; +    int i; +    static const int p05[3] = { 5, 25, 125 }; + +    if ((i = k & 3) != 0) +        b = multadd(b, p05[i-1], 0); + +    if (!(k >>= 2)) +        return b; +    if (!(p5 = p5s)) { +        /* first time */ +        p5 = p5s = i2b(625); +        p5->next = 0; +    } +    for(;;) { +        if (k & 1) { +            b1 = mult(b, p5); +            Bfree(b); +            b = b1; +        } +        if (!(k >>= 1)) +            break; +        if (!(p51 = p5->next)) { +            p51 = p5->next = mult(p5,p5); +            p51->next = 0; +        } +        p5 = p51; +    } +    return b; +} + +static Bigint *lshift(Bigint *b, int k) +{ +    int i, k1, n, n1; +    Bigint *b1; +    ULong *x, *x1, *xe, z; + +#ifdef Pack_32 +    n = k >> 5; +#else +    n = k >> 4; +#endif +    k1 = b->k; +    n1 = n + b->wds + 1; +    for(i = b->maxwds; n1 > i; i <<= 1) +        k1++; +    b1 = Balloc(k1); +    x1 = b1->x; +    for(i = 0; i < n; i++) +        *x1++ = 0; +    x = b->x; +    xe = x + b->wds; +#ifdef Pack_32 +    if (k &= 0x1f) { +        k1 = 32 - k; +        z = 0; +        do { +            *x1++ = *x << k | z; +            z = *x++ >> k1; +        } +        while(x < xe); +        if ((*x1 = z) != 0) +            ++n1; +    } +#else +    if (k &= 0xf) { +        k1 = 16 - k; +        z = 0; +        do { +            *x1++ = *x << k  & 0xffff | z; +            z = *x++ >> k1; +        } +        while(x < xe); +        if (*x1 = z) +            ++n1; +    } +#endif +    else do +        *x1++ = *x++; +    while(x < xe); +    b1->wds = n1 - 1; +    Bfree(b); +    return b1; +} + +static int cmp(Bigint *a, Bigint *b) +{ +    ULong *xa, *xa0, *xb, *xb0; +    int i, j; + +    i = a->wds; +    j = b->wds; +#ifdef BSD_TQDTOA_DEBUG +    if (i > 1 && !a->x[i-1]) +        Bug("cmp called with a->x[a->wds-1] == 0"); +    if (j > 1 && !b->x[j-1]) +        Bug("cmp called with b->x[b->wds-1] == 0"); +#endif +    if (i -= j) +        return i; +    xa0 = a->x; +    xa = xa0 + j; +    xb0 = b->x; +    xb = xb0 + j; +    for(;;) { +        if (*--xa != *--xb) +            return *xa < *xb ? -1 : 1; +        if (xa <= xa0) +            break; +    } +    return 0; +} + +static Bigint *diff(Bigint *a, Bigint *b) +{ +    Bigint *c; +    int i, wa, wb; +    Long borrow, y;        /* We need signed shifts here. */ +    ULong *xa, *xae, *xb, *xbe, *xc; +#ifdef Pack_32 +    Long z; +#endif + +    i = cmp(a,b); +    if (!i) { +        c = Balloc(0); +        c->wds = 1; +        c->x[0] = 0; +        return c; +    } +    if (i < 0) { +        c = a; +        a = b; +        b = c; +        i = 1; +    } +    else +        i = 0; +    c = Balloc(a->k); +    c->sign = i; +    wa = a->wds; +    xa = a->x; +    xae = xa + wa; +    wb = b->wds; +    xb = b->x; +    xbe = xb + wb; +    xc = c->x; +    borrow = 0; +#ifdef Pack_32 +    do { +        y = (*xa & 0xffff) - (*xb & 0xffff) + borrow; +        borrow = y >> 16; +        Sign_Extend(borrow, y); +        z = (*xa++ >> 16) - (*xb++ >> 16) + borrow; +        borrow = z >> 16; +        Sign_Extend(borrow, z); +        Storeinc(xc, z, y); +    } +    while(xb < xbe); +    while(xa < xae) { +        y = (*xa & 0xffff) + borrow; +        borrow = y >> 16; +        Sign_Extend(borrow, y); +        z = (*xa++ >> 16) + borrow; +        borrow = z >> 16; +        Sign_Extend(borrow, z); +        Storeinc(xc, z, y); +    } +#else +    do { +        y = *xa++ - *xb++ + borrow; +        borrow = y >> 16; +        Sign_Extend(borrow, y); +        *xc++ = y & 0xffff; +    } +    while(xb < xbe); +    while(xa < xae) { +        y = *xa++ + borrow; +        borrow = y >> 16; +        Sign_Extend(borrow, y); +        *xc++ = y & 0xffff; +    } +#endif +    while(!*--xc) +        wa--; +    c->wds = wa; +    return c; +} + +static double ulp(double x) +{ +    Long L; +    double a; + +    L = (getWord0(x) & Exp_mask) - (P-1)*Exp_msk1; +#ifndef Sudden_Underflow +    if (L > 0) { +#endif +#ifdef IBM +        L |= Exp_msk1 >> 4; +#endif +        setWord0(&a, L); +        setWord1(&a, 0); +#ifndef Sudden_Underflow +    } +    else { +        L = -L >> Exp_shift; +        if (L < Exp_shift) { +            setWord0(&a, 0x80000 >> L); +            setWord1(&a, 0); +        } +        else { +            setWord0(&a, 0); +            L -= Exp_shift; +            setWord1(&a, L >= 31 ? 1U : 1U << (31 - L)); +        } +    } +#endif +    return a; +} + +static double b2d(Bigint *a, int *e) +{ +    ULong *xa, *xa0, w, y, z; +    int k; +    double d; + +    xa0 = a->x; +    xa = xa0 + a->wds; +    y = *--xa; +#ifdef BSD_TQDTOA_DEBUG +    if (!y) Bug("zero y in b2d"); +#endif +    k = hi0bits(y); +    *e = 32 - k; +#ifdef Pack_32 +    if (k < Ebits) { +        setWord0(&d, Exp_1 | y >> (Ebits - k)); +        w = xa > xa0 ? *--xa : 0; +        setWord1(&d, y << ((32-Ebits) + k) | w >> (Ebits - k)); +        goto ret_d; +    } +    z = xa > xa0 ? *--xa : 0; +    if (k -= Ebits) { +        setWord0(&d, Exp_1 | y << k | z >> (32 - k)); +        y = xa > xa0 ? *--xa : 0; +        setWord1(&d, z << k | y >> (32 - k)); +    } +    else { +        setWord0(&d, Exp_1 | y); +        setWord1(&d, z); +    } +#else +    if (k < Ebits + 16) { +        z = xa > xa0 ? *--xa : 0; +        setWord0(&d, Exp_1 | y << k - Ebits | z >> Ebits + 16 - k); +        w = xa > xa0 ? *--xa : 0; +        y = xa > xa0 ? *--xa : 0; +        setWord1(&d, z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k); +        goto ret_d; +    } +    z = xa > xa0 ? *--xa : 0; +    w = xa > xa0 ? *--xa : 0; +    k -= Ebits + 16; +    setWord0(&d, Exp_1 | y << k + 16 | z << k | w >> 16 - k); +    y = xa > xa0 ? *--xa : 0; +    setWord1(&d, w << k + 16 | y << k); +#endif + ret_d: +    return d; +} + +static Bigint *d2b(double d, int *e, int *bits) +{ +    Bigint *b; +    int de, i, k; +    ULong *x, y, z; + +#ifdef Pack_32 +    b = Balloc(1); +#else +    b = Balloc(2); +#endif +    x = b->x; + +    z = getWord0(d) & Frac_mask; +    setWord0(&d, getWord0(d) & 0x7fffffff);        /* clear sign bit, which we ignore */ +#ifdef Sudden_Underflow +    de = (int)(getWord0(d) >> Exp_shift); +#ifndef IBM +    z |= Exp_msk11; +#endif +#else +    if ((de = (int)(getWord0(d) >> Exp_shift)) != 0) +        z |= Exp_msk1; +#endif +#ifdef Pack_32 +    if ((y = getWord1(d)) != 0) { +        if ((k = lo0bits(&y)) != 0) { +            x[0] = y | z << (32 - k); +            z >>= k; +        } +        else +            x[0] = y; +        i = b->wds = (x[1] = z) ? 2 : 1; +    } +    else { +#ifdef BSD_TQDTOA_DEBUG +        if (!z) +            Bug("Zero passed to d2b"); +#endif +        k = lo0bits(&z); +        x[0] = z; +        i = b->wds = 1; +        k += 32; +    } +#else +    if (y = getWord1(d)) { +        if (k = lo0bits(&y)) +            if (k >= 16) { +                x[0] = y | z << 32 - k & 0xffff; +                x[1] = z >> k - 16 & 0xffff; +                x[2] = z >> k; +                i = 2; +            } +            else { +                x[0] = y & 0xffff; +                x[1] = y >> 16 | z << 16 - k & 0xffff; +                x[2] = z >> k & 0xffff; +                x[3] = z >> k+16; +                i = 3; +            } +        else { +            x[0] = y & 0xffff; +            x[1] = y >> 16; +            x[2] = z & 0xffff; +            x[3] = z >> 16; +            i = 3; +        } +    } +    else { +#ifdef BSD_TQDTOA_DEBUG +        if (!z) +            Bug("Zero passed to d2b"); +#endif +        k = lo0bits(&z); +        if (k >= 16) { +            x[0] = z; +            i = 0; +        } +        else { +            x[0] = z & 0xffff; +            x[1] = z >> 16; +            i = 1; +        } +        k += 32; +    } +    while(!x[i]) +        --i; +    b->wds = i + 1; +#endif +#ifndef Sudden_Underflow +    if (de) { +#endif +#ifdef IBM +        *e = (de - Bias - (P-1) << 2) + k; +        *bits = 4*P + 8 - k - hi0bits(getWord0(d) & Frac_mask); +#else +        *e = de - Bias - (P-1) + k; +        *bits = P - k; +#endif +#ifndef Sudden_Underflow +    } +    else { +        *e = de - Bias - (P-1) + 1 + k; +#ifdef Pack_32 +        *bits = 32*i - hi0bits(x[i-1]); +#else +        *bits = (i+2)*16 - hi0bits(x[i]); +#endif +    } +#endif +    return b; +} + +static double ratio(Bigint *a, Bigint *b) +{ +    double da, db; +    int k, ka, kb; + +    da = b2d(a, &ka); +    db = b2d(b, &kb); +#ifdef Pack_32 +    k = ka - kb + 32*(a->wds - b->wds); +#else +    k = ka - kb + 16*(a->wds - b->wds); +#endif +#ifdef IBM +    if (k > 0) { +        setWord0(&da, getWord0(da) + (k >> 2)*Exp_msk1); +        if (k &= 3) +            da *= 1 << k; +    } +    else { +        k = -k; +        setWord0(&db, getWord0(db) + (k >> 2)*Exp_msk1); +        if (k &= 3) +            db *= 1 << k; +    } +#else +    if (k > 0) +        setWord0(&da, getWord0(da) + k*Exp_msk1); +    else { +        k = -k; +        setWord0(&db, getWord0(db) + k*Exp_msk1); +    } +#endif +    return da / db; +} + +static CONST double tens[] = { +    1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, +    1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, +    1e20, 1e21, 1e22 +#ifdef VAX +    , 1e23, 1e24 +#endif +}; + +#ifdef IEEE_Arith +static CONST double bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; +static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, 1e-256 }; +#define n_bigtens 5 +#else +#ifdef IBM +static CONST double bigtens[] = { 1e16, 1e32, 1e64 }; +static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 }; +#define n_bigtens 3 +#else +static CONST double bigtens[] = { 1e16, 1e32 }; +static CONST double tinytens[] = { 1e-16, 1e-32 }; +#define n_bigtens 2 +#endif +#endif + +/* +  The pre-release gcc3.3 shipped with SuSE 8.2 has a bug which causes +  the comparison 1e-100 == 0.0 to return true. As a workaround, we +  compare it to a global variable containing 0.0, which produces +  correct assembler output. + +  ### consider detecting the broken compilers and using the static +  ### double for these, and use a #define for all working compilers +*/ +static double g_double_zero = 0.0; + +static double qstrtod(CONST char *s00, CONST char **se, bool *ok) +{ +    int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, +        e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; +    CONST char *s, *s0, *s1; +    double aadj, aadj1, adj, rv, rv0; +    Long L; +    ULong y, z; +    Bigint *bb1, *bd0; +    Bigint *bb = NULL, *bd = NULL, *bs = NULL, *delta = NULL;/* pacify gcc */ + +    /* +      #ifndef KR_headers +      CONST char decimal_point = localeconv()->decimal_point[0]; +      #else +      CONST char decimal_point = '.'; +      #endif */ +    if (ok != 0) +        *ok = TRUE; + +    CONST char decimal_point = '.'; + +    sign = nz0 = nz = 0; +    rv = 0.; + + +    for(s = s00; isspace((unsigned char) *s); s++) +        ; + +    if (*s == '-') { +        sign = 1; +        s++; +    } else if (*s == '+') { +        s++; +    } + +    if (*s == '\0') { +        s = s00; +        goto ret; +    } + +    if (*s == '0') { +        nz0 = 1; +        while(*++s == '0') ; +        if (!*s) +            goto ret; +    } +    s0 = s; +    y = z = 0; +    for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) +        if (nd < 9) +            y = 10*y + c - '0'; +        else if (nd < 16) +            z = 10*z + c - '0'; +    nd0 = nd; +    if (c == decimal_point) { +        c = *++s; +        if (!nd) { +            for(; c == '0'; c = *++s) +                nz++; +            if (c > '0' && c <= '9') { +                s0 = s; +                nf += nz; +                nz = 0; +                goto have_dig; +            } +            goto dig_done; +        } +        for(; c >= '0' && c <= '9'; c = *++s) { +        have_dig: +            nz++; +            if (c -= '0') { +                nf += nz; +                for(i = 1; i < nz; i++) +                    if (nd++ < 9) +                        y *= 10; +                    else if (nd <= DBL_DIG + 1) +                        z *= 10; +                if (nd++ < 9) +                    y = 10*y + c; +                else if (nd <= DBL_DIG + 1) +                    z = 10*z + c; +                nz = 0; +            } +        } +    } + dig_done: +    e = 0; +    if (c == 'e' || c == 'E') { +        if (!nd && !nz && !nz0) { +            s = s00; +            goto ret; +        } +        s00 = s; +        esign = 0; +        switch(c = *++s) { +        case '-': +            esign = 1; +        case '+': +            c = *++s; +        } +        if (c >= '0' && c <= '9') { +            while(c == '0') +                c = *++s; +            if (c > '0' && c <= '9') { +                L = c - '0'; +                s1 = s; +                while((c = *++s) >= '0' && c <= '9') +                    L = 10*L + c - '0'; +                if (s - s1 > 8 || L > 19999) +                    /* Avoid confusion from exponents +                     * so large that e might overflow. +                     */ +                    e = 19999; /* safe for 16 bit ints */ +                else +                    e = (int)L; +                if (esign) +                    e = -e; +            } +            else +                e = 0; +        } +        else +            s = s00; +    } +    if (!nd) { +        if (!nz && !nz0) +            s = s00; +        goto ret; +    } +    e1 = e -= nf; + +    /* Now we have nd0 digits, starting at s0, followed by a +     * decimal point, followed by nd-nd0 digits.  The number we're +     * after is the integer represented by those digits times +     * 10**e */ + +    if (!nd0) +        nd0 = nd; +    k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; +    rv = y; +    if (k > 9) +        rv = tens[k - 9] * rv + z; +    bd0 = 0; +    if (nd <= DBL_DIG +#ifndef RND_PRODTQUOT +        && FLT_ROUNDS == 1 +#endif +        ) { +        if (!e) +            goto ret; +        if (e > 0) { +            if (e <= Ten_pmax) { +#ifdef VAX +                goto vax_ovfl_check; +#else +                /* rv = */ rounded_product(rv, tens[e]); +                goto ret; +#endif +            } +            i = DBL_DIG - nd; +            if (e <= Ten_pmax + i) { +                /* A fancier test would sometimes let us do +                 * this for larger i values. +                 */ +                e -= i; +                rv *= tens[i]; +#ifdef VAX +                /* VAX exponent range is so narrow we must +                 * worry about overflow here... +                 */ +            vax_ovfl_check: +                setWord0(&rv, getWord0(rv) - P*Exp_msk1); +                /* rv = */ rounded_product(rv, tens[e]); +                if ((getWord0(rv) & Exp_mask) +                    > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) +                    goto ovfl; +                setWord0(&rv, getWord0(rv) + P*Exp_msk1); +#else +                /* rv = */ rounded_product(rv, tens[e]); +#endif +                goto ret; +            } +        } +#ifndef Inaccurate_Divide +        else if (e >= -Ten_pmax) { +            /* rv = */ rounded_quotient(rv, tens[-e]); +            goto ret; +        } +#endif +    } +    e1 += nd - k; + +    /* Get starting approximation = rv * 10**e1 */ + +    if (e1 > 0) { +        if ((i = e1 & 15) != 0) +            rv *= tens[i]; +        if (e1 &= ~15) { +            if (e1 > DBL_MAX_10_EXP) { +            ovfl: +                //                                errno = ERANGE; +                if (ok != 0) +                    *ok = FALSE; +#ifdef __STDC__ +                rv = HUGE_VAL; +#else +                /* Can't trust HUGE_VAL */ +#ifdef IEEE_Arith +                setWord0(&rv, Exp_mask); +                setWord1(&rv, 0); +#else +                setWord0(&rv, Big0); +                setWord1(&rv, Big1); +#endif +#endif +                if (bd0) +                    goto retfree; +                goto ret; +            } +            if (e1 >>= 4) { +                for(j = 0; e1 > 1; j++, e1 >>= 1) +                    if (e1 & 1) +                        rv *= bigtens[j]; +                /* The last multiplication could overflow. */ +                setWord0(&rv, getWord0(rv) - P*Exp_msk1); +                rv *= bigtens[j]; +                if ((z = getWord0(rv) & Exp_mask) +                    > Exp_msk1*(DBL_MAX_EXP+Bias-P)) +                    goto ovfl; +                if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { +                    /* set to largest number */ +                    /* (Can't trust DBL_MAX) */ +                    setWord0(&rv, Big0); +                    setWord1(&rv, Big1); +                } +                else +                    setWord0(&rv, getWord0(rv) + P*Exp_msk1); +            } + +        } +    } +    else if (e1 < 0) { +        e1 = -e1; +        if ((i = e1 & 15) != 0) +            rv /= tens[i]; +        if (e1 &= ~15) { +            e1 >>= 4; +            if (e1 >= 1 << n_bigtens) +                goto undfl; +            for(j = 0; e1 > 1; j++, e1 >>= 1) +                if (e1 & 1) +                    rv *= tinytens[j]; +            /* The last multiplication could underflow. */ +            rv0 = rv; +            rv *= tinytens[j]; +            if (rv == g_double_zero) +                { +                    rv = 2.*rv0; +                    rv *= tinytens[j]; +                    if (rv == g_double_zero) +                        { +                        undfl: +                            rv = 0.; +                            //                                        errno = ERANGE; +                            if (ok != 0) +                                *ok = FALSE; +                            if (bd0) +                                goto retfree; +                            goto ret; +                        } +                    setWord0(&rv, Tiny0); +                    setWord1(&rv, Tiny1); +                    /* The refinement below will clean +                     * this approximation up. +                     */ +                } +        } +    } + +    /* Now the hard part -- adjusting rv to the correct value.*/ + +    /* Put digits into bd: true value = bd * 10^e */ + +    bd0 = s2b(s0, nd0, nd, y); + +    for(;;) { +        bd = Balloc(bd0->k); +        Bcopy(bd, bd0); +        bb = d2b(rv, &bbe, &bbbits);        /* rv = bb * 2^bbe */ +        bs = i2b(1); + +        if (e >= 0) { +            bb2 = bb5 = 0; +            bd2 = bd5 = e; +        } +        else { +            bb2 = bb5 = -e; +            bd2 = bd5 = 0; +        } +        if (bbe >= 0) +            bb2 += bbe; +        else +            bd2 -= bbe; +        bs2 = bb2; +#ifdef Sudden_Underflow +#ifdef IBM +        j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3); +#else +        j = P + 1 - bbbits; +#endif +#else +        i = bbe + bbbits - 1;        /* logb(rv) */ +        if (i < Emin)        /* denormal */ +            j = bbe + (P-Emin); +        else +            j = P + 1 - bbbits; +#endif +        bb2 += j; +        bd2 += j; +        i = bb2 < bd2 ? bb2 : bd2; +        if (i > bs2) +            i = bs2; +        if (i > 0) { +            bb2 -= i; +            bd2 -= i; +            bs2 -= i; +        } +        if (bb5 > 0) { +            bs = pow5mult(bs, bb5); +            bb1 = mult(bs, bb); +            Bfree(bb); +            bb = bb1; +        } +        if (bb2 > 0) +            bb = lshift(bb, bb2); +        if (bd5 > 0) +            bd = pow5mult(bd, bd5); +        if (bd2 > 0) +            bd = lshift(bd, bd2); +        if (bs2 > 0) +            bs = lshift(bs, bs2); +        delta = diff(bb, bd); +        dsign = delta->sign; +        delta->sign = 0; +        i = cmp(delta, bs); +        if (i < 0) { +            /* Error is less than half an ulp -- check for +             * special case of mantissa a power of two. +             */ +            if (dsign || getWord1(rv) || getWord0(rv) & Bndry_mask) +                break; +            delta = lshift(delta,Log2P); +            if (cmp(delta, bs) > 0) +                goto drop_down; +            break; +        } +        if (i == 0) { +            /* exactly half-way between */ +            if (dsign) { +                if ((getWord0(rv) & Bndry_mask1) == Bndry_mask1 +                    &&  getWord1(rv) == 0xffffffff) { +                    /*boundary case -- increment exponent*/ +                    setWord0(&rv, (getWord0(rv) & Exp_mask) +                                + Exp_msk1 +#ifdef IBM +                                | Exp_msk1 >> 4 +#endif +                                ); +                    setWord1(&rv, 0); +                    break; +                } +            } +            else if (!(getWord0(rv) & Bndry_mask) && !getWord1(rv)) { +            drop_down: +                /* boundary case -- decrement exponent */ +#ifdef Sudden_Underflow +                L = getWord0(rv) & Exp_mask; +#ifdef IBM +                if (L <  Exp_msk1) +#else +                    if (L <= Exp_msk1) +#endif +                        goto undfl; +                L -= Exp_msk1; +#else +                L = (getWord0(rv) & Exp_mask) - Exp_msk1; +#endif +                setWord0(&rv, L | Bndry_mask1); +                setWord1(&rv, 0xffffffff); +#ifdef IBM +                goto cont; +#else +                break; +#endif +            } +#ifndef ROUND_BIASED +            if (!(getWord1(rv) & LSB)) +                break; +#endif +            if (dsign) +                rv += ulp(rv); +#ifndef ROUND_BIASED +            else { +                rv -= ulp(rv); +#ifndef Sudden_Underflow +                if (rv == g_double_zero) +                    goto undfl; +#endif +            } +#endif +            break; +        } +        if ((aadj = ratio(delta, bs)) <= 2.) { +            if (dsign) +                aadj = aadj1 = 1.; +            else if (getWord1(rv) || getWord0(rv) & Bndry_mask) { +#ifndef Sudden_Underflow +                if (getWord1(rv) == Tiny1 && !getWord0(rv)) +                    goto undfl; +#endif +                aadj = 1.; +                aadj1 = -1.; +            } +            else { +                /* special case -- power of FLT_RADIX to be */ +                /* rounded down... */ + +                if (aadj < 2./FLT_RADIX) +                    aadj = 1./FLT_RADIX; +                else +                    aadj *= 0.5; +                aadj1 = -aadj; +            } +        } +        else { +            aadj *= 0.5; +            aadj1 = dsign ? aadj : -aadj; +#ifdef Check_FLT_ROUNDS +            switch(FLT_ROUNDS) { +            case 2: /* towards +infinity */ +                aadj1 -= 0.5; +                break; +            case 0: /* towards 0 */ +            case 3: /* towards -infinity */ +                aadj1 += 0.5; +            } +#else +            if (FLT_ROUNDS == 0) +                aadj1 += 0.5; +#endif +        } +        y = getWord0(rv) & Exp_mask; + +        /* Check for overflow */ + +        if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { +            rv0 = rv; +            setWord0(&rv, getWord0(rv) - P*Exp_msk1); +            adj = aadj1 * ulp(rv); +            rv += adj; +            if ((getWord0(rv) & Exp_mask) >= +                Exp_msk1*(DBL_MAX_EXP+Bias-P)) { +                if (getWord0(rv0) == Big0 && getWord1(rv0) == Big1) +                    goto ovfl; +                setWord0(&rv, Big0); +                setWord1(&rv, Big1); +                goto cont; +            } +            else +                setWord0(&rv, getWord0(rv) + P*Exp_msk1); +        } +        else { +#ifdef Sudden_Underflow +            if ((getWord0(rv) & Exp_mask) <= P*Exp_msk1) { +                rv0 = rv; +                setWord0(&rv, getWord0(rv) + P*Exp_msk1); +                adj = aadj1 * ulp(rv); +                rv += adj; +#ifdef IBM +                if ((getWord0(rv) & Exp_mask) <  P*Exp_msk1) +#else +                    if ((getWord0(rv) & Exp_mask) <= P*Exp_msk1) +#endif +                        { +                            if (getWord0(rv0) == Tiny0 +                                && getWord1(rv0) == Tiny1) +                                goto undfl; +                            setWord0(&rv, Tiny0); +                            setWord1(&rv, Tiny1); +                            goto cont; +                        } +                    else +                        setWord0(&rv, getWord0(rv) - P*Exp_msk1); +            } +            else { +                adj = aadj1 * ulp(rv); +                rv += adj; +            } +#else +            /* Compute adj so that the IEEE rounding rules will +             * correctly round rv + adj in some half-way cases. +             * If rv * ulp(rv) is denormalized (i.e., +             * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid +             * trouble from bits lost to denormalization; +             * example: 1.2e-307 . +             */ +            if (y <= (P-1)*Exp_msk1 && aadj >= 1.) { +                aadj1 = (double)(int)(aadj + 0.5); +                if (!dsign) +                    aadj1 = -aadj1; +            } +            adj = aadj1 * ulp(rv); +            rv += adj; +#endif +        } +        z = getWord0(rv) & Exp_mask; +        if (y == z) { +            /* Can we stop now? */ +            L = (Long) aadj; +            aadj -= L; +            /* The tolerances below are conservative. */ +            if (dsign || getWord1(rv) || getWord0(rv) & Bndry_mask) { +                if (aadj < .4999999 || aadj > .5000001) +                    break; +            } +            else if (aadj < .4999999/FLT_RADIX) +                break; +        } +    cont: +        Bfree(bb); +        Bfree(bd); +        Bfree(bs); +        Bfree(delta); +    } + retfree: +    Bfree(bb); +    Bfree(bd); +    Bfree(bs); +    Bfree(bd0); +    Bfree(delta); + ret: +    if (se) +        *se = (char *)s; +    return sign ? -rv : rv; +} + +static int quorem(Bigint *b, Bigint *S) +{ +    int n; +    Long borrow, y; +    ULong carry, q, ys; +    ULong *bx, *bxe, *sx, *sxe; +#ifdef Pack_32 +    Long z; +    ULong si, zs; +#endif + +    n = S->wds; +#ifdef BSD_TQDTOA_DEBUG +    /*debug*/ if (b->wds > n) +        /*debug*/        Bug("oversize b in quorem"); +#endif +    if (b->wds < n) +        return 0; +    sx = S->x; +    sxe = sx + --n; +    bx = b->x; +    bxe = bx + n; +    q = *bxe / (*sxe + 1);        /* ensure q <= true quotient */ +#ifdef BSD_TQDTOA_DEBUG +    /*debug*/ if (q > 9) +        /*debug*/        Bug("oversized quotient in quorem"); +#endif +    if (q) { +        borrow = 0; +        carry = 0; +        do { +#ifdef Pack_32 +            si = *sx++; +            ys = (si & 0xffff) * q + carry; +            zs = (si >> 16) * q + (ys >> 16); +            carry = zs >> 16; +            y = (*bx & 0xffff) - (ys & 0xffff) + borrow; +            borrow = y >> 16; +            Sign_Extend(borrow, y); +            z = (*bx >> 16) - (zs & 0xffff) + borrow; +            borrow = z >> 16; +            Sign_Extend(borrow, z); +            Storeinc(bx, z, y); +#else +            ys = *sx++ * q + carry; +            carry = ys >> 16; +            y = *bx - (ys & 0xffff) + borrow; +            borrow = y >> 16; +            Sign_Extend(borrow, y); +            *bx++ = y & 0xffff; +#endif +        } +        while(sx <= sxe); +        if (!*bxe) { +            bx = b->x; +            while(--bxe > bx && !*bxe) +                --n; +            b->wds = n; +        } +    } +    if (cmp(b, S) >= 0) { +        q++; +        borrow = 0; +        carry = 0; +        bx = b->x; +        sx = S->x; +        do { +#ifdef Pack_32 +            si = *sx++; +            ys = (si & 0xffff) + carry; +            zs = (si >> 16) + (ys >> 16); +            carry = zs >> 16; +            y = (*bx & 0xffff) - (ys & 0xffff) + borrow; +            borrow = y >> 16; +            Sign_Extend(borrow, y); +            z = (*bx >> 16) - (zs & 0xffff) + borrow; +            borrow = z >> 16; +            Sign_Extend(borrow, z); +            Storeinc(bx, z, y); +#else +            ys = *sx++ + carry; +            carry = ys >> 16; +            y = *bx - (ys & 0xffff) + borrow; +            borrow = y >> 16; +            Sign_Extend(borrow, y); +            *bx++ = y & 0xffff; +#endif +        } +        while(sx <= sxe); +        bx = b->x; +        bxe = bx + n; +        if (!*bxe) { +            while(--bxe > bx && !*bxe) +                --n; +            b->wds = n; +        } +    } +    return q; +} + +/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. + * + * Inspired by "How to Print Floating-Point Numbers Accurately" by + * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101]. + * + * Modifications: + *        1. Rather than iterating, we use a simple numeric overestimate + *           to determine k = floor(log10(d)).  We scale relevant + *           quantities using O(log2(k)) rather than O(k) multiplications. + *        2. For some modes > 2 (corresponding to ecvt and fcvt), we don't + *           try to generate digits strictly left to right.  Instead, we + *           compute with fewer bits and propagate the carry if necessary + *           when rounding the final digit up.  This is often faster. + *        3. Under the assumption that input will be rounded nearest, + *           mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. + *           That is, we allow equality in stopping tests when the + *           round-nearest rule will give the same floating-point value + *           as would satisfaction of the stopping test with strict + *           inequality. + *        4. We remove common factors of powers of 2 from relevant + *           quantities. + *        5. When converting floating-point integers less than 1e16, + *           we use floating-point arithmetic rather than resorting + *           to multiple-precision integers. + *        6. When asked to produce fewer than 15 digits, we first try + *           to get by with floating-point arithmetic; we resort to + *           multiple-precision integer arithmetic only if we cannot + *           guarantee that the floating-point calculation has given + *           the correctly rounded result.  For k requested digits and + *           "uniformly" distributed input, the probability is + *           something like 10^(k-15) that we must resort to the Long + *           calculation. + */ + + +/* This actually sometimes returns a pointer to a string literal +   cast to a char*. Do NOT try to modify the return value. */ + +static char *qdtoa ( double d, int mode, int ndigits, int *decpt, int *sign, char **rve, char **resultp) +{ +    // Some values of the floating-point control word can cause _qdtoa to crash with an underflow. +    // We set a safe value here. +#ifdef TQ_OS_WIN +#ifndef TQ_CC_BOR +    unsigned int oldbits = _control87(0, 0); +#ifndef _M_X64 //x64 does not support precition control +    _control87(0x9001F, 0xFFFFF); +#else +    _control87(0x9001F, _MCW_DN|_MCW_EM|_MCW_RC); +#endif //_M_X64 +#endif +#endif + +#ifdef TQ_OS_LINUX +    fenv_t envp; +    feholdexcept(&envp); +#endif + +    char *s = _qdtoa(d, mode, ndigits, decpt, sign, rve, resultp); + +#ifdef TQ_OS_WIN +#ifndef TQ_CC_BOR +    _clear87(); +#ifndef _M_X64 +    _control87(oldbits, 0xFFFFF); +#else +    _control87(oldbits, _MCW_DN|_MCW_EM|_MCW_RC); +#endif //_M_X64 +#endif +#endif + +#ifdef TQ_OS_LINUX +    fesetenv(&envp); +#endif + +    return s; +} + +static char *_qdtoa( NEEDS_VOLATILE double d, int mode, int ndigits, int *decpt, int *sign, char **rve, char **resultp) +{ +    /* +      Arguments ndigits, decpt, sign are similar to those +      of ecvt and fcvt; trailing zeros are suppressed from +      the returned string.  If not null, *rve is set to point +      to the end of the return value.  If d is +-Infinity or NaN, +      then *decpt is set to 9999. + +      mode: +      0 ==> shortest string that yields d when read in +      and rounded to nearest. +      1 ==> like 0, but with Steele & White stopping rule; +      e.g. with IEEE P754 arithmetic , mode 0 gives +      1e23 whereas mode 1 gives 9.999999999999999e22. +      2 ==> max(1,ndigits) significant digits.  This gives a +      return value similar to that of ecvt, except +      that trailing zeros are suppressed. +      3 ==> through ndigits past the decimal point.  This +      gives a return value similar to that from fcvt, +      except that trailing zeros are suppressed, and +      ndigits can be negative. +      4-9 should give the same return values as 2-3, i.e., +      4 <= mode <= 9 ==> same return as mode +      2 + (mode & 1).  These modes are mainly for +      debugging; often they run slower but sometimes +      faster than modes 2-3. +      4,5,8,9 ==> left-to-right digit generation. +      6-9 ==> don't try fast floating-point estimate +      (if applicable). + +      Values of mode other than 0-9 are treated as mode 0. + +      Sufficient space is allocated to the return value +      to hold the suppressed trailing zeros. +    */ + +    int bbits, b2, b5, be, dig, i, ieps, ilim0, +        j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, +        try_quick; +    int ilim = 0, ilim1 = 0, spec_case = 0;        /* pacify gcc */ +    Long L; +#ifndef Sudden_Underflow +    int denorm; +    ULong x; +#endif +    Bigint *b, *b1, *delta, *mhi, *S; +    Bigint *mlo = NULL; /* pacify gcc */ +    double d2; +    double ds, eps; +    char *s, *s0; + +    if (getWord0(d) & Sign_bit) { +        /* set sign for everything, including 0's and NaNs */ +        *sign = 1; +        setWord0(&d, getWord0(d) & ~Sign_bit);        /* clear sign bit */ +    } +    else +        *sign = 0; + +#if defined(IEEE_Arith) + defined(VAX) +#ifdef IEEE_Arith +    if ((getWord0(d) & Exp_mask) == Exp_mask) +#else +        if (getWord0(d)  == 0x8000) +#endif +            { +                /* Infinity or NaN */ +                *decpt = 9999; +                s = +#ifdef IEEE_Arith +                    !getWord1(d) && !(getWord0(d) & 0xfffff) ? (char*)"Infinity" : +#endif +                    (char*)"NaN"; +                if (rve) +                    *rve = +#ifdef IEEE_Arith +                        s[3] ? s + 8 : +#endif +                        s + 3; +                return s; +            } +#endif +#ifdef IBM +    d += 0; /* normalize */ +#endif +    if (d == g_double_zero) +        { +            *decpt = 1; +            s = (char*) "0"; +            if (rve) +                *rve = s + 1; +            return s; +        } + +    b = d2b(d, &be, &bbits); +#ifdef Sudden_Underflow +    i = (int)(getWord0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); +#else +    if ((i = (int)(getWord0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1))) != 0) { +#endif +        d2 = d; +        setWord0(&d2, getWord0(d2) & Frac_mask1); +        setWord0(&d2, getWord0(d2) | Exp_11); +#ifdef IBM +        if (j = 11 - hi0bits(getWord0(d2) & Frac_mask)) +            d2 /= 1 << j; +#endif + +        /* log(x)        ~=~ log(1.5) + (x-1.5)/1.5 +         * log10(x)         =  log(x) / log(10) +         *                ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) +         * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) +         * +         * This suggests computing an approximation k to log10(d) by +         * +         * k = (i - Bias)*0.301029995663981 +         *        + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); +         * +         * We want k to be too large rather than too small. +         * The error in the first-order Taylor series approximation +         * is in our favor, so we just round up the constant enough +         * to compensate for any error in the multiplication of +         * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, +         * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, +         * adding 1e-13 to the constant term more than suffices. +         * Hence we adjust the constant term to 0.1760912590558. +         * (We could get a more accurate k by invoking log10, +         *  but this is probably not worthwhile.) +         */ + +        i -= Bias; +#ifdef IBM +        i <<= 2; +        i += j; +#endif +#ifndef Sudden_Underflow +        denorm = 0; +    } +    else { +        /* d is denormalized */ + +        i = bbits + be + (Bias + (P-1) - 1); +        x = i > 32  ? getWord0(d) << (64 - i) | getWord1(d) >> (i - 32) +            : getWord1(d) << (32 - i); +        d2 = x; +        setWord0(&d2, getWord0(d2) - 31*Exp_msk1); /* adjust exponent */ +        i -= (Bias + (P-1) - 1) + 1; +        denorm = 1; +    } +#endif +    ds = (d2-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; +    k = (int)ds; +    if (ds < 0. && ds != k) +        k--;        /* want k = floor(ds) */ +    k_check = 1; +    if (k >= 0 && k <= Ten_pmax) { +        if (d < tens[k]) +            k--; +        k_check = 0; +    } +    j = bbits - i - 1; +    if (j >= 0) { +        b2 = 0; +        s2 = j; +    } +    else { +        b2 = -j; +        s2 = 0; +    } +    if (k >= 0) { +        b5 = 0; +        s5 = k; +        s2 += k; +    } +    else { +        b2 -= k; +        b5 = -k; +        s5 = 0; +    } +    if (mode < 0 || mode > 9) +        mode = 0; +    try_quick = 1; +    if (mode > 5) { +        mode -= 4; +        try_quick = 0; +    } +    leftright = 1; +    switch(mode) { +    case 0: +    case 1: +        ilim = ilim1 = -1; +        i = 18; +        ndigits = 0; +        break; +    case 2: +        leftright = 0; +        /* no break */ +    case 4: +        if (ndigits <= 0) +            ndigits = 1; +        ilim = ilim1 = i = ndigits; +        break; +    case 3: +        leftright = 0; +        /* no break */ +    case 5: +        i = ndigits + k + 1; +        ilim = i; +        ilim1 = i - 1; +        if (i <= 0) +            i = 1; +    } +    *resultp = (char *) malloc(i + 1); +    s = s0 = *resultp; + +    if (ilim >= 0 && ilim <= Quick_max && try_quick) { + +        /* Try to get by with floating-point arithmetic. */ + +        i = 0; +        d2 = d; +        k0 = k; +        ilim0 = ilim; +        ieps = 2; /* conservative */ +        if (k > 0) { +            ds = tens[k&0xf]; +            j = k >> 4; +            if (j & Bletch) { +                /* prevent overflows */ +                j &= Bletch - 1; +                d /= bigtens[n_bigtens-1]; +                ieps++; +            } +            for(; j; j >>= 1, i++) +                if (j & 1) { +                    ieps++; +                    ds *= bigtens[i]; +                } +            d /= ds; +        } +        else if ((j1 = -k) != 0) { +            d *= tens[j1 & 0xf]; +            for(j = j1 >> 4; j; j >>= 1, i++) +                if (j & 1) { +                    ieps++; +                    d *= bigtens[i]; +                } +        } +        if (k_check && d < 1. && ilim > 0) { +            if (ilim1 <= 0) +                goto fast_failed; +            ilim = ilim1; +            k--; +            d *= 10.; +            ieps++; +        } +        eps = ieps*d + 7.; +        setWord0(&eps, getWord0(eps) - (P-1)*Exp_msk1); +        if (ilim == 0) { +            S = mhi = 0; +            d -= 5.; +            if (d > eps) +                goto one_digit; +            if (d < -eps) +                goto no_digits; +            goto fast_failed; +        } +#ifndef No_leftright +        if (leftright) { +            /* Use Steele & White method of only +             * generating digits needed. +             */ +            eps = 0.5/tens[ilim-1] - eps; +            for(i = 0;;) { +                L = (Long)d; +                d -= L; +                *s++ = '0' + (int)L; +                if (d < eps) +                    goto ret1; +                if (1. - d < eps) +                    goto bump_up; +                if (++i >= ilim) +                    break; +                eps *= 10.; +                d *= 10.; +            } +        } +        else { +#endif +            /* Generate ilim digits, then fix them up. */ +            eps *= tens[ilim-1]; +            for(i = 1;; i++, d *= 10.) { +                L = (Long)d; +                d -= L; +                *s++ = '0' + (int)L; +                if (i == ilim) { +                    if (d > 0.5 + eps) +                        goto bump_up; +                    else if (d < 0.5 - eps) { +                        while(*--s == '0'); +                        s++; +                        goto ret1; +                    } +                    break; +                } +            } +#ifndef No_leftright +        } +#endif +    fast_failed: +        s = s0; +        d = d2; +        k = k0; +        ilim = ilim0; +    } + +    /* Do we have a "small" integer? */ + +    if (be >= 0 && k <= Int_max) { +        /* Yes. */ +        ds = tens[k]; +        if (ndigits < 0 && ilim <= 0) { +            S = mhi = 0; +            if (ilim < 0 || d <= 5*ds) +                goto no_digits; +            goto one_digit; +        } +        for(i = 1;; i++) { +            L = (Long)(d / ds); +            d -= L*ds; +#ifdef Check_FLT_ROUNDS +            /* If FLT_ROUNDS == 2, L will usually be high by 1 */ +            if (d < 0) { +                L--; +                d += ds; +            } +#endif +            *s++ = '0' + (int)L; +            if (i == ilim) { +                d += d; +                if (d > ds || (d == ds && L & 1)) { +                bump_up: +                    while(*--s == '9') +                        if (s == s0) { +                            k++; +                            *s = '0'; +                            break; +                        } +                    ++*s++; +                } +                break; +            } +            if ((d *= 10.) == g_double_zero) +                break; +        } +        goto ret1; +    } + +    m2 = b2; +    m5 = b5; +    mhi = mlo = 0; +    if (leftright) { +        if (mode < 2) { +            i = +#ifndef Sudden_Underflow +                denorm ? be + (Bias + (P-1) - 1 + 1) : +#endif +#ifdef IBM +                1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3); +#else +            1 + P - bbits; +#endif +        } +        else { +            j = ilim - 1; +            if (m5 >= j) +                m5 -= j; +            else { +                s5 += j -= m5; +                b5 += j; +                m5 = 0; +            } +            if ((i = ilim) < 0) { +                m2 -= i; +                i = 0; +            } +        } +        b2 += i; +        s2 += i; +        mhi = i2b(1); +    } +    if (m2 > 0 && s2 > 0) { +        i = m2 < s2 ? m2 : s2; +        b2 -= i; +        m2 -= i; +        s2 -= i; +    } +    if (b5 > 0) { +        if (leftright) { +            if (m5 > 0) { +                mhi = pow5mult(mhi, m5); +                b1 = mult(mhi, b); +                Bfree(b); +                b = b1; +            } +            if ((j = b5 - m5) != 0) +                b = pow5mult(b, j); +        } +        else +            b = pow5mult(b, b5); +    } +    S = i2b(1); +    if (s5 > 0) +        S = pow5mult(S, s5); + +    /* Check for special case that d is a normalized power of 2. */ + +    if (mode < 2) { +        if (!getWord1(d) && !(getWord0(d) & Bndry_mask) +#ifndef Sudden_Underflow +            && getWord0(d) & Exp_mask +#endif +            ) { +            /* The special case */ +            b2 += Log2P; +            s2 += Log2P; +            spec_case = 1; +        } +        else +            spec_case = 0; +    } + +    /* Arrange for convenient computation of quotients: +     * shift left if necessary so divisor has 4 leading 0 bits. +     * +     * Perhaps we should just compute leading 28 bits of S once +     * and for all and pass them and a shift to quorem, so it +     * can do shifts and ors to compute the numerator for q. +     */ +#ifdef Pack_32 +    if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f) != 0) +        i = 32 - i; +#else +    if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf) +        i = 16 - i; +#endif +    if (i > 4) { +        i -= 4; +        b2 += i; +        m2 += i; +        s2 += i; +    } +    else if (i < 4) { +        i += 28; +        b2 += i; +        m2 += i; +        s2 += i; +    } +    if (b2 > 0) +        b = lshift(b, b2); +    if (s2 > 0) +        S = lshift(S, s2); +    if (k_check) { +        if (cmp(b,S) < 0) { +            k--; +            b = multadd(b, 10, 0);        /* we botched the k estimate */ +            if (leftright) +                mhi = multadd(mhi, 10, 0); +            ilim = ilim1; +        } +    } +    if (ilim <= 0 && mode > 2) { +        if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) { +            /* no digits, fcvt style */ +        no_digits: +            k = -1 - ndigits; +            goto ret; +        } +    one_digit: +        *s++ = '1'; +        k++; +        goto ret; +    } +    if (leftright) { +        if (m2 > 0) +            mhi = lshift(mhi, m2); + +        /* Compute mlo -- check for special case +         * that d is a normalized power of 2. +         */ + +        mlo = mhi; +        if (spec_case) { +            mhi = Balloc(mhi->k); +            Bcopy(mhi, mlo); +            mhi = lshift(mhi, Log2P); +        } + +        for(i = 1;;i++) { +            dig = quorem(b,S) + '0'; +            /* Do we yet have the shortest decimal string +             * that will round to d? +             */ +            j = cmp(b, mlo); +            delta = diff(S, mhi); +            j1 = delta->sign ? 1 : cmp(b, delta); +            Bfree(delta); +#ifndef ROUND_BIASED +            if (j1 == 0 && !mode && !(getWord1(d) & 1)) { +                if (dig == '9') +                    goto round_9_up; +                if (j > 0) +                    dig++; +                *s++ = dig; +                goto ret; +            } +#endif +            if (j < 0 || (j == 0 && !mode +#ifndef ROUND_BIASED +                          && !(getWord1(d) & 1) +#endif +                          )) { +                if (j1 > 0) { +                    b = lshift(b, 1); +                    j1 = cmp(b, S); +                    if ((j1 > 0 || (j1 == 0 && dig & 1)) +                        && dig++ == '9') +                        goto round_9_up; +                } +                *s++ = dig; +                goto ret; +            } +            if (j1 > 0) { +                if (dig == '9') { /* possible if i == 1 */ +                round_9_up: +                    *s++ = '9'; +                    goto roundoff; +                } +                *s++ = dig + 1; +                goto ret; +            } +            *s++ = dig; +            if (i == ilim) +                break; +            b = multadd(b, 10, 0); +            if (mlo == mhi) +                mlo = mhi = multadd(mhi, 10, 0); +            else { +                mlo = multadd(mlo, 10, 0); +                mhi = multadd(mhi, 10, 0); +            } +        } +    } +    else +        for(i = 1;; i++) { +            *s++ = dig = quorem(b,S) + '0'; +            if (i >= ilim) +                break; +            b = multadd(b, 10, 0); +        } + +    /* Round off last digit */ + +    b = lshift(b, 1); +    j = cmp(b, S); +    if (j > 0 || (j == 0 && dig & 1)) { +    roundoff: +        while(*--s == '9') +            if (s == s0) { +                k++; +                *s++ = '1'; +                goto ret; +            } +        ++*s++; +    } +    else { +        while(*--s == '0'); +        s++; +    } + ret: +    Bfree(S); +    if (mhi) { +        if (mlo && mlo != mhi) +            Bfree(mlo); +        Bfree(mhi); +    } + ret1: +    Bfree(b); +    if (s == s0) {                                /* don't return empty string */ +        *s++ = '0'; +        k = 0; +    } +    *s = 0; +    *decpt = k + 1; +    if (rve) +        *rve = s; +    return s0; +} + +#endif // TQT_TQLOCALE_USES_FCVT | 
