/**************************************************************************** ** ** Implementation of the TQLocale class ** ** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. ** ** 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 #include #include #include #include #include #include "ntqlocale.h" #include "qlocale_p.h" #include "ntqnamespace.h" #ifdef QT_QLOCALE_USES_FCVT # include # include #endif #if defined (Q_OS_WIN) # include # undef NAN // we want to use our fallback on Windows # undef INFINITY #endif #ifdef Q_OS_LINUX # include #endif #if !defined( TQWS ) && defined( Q_OS_MAC ) # include #endif #if defined (Q_OS_SOLARIS) # include #endif #if defined (Q_OS_OSF) && (defined(__DECC) || defined(__DECCXX)) # define INFINITY DBL_INFINITY # define NAN DBL_QNAN #endif #if (defined(Q_CC_GNU) && defined(Q_OS_WIN)) || __GNUC__ == 4 || defined(QT_QLOCALE_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 double be_neg_nan; static double le_neg_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 bool neg_nan_init = false; static inline double negNan() { if (!neg_nan_init) { memcpy(&be_neg_nan,be_neg_nan_bytes,sizeof(be_neg_nan_bytes)); memcpy(&le_neg_nan,le_neg_nan_bytes,sizeof(le_neg_nan_bytes)); neg_nan_init = true; } return (ByteOrder == BigEndian ? be_neg_nan : le_neg_nan); } // 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 QT_QLOCALE_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, int base, bool *ok); static TQ_ULLONG qstrtoull(const char *nptr, const char **endptr, 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" "DemocraticRepublicOfCongo\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" "DemocraticRepublicOfKorea\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,// DemocraticRepublicOfCongo 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,// DemocraticRepublicOfKorea 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" // DemocraticRepublicOfCongo "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" // DemocraticRepublicOfKorea "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.unicode()[0].unicode(); ushort uc2 = code.unicode()[1].unicode(); 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.unicode()[0].unicode(); ushort uc2 = code.unicode()[1].unicode(); 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::fromLatin1("inf"); } TQString TQLocalePrivate::nan() const { return TQString::fromLatin1("nan"); } #if defined(Q_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 // Q_OS_WIN const char* TQLocalePrivate::systemLocaleName() { static TQCString lang; lang = getenv( "LANG" ); #if !defined( TQWS ) && defined( Q_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(Q_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 { QT_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 *findLocale(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; Q_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 contains 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 DemocraticRepublicOfCongo \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 DemocraticRepublicOfKorea \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.unicode(); 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 = findLocale(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 = findLocale(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 QT_MAX_FLOAT 3.4028234663852886e+38 float TQLocale::toFloat(const TQString &s, bool *ok) const { bool myOk; double d = toDouble(s, &myOk); if (!myOk || d > QT_MAX_FLOAT || d < -QT_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 Q_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().unicode() <= d.unicode() && zero().unicode() + 10 > d.unicode(); } static char digitToCLocale(TQChar zero, TQChar d) { if (zero.unicode() <= d.unicode() && zero.unicode() + 10 > d.unicode()) return '0' + d.unicode() - zero.unicode(); tqWarning("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().unicode() == '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().unicode() + 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 Q_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 QT_QLOCALE_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.unicode()[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 // QT_QLOCALE_USES_FCVT if (zero().unicode() != '0') { for (uint i = 0; i < digits.length(); ++i) digits.ref(i).unicode() += zero().unicode() - '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.unicode() >= '0' && c.unicode() <= '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.unicode()[i]; if (c.unicode() == ',') { // check that there are digits before and after the separator if (i == 0 || !isLatin1Digit(num_str.unicode()[i - 1])) return FALSE; if (i == num_str.length() + 1 || !isLatin1Digit(num_str.unicode()[i + 1])) return FALSE; ++group_cnt; } else if (c.unicode() == '.') { // Fail if more than one decimal points if (decpt_idx != -1) return FALSE; decpt_idx = i; } else if (c.unicode() == 'e' || c.unicode() == '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.unicode()[i]; if (c.unicode() == ',') { // 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.unicode()[i].isSpace()) ++i; if (i > 0) s.remove(0, i); i = s.length(); if (i == 0) return; --i; while (i > 0 && s.unicode()[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().unicode() == 0xA0 && c.unicode() == ' ') c = ','; else if (c == exponential() || c == exponential().upper()) c = 'e'; else if (c == list()) c = ';'; else if (c == percent()) c = '%'; else if (c.unicode() >= 'A' && c.unicode() <= 'Z') c = c.lower(); else if (c.unicode() >= 'a' && c.unicode() <= '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 QT_QLOCALE_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 CONSEQUENTIAL * 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, int base, bool *ok) { const char *s = nptr; TQ_ULLONG acc; unsigned char c; TQ_ULLONG qbase, cutoff; 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, int base, bool *ok) { const char *s; TQ_ULLONG acc; unsigned char c; TQ_ULLONG qbase, cutoff; 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 QT_QLOCALE_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_PRODQUOT 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(Q_OS_WIN) || defined(Q_OS_DARWIN) || defined(Q_OS_MACX) || \ defined(mips) || defined(Q_OS_AIX) || defined(Q_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_QDTOA_DEBUG #include #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(&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(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(&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(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_PRODQUOT #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_QDTOA_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_QDTOA_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_QDTOA_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_QDTOA_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_PRODQUOT && 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_QDTOA_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_QDTOA_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 Q_OS_WIN #ifndef Q_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 Q_OS_LINUX fenv_t envp; feholdexcept(&envp); #endif char *s = _qdtoa(d, mode, ndigits, decpt, sign, rve, resultp); #ifdef Q_OS_WIN #ifndef Q_CC_BOR _clear87(); #ifndef _M_X64 _control87(oldbits, 0xFFFFF); #else _control87(oldbits, _MCW_DN|_MCW_EM|_MCW_RC); #endif //_M_X64 #endif #endif #ifdef Q_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 // QT_QLOCALE_USES_FCVT