You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
6323 lines
159 KiB
6323 lines
159 KiB
/****************************************************************************
|
|
**
|
|
** 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 <sys/types.h>
|
|
#include <ctype.h>
|
|
#include <float.h>
|
|
#include <limits.h>
|
|
#include <math.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "ntqlocale.h"
|
|
#include "qlocale_p.h"
|
|
#include "ntqnamespace.h"
|
|
|
|
#ifdef QT_QLOCALE_USES_FCVT
|
|
# include <ntqmutex.h>
|
|
# include <private/qmutexpool_p.h>
|
|
#endif
|
|
|
|
#if defined (Q_OS_WIN)
|
|
# include <windows.h>
|
|
# undef NAN // we want to use our fallback on Windows
|
|
# undef INFINITY
|
|
#endif
|
|
|
|
#ifdef Q_OS_LINUX
|
|
# include <fenv.h>
|
|
#endif
|
|
|
|
#if !defined( TQWS ) && defined( Q_OS_MAC )
|
|
# include <Carbon/Carbon.h>
|
|
#endif
|
|
|
|
#if defined (Q_OS_SOLARIS)
|
|
# include <ieeefp.h>
|
|
#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 Q_BYTE_ORDER
|
|
# if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
|
, ByteOrder = BigEndian
|
|
# elif Q_BYTE_ORDER == Q_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, register int base, bool *ok);
|
|
static TQ_ULLONG qstrtoull(const char *nptr, const char **endptr, register int base, bool *ok);
|
|
|
|
static inline bool compareBits(double d1, double d2)
|
|
{
|
|
return memcmp((const char*)&d1, (const char*)&d2, sizeof(double)) == 0;
|
|
}
|
|
|
|
static inline bool qIsInf(double d)
|
|
{
|
|
return compareBits(d, INFINITY) || compareBits(d, -INFINITY);
|
|
}
|
|
|
|
static inline bool qIsNan(double d)
|
|
{
|
|
return compareBits(d, NAN) || compareBits(d, negNan());
|
|
}
|
|
|
|
static const uint locale_index[] = {
|
|
0, // unused
|
|
0, // C
|
|
0, // Abkhazian
|
|
0, // Afan
|
|
0, // Afar
|
|
1, // Afrikaans
|
|
2, // Albanian
|
|
0, // Amharic
|
|
3, // Arabic
|
|
19, // Armenian
|
|
0, // Assamese
|
|
0, // Aymara
|
|
20, // Azerbaijani
|
|
0, // Bashkir
|
|
21, // Basque
|
|
22, // Bengali
|
|
0, // Bhutani
|
|
0, // Bihari
|
|
0, // Bislama
|
|
0, // Breton
|
|
23, // Bulgarian
|
|
0, // Burmese
|
|
24, // Byelorussian
|
|
0, // Cambodian
|
|
25, // Catalan
|
|
26, // Chinese
|
|
0, // Corsican
|
|
31, // Croatian
|
|
32, // Czech
|
|
33, // Danish
|
|
34, // Dutch
|
|
36, // English
|
|
0, // Esperanto
|
|
48, // Estonian
|
|
49, // Faroese
|
|
0, // Fiji
|
|
50, // Finnish
|
|
51, // French
|
|
0, // Frisian
|
|
0, // Gaelic
|
|
57, // Galician
|
|
58, // Georgian
|
|
59, // German
|
|
64, // Greek
|
|
0, // Greenlandic
|
|
0, // Guarani
|
|
65, // Gujarati
|
|
0, // Hausa
|
|
66, // Hebrew
|
|
67, // Hindi
|
|
68, // Hungarian
|
|
69, // Icelandic
|
|
70, // Indonesian
|
|
0, // Interlingua
|
|
0, // Interlingue
|
|
0, // Inuktitut
|
|
0, // Inupiak
|
|
0, // Irish
|
|
71, // Italian
|
|
73, // Japanese
|
|
0, // Javanese
|
|
74, // Kannada
|
|
0, // Kashmiri
|
|
75, // Kazakh
|
|
0, // Kinyarwanda
|
|
76, // Kirghiz
|
|
77, // Korean
|
|
0, // Kurdish
|
|
0, // Kurundi
|
|
0, // Laothian
|
|
0, // Latin
|
|
78, // Latvian
|
|
0, // Lingala
|
|
79, // Lithuanian
|
|
80, // Macedonian
|
|
0, // Malagasy
|
|
81, // Malay
|
|
0, // Malayalam
|
|
0, // Maltese
|
|
0, // Maori
|
|
83, // Marathi
|
|
0, // Moldavian
|
|
84, // Mongolian
|
|
0, // Nauru
|
|
0, // Nepali
|
|
85, // Norwegian
|
|
0, // Occitan
|
|
0, // Oriya
|
|
0, // Pashto
|
|
86, // Persian
|
|
87, // Polish
|
|
88, // Portuguese
|
|
90, // Punjabi
|
|
0, // Quechua
|
|
0, // RhaetoRomance
|
|
91, // Romanian
|
|
92, // Russian
|
|
0, // Samoan
|
|
0, // Sangho
|
|
93, // Sanskrit
|
|
0, // Serbian
|
|
0, // SerboCroatian
|
|
0, // Sesotho
|
|
0, // Setswana
|
|
0, // Shona
|
|
0, // Sindhi
|
|
0, // Singhalese
|
|
0, // Siswati
|
|
94, // Slovak
|
|
95, // Slovenian
|
|
0, // Somali
|
|
96, // Spanish
|
|
0, // Sundanese
|
|
115, // Swahili
|
|
116, // Swedish
|
|
0, // Tagalog
|
|
0, // Tajik
|
|
118, // Tamil
|
|
0, // Tatar
|
|
119, // Telugu
|
|
120, // Thai
|
|
0, // Tibetan
|
|
0, // Tigrinya
|
|
0, // Tonga
|
|
0, // Tsonga
|
|
121, // Turkish
|
|
0, // Turkmen
|
|
0, // Twi
|
|
0, // Uigur
|
|
122, // Ukrainian
|
|
123, // Urdu
|
|
124, // Uzbek
|
|
125, // Vietnamese
|
|
0, // Volapuk
|
|
0, // Welsh
|
|
0, // Wolof
|
|
0, // Xhosa
|
|
0, // Yiddish
|
|
0, // Yoruba
|
|
0, // Zhuang
|
|
0, // Zulu
|
|
0 // trailing 0
|
|
};
|
|
|
|
static const TQLocalePrivate locale_data[] = {
|
|
// lang terr dec group list prcnt zero minus exp
|
|
{ 1, 0, 46, 44, 59, 37, 48, 45, 101 }, // C/AnyCountry
|
|
{ 5, 195, 46, 44, 44, 37, 48, 45, 101 }, // Afrikaans/SouthAfrica
|
|
{ 6, 2, 44, 46, 59, 37, 48, 45, 101 }, // Albanian/Albania
|
|
{ 8, 186, 46, 44, 59, 37, 1632, 45, 101 }, // Arabic/SaudiArabia
|
|
{ 8, 3, 46, 44, 59, 37, 48, 45, 101 }, // Arabic/Algeria
|
|
{ 8, 17, 46, 44, 59, 37, 1632, 45, 101 }, // Arabic/Bahrain
|
|
{ 8, 64, 46, 44, 59, 37, 1632, 45, 101 }, // Arabic/Egypt
|
|
{ 8, 103, 46, 44, 59, 37, 1632, 45, 101 }, // Arabic/Iraq
|
|
{ 8, 109, 46, 44, 59, 37, 1632, 45, 101 }, // Arabic/Jordan
|
|
{ 8, 115, 46, 44, 59, 37, 1632, 45, 101 }, // Arabic/Kuwait
|
|
{ 8, 119, 46, 44, 59, 37, 1632, 45, 101 }, // Arabic/Lebanon
|
|
{ 8, 122, 46, 44, 59, 37, 48, 45, 101 }, // Arabic/LibyanArabJamahiriya
|
|
{ 8, 145, 46, 44, 59, 37, 48, 45, 101 }, // Arabic/Morocco
|
|
{ 8, 162, 46, 44, 59, 37, 1632, 45, 101 }, // Arabic/Oman
|
|
{ 8, 175, 46, 44, 59, 37, 1632, 45, 101 }, // Arabic/Qatar
|
|
{ 8, 207, 46, 44, 59, 37, 1632, 45, 101 }, // Arabic/SyrianArabRepublic
|
|
{ 8, 216, 46, 44, 59, 37, 48, 45, 101 }, // Arabic/Tunisia
|
|
{ 8, 223, 46, 44, 59, 37, 1632, 45, 101 }, // Arabic/UnitedArabEmirates
|
|
{ 8, 237, 46, 44, 59, 37, 1632, 45, 101 }, // Arabic/Yemen
|
|
{ 9, 11, 46, 44, 44, 37, 48, 45, 101 }, // Armenian/Armenia
|
|
{ 12, 15, 44, 160, 59, 37, 48, 45, 101 }, // Azerbaijani/Azerbaijan
|
|
{ 14, 197, 44, 46, 59, 37, 48, 45, 101 }, // Basque/Spain
|
|
{ 15, 100, 46, 44, 59, 37, 48, 45, 101 }, // Bengali/India
|
|
{ 20, 33, 44, 160, 59, 37, 48, 45, 101 }, // Bulgarian/Bulgaria
|
|
{ 22, 20, 44, 160, 59, 37, 48, 45, 101 }, // Byelorussian/Belarus
|
|
{ 24, 197, 44, 46, 59, 37, 48, 45, 101 }, // Catalan/Spain
|
|
{ 25, 44, 46, 44, 44, 37, 48, 45, 101 }, // Chinese/China
|
|
{ 25, 97, 46, 44, 44, 37, 48, 45, 101 }, // Chinese/HongKong
|
|
{ 25, 126, 46, 44, 44, 37, 48, 45, 101 }, // Chinese/Macau
|
|
{ 25, 190, 46, 44, 44, 37, 48, 45, 101 }, // Chinese/Singapore
|
|
{ 25, 208, 46, 44, 44, 37, 48, 45, 101 }, // Chinese/Taiwan
|
|
{ 27, 54, 44, 46, 59, 37, 48, 45, 101 }, // Croatian/Croatia
|
|
{ 28, 57, 44, 160, 59, 37, 48, 45, 101 }, // Czech/CzechRepublic
|
|
{ 29, 58, 44, 46, 59, 37, 48, 45, 101 }, // Danish/Denmark
|
|
{ 30, 151, 44, 46, 59, 37, 48, 45, 101 }, // Dutch/Netherlands
|
|
{ 30, 21, 44, 46, 59, 37, 48, 45, 101 }, // Dutch/Belgium
|
|
{ 31, 225, 46, 44, 44, 37, 48, 45, 101 }, // English/UnitedStates
|
|
{ 31, 13, 46, 44, 44, 37, 48, 45, 101 }, // English/Australia
|
|
{ 31, 22, 46, 44, 59, 37, 48, 45, 101 }, // English/Belize
|
|
{ 31, 38, 46, 44, 44, 37, 48, 45, 101 }, // English/Canada
|
|
{ 31, 104, 46, 44, 44, 37, 48, 45, 101 }, // English/Ireland
|
|
{ 31, 107, 46, 44, 44, 37, 48, 45, 101 }, // English/Jamaica
|
|
{ 31, 154, 46, 44, 44, 37, 48, 45, 101 }, // English/NewZealand
|
|
{ 31, 170, 46, 44, 44, 37, 48, 45, 101 }, // English/Philippines
|
|
{ 31, 195, 46, 44, 44, 37, 48, 45, 101 }, // English/SouthAfrica
|
|
{ 31, 215, 46, 44, 59, 37, 48, 45, 101 }, // English/TrinidadAndTobago
|
|
{ 31, 224, 46, 44, 44, 37, 48, 45, 101 }, // English/UnitedKingdom
|
|
{ 31, 240, 46, 44, 44, 37, 48, 45, 101 }, // English/Zimbabwe
|
|
{ 33, 68, 44, 160, 59, 37, 48, 45, 101 }, // Estonian/Estonia
|
|
{ 34, 71, 44, 46, 59, 37, 48, 45, 101 }, // Faroese/FaroeIslands
|
|
{ 36, 73, 44, 160, 59, 37, 48, 45, 101 }, // Finnish/Finland
|
|
{ 37, 74, 44, 160, 59, 37, 48, 45, 101 }, // French/France
|
|
{ 37, 21, 44, 46, 59, 37, 48, 45, 101 }, // French/Belgium
|
|
{ 37, 38, 44, 160, 59, 37, 48, 45, 101 }, // French/Canada
|
|
{ 37, 125, 44, 160, 59, 37, 48, 45, 101 }, // French/Luxembourg
|
|
{ 37, 142, 44, 160, 59, 37, 48, 45, 101 }, // French/Monaco
|
|
{ 37, 206, 46, 39, 59, 37, 48, 45, 101 }, // French/Switzerland
|
|
{ 40, 197, 44, 46, 44, 37, 48, 45, 101 }, // Galician/Spain
|
|
{ 41, 81, 44, 160, 59, 37, 48, 45, 101 }, // Georgian/Georgia
|
|
{ 42, 82, 44, 46, 59, 37, 48, 45, 101 }, // German/Germany
|
|
{ 42, 14, 44, 46, 59, 37, 48, 45, 101 }, // German/Austria
|
|
{ 42, 123, 46, 39, 59, 37, 48, 45, 101 }, // German/Liechtenstein
|
|
{ 42, 125, 44, 46, 59, 37, 48, 45, 101 }, // German/Luxembourg
|
|
{ 42, 206, 46, 39, 59, 37, 48, 45, 101 }, // German/Switzerland
|
|
{ 43, 85, 44, 46, 59, 37, 48, 45, 101 }, // Greek/Greece
|
|
{ 46, 100, 46, 44, 44, 37, 2790, 45, 101 }, // Gujarati/India
|
|
{ 48, 105, 46, 44, 44, 37, 48, 45, 101 }, // Hebrew/Israel
|
|
{ 49, 100, 46, 44, 44, 37, 48, 45, 101 }, // Hindi/India
|
|
{ 50, 98, 44, 160, 59, 37, 48, 45, 101 }, // Hungarian/Hungary
|
|
{ 51, 99, 44, 46, 59, 37, 48, 45, 101 }, // Icelandic/Iceland
|
|
{ 52, 101, 44, 46, 59, 37, 48, 45, 101 }, // Indonesian/Indonesia
|
|
{ 58, 106, 44, 46, 59, 37, 48, 45, 101 }, // Italian/Italy
|
|
{ 58, 206, 46, 39, 59, 37, 48, 45, 101 }, // Italian/Switzerland
|
|
{ 59, 108, 46, 44, 44, 37, 48, 45, 101 }, // Japanese/Japan
|
|
{ 61, 100, 46, 44, 44, 37, 3302, 45, 101 }, // Kannada/India
|
|
{ 63, 110, 44, 160, 59, 37, 48, 45, 101 }, // Kazakh/Kazakhstan
|
|
{ 65, 116, 44, 160, 59, 37, 48, 45, 101 }, // Kirghiz/Kyrgyzstan
|
|
{ 66, 114, 46, 44, 44, 37, 48, 45, 101 }, // Korean/RepublicOfKorea
|
|
{ 71, 118, 44, 160, 59, 37, 48, 45, 101 }, // Latvian/Latvia
|
|
{ 73, 124, 44, 46, 59, 37, 48, 45, 101 }, // Lithuanian/Lithuania
|
|
{ 74, 127, 44, 46, 59, 37, 48, 45, 101 }, // Macedonian/Macedonia
|
|
{ 76, 130, 44, 46, 59, 37, 48, 45, 101 }, // Malay/Malaysia
|
|
{ 76, 32, 44, 46, 59, 37, 48, 45, 101 }, // Malay/BruneiDarussalam
|
|
{ 80, 100, 46, 44, 44, 37, 2406, 45, 101 }, // Marathi/India
|
|
{ 82, 143, 44, 160, 59, 37, 48, 45, 101 }, // Mongolian/Mongolia
|
|
{ 85, 161, 44, 160, 59, 37, 48, 45, 101 }, // Norwegian/Norway
|
|
{ 89, 102, 46, 44, 59, 37, 1776, 45, 101 }, // Persian/Iran
|
|
{ 90, 172, 44, 160, 59, 37, 48, 45, 101 }, // Polish/Poland
|
|
{ 91, 173, 44, 46, 59, 37, 48, 45, 101 }, // Portuguese/Portugal
|
|
{ 91, 30, 44, 46, 59, 37, 48, 45, 101 }, // Portuguese/Brazil
|
|
{ 92, 100, 46, 44, 44, 37, 2662, 45, 101 }, // Punjabi/India
|
|
{ 95, 177, 44, 46, 59, 37, 48, 45, 101 }, // Romanian/Romania
|
|
{ 96, 178, 44, 160, 59, 37, 48, 45, 101 }, // Russian/RussianFederation
|
|
{ 99, 100, 46, 44, 44, 37, 2406, 45, 101 }, // Sanskrit/India
|
|
{ 108, 191, 44, 160, 59, 37, 48, 45, 101 }, // Slovak/Slovakia
|
|
{ 109, 192, 44, 46, 59, 37, 48, 45, 101 }, // Slovenian/Slovenia
|
|
{ 111, 197, 44, 46, 59, 37, 48, 45, 101 }, // Spanish/Spain
|
|
{ 111, 10, 44, 46, 44, 37, 48, 45, 101 }, // Spanish/Argentina
|
|
{ 111, 26, 44, 46, 44, 37, 48, 45, 101 }, // Spanish/Bolivia
|
|
{ 111, 43, 44, 46, 44, 37, 48, 45, 101 }, // Spanish/Chile
|
|
{ 111, 47, 44, 46, 44, 37, 48, 45, 101 }, // Spanish/Colombia
|
|
{ 111, 52, 44, 46, 44, 37, 48, 45, 101 }, // Spanish/CostaRica
|
|
{ 111, 61, 46, 44, 44, 37, 48, 45, 101 }, // Spanish/DominicanRepublic
|
|
{ 111, 63, 44, 46, 44, 37, 48, 45, 101 }, // Spanish/Ecuador
|
|
{ 111, 65, 46, 44, 44, 37, 48, 45, 101 }, // Spanish/ElSalvador
|
|
{ 111, 90, 46, 44, 44, 37, 48, 45, 101 }, // Spanish/Guatemala
|
|
{ 111, 96, 46, 44, 44, 37, 48, 45, 101 }, // Spanish/Honduras
|
|
{ 111, 139, 46, 44, 44, 37, 48, 45, 101 }, // Spanish/Mexico
|
|
{ 111, 155, 46, 44, 44, 37, 48, 45, 101 }, // Spanish/Nicaragua
|
|
{ 111, 166, 46, 44, 44, 37, 48, 45, 101 }, // Spanish/Panama
|
|
{ 111, 168, 44, 46, 44, 37, 48, 45, 101 }, // Spanish/Paraguay
|
|
{ 111, 169, 46, 44, 44, 37, 48, 45, 101 }, // Spanish/Peru
|
|
{ 111, 174, 46, 44, 44, 37, 48, 45, 101 }, // Spanish/PuertoRico
|
|
{ 111, 227, 44, 46, 44, 37, 48, 45, 101 }, // Spanish/Uruguay
|
|
{ 111, 231, 44, 46, 44, 37, 48, 45, 101 }, // Spanish/Venezuela
|
|
{ 113, 111, 46, 44, 44, 37, 48, 45, 101 }, // Swahili/Kenya
|
|
{ 114, 205, 44, 160, 59, 37, 48, 45, 101 }, // Swedish/Sweden
|
|
{ 114, 73, 44, 160, 59, 37, 48, 45, 101 }, // Swedish/Finland
|
|
{ 117, 100, 46, 44, 44, 37, 48, 45, 101 }, // Tamil/India
|
|
{ 119, 100, 46, 44, 44, 37, 3174, 45, 101 }, // Telugu/India
|
|
{ 120, 211, 46, 44, 44, 37, 3664, 45, 101 }, // Thai/Thailand
|
|
{ 125, 217, 44, 46, 59, 37, 48, 45, 101 }, // Turkish/Turkey
|
|
{ 129, 222, 44, 160, 59, 37, 48, 45, 101 }, // Ukrainian/Ukraine
|
|
{ 130, 163, 46, 44, 59, 37, 1776, 45, 101 }, // Urdu/Pakistan
|
|
{ 131, 228, 44, 160, 59, 37, 48, 45, 101 }, // Uzbek/Uzbekistan
|
|
{ 132, 232, 44, 46, 44, 37, 48, 45, 101 }, // Vietnamese/VietNam
|
|
{ 0, 0, 0, 0, 0, 0, 0, 0, 0 } // trailing 0s
|
|
};
|
|
|
|
static const char language_name_list[] =
|
|
"Default\0"
|
|
"C\0"
|
|
"Abkhazian\0"
|
|
"Afan\0"
|
|
"Afar\0"
|
|
"Afrikaans\0"
|
|
"Albanian\0"
|
|
"Amharic\0"
|
|
"Arabic\0"
|
|
"Armenian\0"
|
|
"Assamese\0"
|
|
"Aymara\0"
|
|
"Azerbaijani\0"
|
|
"Bashkir\0"
|
|
"Basque\0"
|
|
"Bengali\0"
|
|
"Bhutani\0"
|
|
"Bihari\0"
|
|
"Bislama\0"
|
|
"Breton\0"
|
|
"Bulgarian\0"
|
|
"Burmese\0"
|
|
"Byelorussian\0"
|
|
"Cambodian\0"
|
|
"Catalan\0"
|
|
"Chinese\0"
|
|
"Corsican\0"
|
|
"Croatian\0"
|
|
"Czech\0"
|
|
"Danish\0"
|
|
"Dutch\0"
|
|
"English\0"
|
|
"Esperanto\0"
|
|
"Estonian\0"
|
|
"Faroese\0"
|
|
"Fiji\0"
|
|
"Finnish\0"
|
|
"French\0"
|
|
"Frisian\0"
|
|
"Gaelic\0"
|
|
"Galician\0"
|
|
"Georgian\0"
|
|
"German\0"
|
|
"Greek\0"
|
|
"Greenlandic\0"
|
|
"Guarani\0"
|
|
"Gujarati\0"
|
|
"Hausa\0"
|
|
"Hebrew\0"
|
|
"Hindi\0"
|
|
"Hungarian\0"
|
|
"Icelandic\0"
|
|
"Indonesian\0"
|
|
"Interlingua\0"
|
|
"Interlingue\0"
|
|
"Inuktitut\0"
|
|
"Inupiak\0"
|
|
"Irish\0"
|
|
"Italian\0"
|
|
"Japanese\0"
|
|
"Javanese\0"
|
|
"Kannada\0"
|
|
"Kashmiri\0"
|
|
"Kazakh\0"
|
|
"Kinyarwanda\0"
|
|
"Kirghiz\0"
|
|
"Korean\0"
|
|
"Kurdish\0"
|
|
"Kurundi\0"
|
|
"Laothian\0"
|
|
"Latin\0"
|
|
"Latvian\0"
|
|
"Lingala\0"
|
|
"Lithuanian\0"
|
|
"Macedonian\0"
|
|
"Malagasy\0"
|
|
"Malay\0"
|
|
"Malayalam\0"
|
|
"Maltese\0"
|
|
"Maori\0"
|
|
"Marathi\0"
|
|
"Moldavian\0"
|
|
"Mongolian\0"
|
|
"Nauru\0"
|
|
"Nepali\0"
|
|
"Norwegian\0"
|
|
"Occitan\0"
|
|
"Oriya\0"
|
|
"Pashto\0"
|
|
"Persian\0"
|
|
"Polish\0"
|
|
"Portuguese\0"
|
|
"Punjabi\0"
|
|
"Quechua\0"
|
|
"RhaetoRomance\0"
|
|
"Romanian\0"
|
|
"Russian\0"
|
|
"Samoan\0"
|
|
"Sangho\0"
|
|
"Sanskrit\0"
|
|
"Serbian\0"
|
|
"SerboCroatian\0"
|
|
"Sesotho\0"
|
|
"Setswana\0"
|
|
"Shona\0"
|
|
"Sindhi\0"
|
|
"Singhalese\0"
|
|
"Siswati\0"
|
|
"Slovak\0"
|
|
"Slovenian\0"
|
|
"Somali\0"
|
|
"Spanish\0"
|
|
"Sundanese\0"
|
|
"Swahili\0"
|
|
"Swedish\0"
|
|
"Tagalog\0"
|
|
"Tajik\0"
|
|
"Tamil\0"
|
|
"Tatar\0"
|
|
"Telugu\0"
|
|
"Thai\0"
|
|
"Tibetan\0"
|
|
"Tigrinya\0"
|
|
"Tonga\0"
|
|
"Tsonga\0"
|
|
"Turkish\0"
|
|
"Turkmen\0"
|
|
"Twi\0"
|
|
"Uigur\0"
|
|
"Ukrainian\0"
|
|
"Urdu\0"
|
|
"Uzbek\0"
|
|
"Vietnamese\0"
|
|
"Volapuk\0"
|
|
"Welsh\0"
|
|
"Wolof\0"
|
|
"Xhosa\0"
|
|
"Yiddish\0"
|
|
"Yoruba\0"
|
|
"Zhuang\0"
|
|
"Zulu\0";
|
|
|
|
static const uint language_name_index[] = {
|
|
0,// Unused
|
|
8,// C
|
|
10,// Abkhazian
|
|
20,// Afan
|
|
25,// Afar
|
|
30,// Afrikaans
|
|
40,// Albanian
|
|
49,// Amharic
|
|
57,// Arabic
|
|
64,// Armenian
|
|
73,// Assamese
|
|
82,// Aymara
|
|
89,// Azerbaijani
|
|
101,// Bashkir
|
|
109,// Basque
|
|
116,// Bengali
|
|
124,// Bhutani
|
|
132,// Bihari
|
|
139,// Bislama
|
|
147,// Breton
|
|
154,// Bulgarian
|
|
164,// Burmese
|
|
172,// Byelorussian
|
|
185,// Cambodian
|
|
195,// Catalan
|
|
203,// Chinese
|
|
211,// Corsican
|
|
220,// Croatian
|
|
229,// Czech
|
|
235,// Danish
|
|
242,// Dutch
|
|
248,// English
|
|
256,// Esperanto
|
|
266,// Estonian
|
|
275,// Faroese
|
|
283,// Fiji
|
|
288,// Finnish
|
|
296,// French
|
|
303,// Frisian
|
|
311,// Gaelic
|
|
318,// Galician
|
|
327,// Georgian
|
|
336,// German
|
|
343,// Greek
|
|
349,// Greenlandic
|
|
361,// Guarani
|
|
369,// Gujarati
|
|
378,// Hausa
|
|
384,// Hebrew
|
|
391,// Hindi
|
|
397,// Hungarian
|
|
407,// Icelandic
|
|
417,// Indonesian
|
|
428,// Interlingua
|
|
440,// Interlingue
|
|
452,// Inuktitut
|
|
462,// Inupiak
|
|
470,// Irish
|
|
476,// Italian
|
|
484,// Japanese
|
|
493,// Javanese
|
|
502,// Kannada
|
|
510,// Kashmiri
|
|
519,// Kazakh
|
|
526,// Kinyarwanda
|
|
538,// Kirghiz
|
|
546,// Korean
|
|
553,// Kurdish
|
|
561,// Kurundi
|
|
569,// Laothian
|
|
578,// Latin
|
|
584,// Latvian
|
|
592,// Lingala
|
|
600,// Lithuanian
|
|
611,// Macedonian
|
|
622,// Malagasy
|
|
631,// Malay
|
|
637,// Malayalam
|
|
647,// Maltese
|
|
655,// Maori
|
|
661,// Marathi
|
|
669,// Moldavian
|
|
679,// Mongolian
|
|
689,// Nauru
|
|
695,// Nepali
|
|
702,// Norwegian
|
|
712,// Occitan
|
|
720,// Oriya
|
|
726,// Pashto
|
|
733,// Persian
|
|
741,// Polish
|
|
748,// Portuguese
|
|
759,// Punjabi
|
|
767,// Quechua
|
|
775,// RhaetoRomance
|
|
789,// Romanian
|
|
798,// Russian
|
|
806,// Samoan
|
|
813,// Sangho
|
|
820,// Sanskrit
|
|
829,// Serbian
|
|
837,// SerboCroatian
|
|
851,// Sesotho
|
|
859,// Setswana
|
|
868,// Shona
|
|
874,// Sindhi
|
|
881,// Singhalese
|
|
892,// Siswati
|
|
900,// Slovak
|
|
907,// Slovenian
|
|
917,// Somali
|
|
924,// Spanish
|
|
932,// Sundanese
|
|
942,// Swahili
|
|
950,// Swedish
|
|
958,// Tagalog
|
|
966,// Tajik
|
|
972,// Tamil
|
|
978,// Tatar
|
|
984,// Telugu
|
|
991,// Thai
|
|
996,// Tibetan
|
|
1004,// Tigrinya
|
|
1013,// Tonga
|
|
1019,// Tsonga
|
|
1026,// Turkish
|
|
1034,// Turkmen
|
|
1042,// Twi
|
|
1046,// Uigur
|
|
1052,// Ukrainian
|
|
1062,// Urdu
|
|
1067,// Uzbek
|
|
1073,// Vietnamese
|
|
1084,// Volapuk
|
|
1092,// Welsh
|
|
1098,// Wolof
|
|
1104,// Xhosa
|
|
1110,// Yiddish
|
|
1118,// Yoruba
|
|
1125,// Zhuang
|
|
1132// Zulu
|
|
};
|
|
|
|
static const char country_name_list[] =
|
|
"Default\0"
|
|
"Afghanistan\0"
|
|
"Albania\0"
|
|
"Algeria\0"
|
|
"AmericanSamoa\0"
|
|
"Andorra\0"
|
|
"Angola\0"
|
|
"Anguilla\0"
|
|
"Antarctica\0"
|
|
"AntiguaAndBarbuda\0"
|
|
"Argentina\0"
|
|
"Armenia\0"
|
|
"Aruba\0"
|
|
"Australia\0"
|
|
"Austria\0"
|
|
"Azerbaijan\0"
|
|
"Bahamas\0"
|
|
"Bahrain\0"
|
|
"Bangladesh\0"
|
|
"Barbados\0"
|
|
"Belarus\0"
|
|
"Belgium\0"
|
|
"Belize\0"
|
|
"Benin\0"
|
|
"Bermuda\0"
|
|
"Bhutan\0"
|
|
"Bolivia\0"
|
|
"BosniaAndHerzegowina\0"
|
|
"Botswana\0"
|
|
"BouvetIsland\0"
|
|
"Brazil\0"
|
|
"BritishIndianOceanTerritory\0"
|
|
"BruneiDarussalam\0"
|
|
"Bulgaria\0"
|
|
"BurkinaFaso\0"
|
|
"Burundi\0"
|
|
"Cambodia\0"
|
|
"Cameroon\0"
|
|
"Canada\0"
|
|
"CapeVerde\0"
|
|
"CaymanIslands\0"
|
|
"CentralAfricanRepublic\0"
|
|
"Chad\0"
|
|
"Chile\0"
|
|
"China\0"
|
|
"ChristmasIsland\0"
|
|
"CocosIslands\0"
|
|
"Colombia\0"
|
|
"Comoros\0"
|
|
"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 QT_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, register int base, bool *ok)
|
|
{
|
|
register const char *s = nptr;
|
|
register TQ_ULLONG acc;
|
|
register unsigned char c;
|
|
register TQ_ULLONG qbase, cutoff;
|
|
register int neg, any, cutlim;
|
|
|
|
if (ok != 0)
|
|
*ok = TRUE;
|
|
|
|
/*
|
|
* See strtoq for comments as to the logic used.
|
|
*/
|
|
s = nptr;
|
|
do {
|
|
c = *s++;
|
|
} while (isspace(c));
|
|
if (c == '-') {
|
|
if (ok != 0)
|
|
*ok = FALSE;
|
|
if (endptr != 0)
|
|
*endptr = s - 1;
|
|
return 0;
|
|
} else {
|
|
neg = 0;
|
|
if (c == '+')
|
|
c = *s++;
|
|
}
|
|
if ((base == 0 || base == 16) &&
|
|
c == '0' && (*s == 'x' || *s == 'X')) {
|
|
c = s[1];
|
|
s += 2;
|
|
base = 16;
|
|
}
|
|
if (base == 0)
|
|
base = c == '0' ? 8 : 10;
|
|
qbase = (unsigned)base;
|
|
cutoff = (TQ_ULLONG)ULLONG_MAX / qbase;
|
|
cutlim = (TQ_ULLONG)ULLONG_MAX % qbase;
|
|
for (acc = 0, any = 0;; c = *s++) {
|
|
if (!isascii(c))
|
|
break;
|
|
if (isdigit(c))
|
|
c -= '0';
|
|
else if (isalpha(c))
|
|
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
|
|
else
|
|
break;
|
|
if (c >= base)
|
|
break;
|
|
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
|
|
any = -1;
|
|
else {
|
|
any = 1;
|
|
acc *= qbase;
|
|
acc += c;
|
|
}
|
|
}
|
|
if (any < 0) {
|
|
acc = ULLONG_MAX;
|
|
if (ok != 0)
|
|
*ok = FALSE;
|
|
}
|
|
else if (neg)
|
|
acc = (~acc) + 1;
|
|
if (endptr != 0)
|
|
*endptr = (char *)(any ? s - 1 : nptr);
|
|
return (acc);
|
|
}
|
|
|
|
|
|
// "$FreeBSD: src/lib/libc/stdlib/strtoll.c,v 1.5.2.1 2001/03/02 09:45:20 obrien Exp $";
|
|
|
|
|
|
/*
|
|
* Convert a string to a TQ_LLONG integer.
|
|
*
|
|
* Ignores `locale' stuff. Assumes that the upper and lower case
|
|
* alphabets and digits are each contiguous.
|
|
*/
|
|
static TQ_LLONG qstrtoll(const char *nptr, const char **endptr, register int base, bool *ok)
|
|
{
|
|
register const char *s;
|
|
register TQ_ULLONG acc;
|
|
register unsigned char c;
|
|
register TQ_ULLONG qbase, cutoff;
|
|
register int neg, any, cutlim;
|
|
|
|
if (ok != 0)
|
|
*ok = TRUE;
|
|
|
|
/*
|
|
* Skip white space and pick up leading +/- sign if any.
|
|
* If base is 0, allow 0x for hex and 0 for octal, else
|
|
* assume decimal; if base is already 16, allow 0x.
|
|
*/
|
|
s = nptr;
|
|
do {
|
|
c = *s++;
|
|
} while (isspace(c));
|
|
if (c == '-') {
|
|
neg = 1;
|
|
c = *s++;
|
|
} else {
|
|
neg = 0;
|
|
if (c == '+')
|
|
c = *s++;
|
|
}
|
|
if ((base == 0 || base == 16) &&
|
|
c == '0' && (*s == 'x' || *s == 'X')) {
|
|
c = s[1];
|
|
s += 2;
|
|
base = 16;
|
|
}
|
|
if (base == 0)
|
|
base = c == '0' ? 8 : 10;
|
|
|
|
/*
|
|
* Compute the cutoff value between legal numbers and illegal
|
|
* numbers. That is the largest legal value, divided by the
|
|
* base. An input number that is greater than this value, if
|
|
* followed by a legal input character, is too big. One that
|
|
* is equal to this value may be valid or not; the limit
|
|
* between valid and invalid numbers is then based on the last
|
|
* digit. For instance, if the range for quads is
|
|
* [-9223372036854775808..9223372036854775807] and the input base
|
|
* is 10, cutoff will be set to 922337203685477580 and cutlim to
|
|
* either 7 (neg==0) or 8 (neg==1), meaning that if we have
|
|
* accumulated a value > 922337203685477580, or equal but the
|
|
* next digit is > 7 (or 8), the number is too big, and we will
|
|
* return a range error.
|
|
*
|
|
* Set any if any `digits' consumed; make it negative to indicate
|
|
* overflow.
|
|
*/
|
|
qbase = (unsigned)base;
|
|
cutoff = neg ? (TQ_ULLONG)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX
|
|
: LLONG_MAX;
|
|
cutlim = cutoff % qbase;
|
|
cutoff /= qbase;
|
|
for (acc = 0, any = 0;; c = *s++) {
|
|
if (!isascii(c))
|
|
break;
|
|
if (isdigit(c))
|
|
c -= '0';
|
|
else if (isalpha(c))
|
|
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
|
|
else
|
|
break;
|
|
if (c >= base)
|
|
break;
|
|
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
|
|
any = -1;
|
|
else {
|
|
any = 1;
|
|
acc *= qbase;
|
|
acc += c;
|
|
}
|
|
}
|
|
if (any < 0) {
|
|
acc = neg ? LLONG_MIN : LLONG_MAX;
|
|
if (ok != 0)
|
|
*ok = FALSE;
|
|
} else if (neg) {
|
|
acc = (~acc) + 1;
|
|
}
|
|
if (endptr != 0)
|
|
*endptr = (char *)(any ? s - 1 : nptr);
|
|
return (acc);
|
|
}
|
|
|
|
#ifndef 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 <stdio.h>
|
|
#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);}
|
|
#endif
|
|
|
|
#ifdef Unsigned_Shifts
|
|
#define Sign_Extend(a,b) if (b < 0) a |= 0xffff0000;
|
|
#else
|
|
#define Sign_Extend(a,b) /*no-op*/
|
|
#endif
|
|
|
|
#if (defined(IEEE_BIG_OR_LITTLE_ENDIAN) + defined(VAX) + defined(IBM)) != 1
|
|
#error Exactly one of IEEE_BIG_OR_LITTLE_ENDIAN, VAX, or IBM should be defined.
|
|
#endif
|
|
|
|
inline ULong getWord0(const NEEDS_VOLATILE double x)
|
|
{
|
|
const NEEDS_VOLATILE uchar *ptr = reinterpret_cast<const NEEDS_VOLATILE uchar *>(&x);
|
|
if (ByteOrder == BigEndian) {
|
|
return (ptr[0]<<24) + (ptr[1]<<16) + (ptr[2]<<8) + ptr[3];
|
|
} else {
|
|
return (ptr[7]<<24) + (ptr[6]<<16) + (ptr[5]<<8) + ptr[4];
|
|
}
|
|
}
|
|
|
|
inline void setWord0(NEEDS_VOLATILE double *x, ULong l)
|
|
{
|
|
NEEDS_VOLATILE uchar *ptr = reinterpret_cast<NEEDS_VOLATILE uchar *>(x);
|
|
if (ByteOrder == BigEndian) {
|
|
ptr[0] = (uchar)(l>>24);
|
|
ptr[1] = (uchar)(l>>16);
|
|
ptr[2] = (uchar)(l>>8);
|
|
ptr[3] = (uchar)l;
|
|
} else {
|
|
ptr[7] = (uchar)(l>>24);
|
|
ptr[6] = (uchar)(l>>16);
|
|
ptr[5] = (uchar)(l>>8);
|
|
ptr[4] = (uchar)l;
|
|
}
|
|
}
|
|
|
|
inline ULong getWord1(const NEEDS_VOLATILE double x)
|
|
{
|
|
const NEEDS_VOLATILE uchar *ptr = reinterpret_cast<const NEEDS_VOLATILE uchar *>(&x);
|
|
if (ByteOrder == BigEndian) {
|
|
return (ptr[4]<<24) + (ptr[5]<<16) + (ptr[6]<<8) + ptr[7];
|
|
} else {
|
|
return (ptr[3]<<24) + (ptr[2]<<16) + (ptr[1]<<8) + ptr[0];
|
|
}
|
|
}
|
|
inline void setWord1(NEEDS_VOLATILE double *x, ULong l)
|
|
{
|
|
NEEDS_VOLATILE uchar *ptr = reinterpret_cast<uchar NEEDS_VOLATILE *>(x);
|
|
if (ByteOrder == BigEndian) {
|
|
ptr[4] = (uchar)(l>>24);
|
|
ptr[5] = (uchar)(l>>16);
|
|
ptr[6] = (uchar)(l>>8);
|
|
ptr[7] = (uchar)l;
|
|
} else {
|
|
ptr[3] = (uchar)(l>>24);
|
|
ptr[2] = (uchar)(l>>16);
|
|
ptr[1] = (uchar)(l>>8);
|
|
ptr[0] = (uchar)l;
|
|
}
|
|
}
|
|
|
|
static inline void Storeinc(ULong *&a, const ULong &b, const ULong &c)
|
|
{
|
|
|
|
*a = (((unsigned short)b) << 16) | ((unsigned short)c);
|
|
++a;
|
|
}
|
|
|
|
/* #define P DBL_MANT_DIG */
|
|
/* Ten_pmax = floor(P*log(2)/log(5)) */
|
|
/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */
|
|
/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */
|
|
/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */
|
|
|
|
#if defined(IEEE_BIG_OR_LITTLE_ENDIAN)
|
|
#define Exp_shift 20
|
|
#define Exp_shift1 20
|
|
#define Exp_msk1 0x100000
|
|
#define Exp_msk11 0x100000
|
|
#define Exp_mask 0x7ff00000
|
|
#define P 53
|
|
#define Bias 1023
|
|
#define IEEE_Arith
|
|
#define Emin (-1022)
|
|
#define Exp_1 0x3ff00000
|
|
#define Exp_11 0x3ff00000
|
|
#define Ebits 11
|
|
#define Frac_mask 0xfffff
|
|
#define Frac_mask1 0xfffff
|
|
#define Ten_pmax 22
|
|
#define Bletch 0x10
|
|
#define Bndry_mask 0xfffff
|
|
#define Bndry_mask1 0xfffff
|
|
#define LSB 1
|
|
#define Sign_bit 0x80000000
|
|
#define Log2P 1
|
|
#define Tiny0 0
|
|
#define Tiny1 1
|
|
#define Quick_max 14
|
|
#define Int_max 14
|
|
#define Infinite(x) (getWord0(x) == 0x7ff00000) /* sufficient test for here */
|
|
#else
|
|
#undef Sudden_Underflow
|
|
#define Sudden_Underflow
|
|
#ifdef IBM
|
|
#define Exp_shift 24
|
|
#define Exp_shift1 24
|
|
#define Exp_msk1 0x1000000
|
|
#define Exp_msk11 0x1000000
|
|
#define Exp_mask 0x7f000000
|
|
#define P 14
|
|
#define Bias 65
|
|
#define Exp_1 0x41000000
|
|
#define Exp_11 0x41000000
|
|
#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */
|
|
#define Frac_mask 0xffffff
|
|
#define Frac_mask1 0xffffff
|
|
#define Bletch 4
|
|
#define Ten_pmax 22
|
|
#define Bndry_mask 0xefffff
|
|
#define Bndry_mask1 0xffffff
|
|
#define LSB 1
|
|
#define Sign_bit 0x80000000
|
|
#define Log2P 4
|
|
#define Tiny0 0x100000
|
|
#define Tiny1 0
|
|
#define Quick_max 14
|
|
#define Int_max 15
|
|
#else /* VAX */
|
|
#define Exp_shift 23
|
|
#define Exp_shift1 7
|
|
#define Exp_msk1 0x80
|
|
#define Exp_msk11 0x800000
|
|
#define Exp_mask 0x7f80
|
|
#define P 56
|
|
#define Bias 129
|
|
#define Exp_1 0x40800000
|
|
#define Exp_11 0x4080
|
|
#define Ebits 8
|
|
#define Frac_mask 0x7fffff
|
|
#define Frac_mask1 0xffff007f
|
|
#define Ten_pmax 24
|
|
#define Bletch 2
|
|
#define Bndry_mask 0xffff007f
|
|
#define Bndry_mask1 0xffff007f
|
|
#define LSB 0x10000
|
|
#define Sign_bit 0x8000
|
|
#define Log2P 1
|
|
#define Tiny0 0x80
|
|
#define Tiny1 0
|
|
#define Quick_max 15
|
|
#define Int_max 15
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef IEEE_Arith
|
|
#define ROUND_BIASED
|
|
#endif
|
|
|
|
#ifdef RND_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
|