GetNumberFormatA implementation added.

This commit is contained in:
Julio César Gázquez 2000-02-03 01:03:49 +00:00 committed by Alexandre Julliard
parent 9934a8d021
commit 05e81574f7
1 changed files with 259 additions and 5 deletions

View File

@ -3,6 +3,7 @@
*
* Copyright 1995 Martin von Loewis
* Copyright 1998 David Lee Lambert
* Copyright 2000 Julio César Gázquez
*/
#include <string.h>
@ -3145,18 +3146,271 @@ BOOL WINAPI EnumTimeFormatsW(
return FALSE;
}
/**************************************************************************
* GetNumberFormat32A (KERNEL32.355)
*/
INT WINAPI GetNumberFormatA(LCID locale, DWORD dwflags,
LPCSTR lpvalue, const NUMBERFMTA * lpFormat,
LPSTR lpNumberStr, int cchNumber)
LPCSTR lpValue, const NUMBERFMTA * lpFormat,
LPSTR lpNumberStr, int cchNumber)
{
FIXME_(file)("%s: stub, no reformating done\n",lpvalue);
LCID thislocale;
UINT thisnumdigits;
UINT thisleadingzero;
UINT thisgrouping[8]={ -1 };
LPCSTR thisdecimalsep;
LPCSTR thisthousandsep;
UINT thisnegativeorder;
lstrcpynA( lpNumberStr, lpvalue, cchNumber );
return cchNumber? lstrlenA( lpNumberStr ) : 0;
LPSTR sptr;
LPSTR dptr;
char roundbuffer[24]; /* Should be enough */
char *gptr;
int i,j;
int dotflag=0,negflag=0;
char misc_buf[8], negative_buf[4], decimal_buf[4], thousand_buf[4];
char digits_buf[11];
int intsize=0,decsize=0,totalsize,lastgroup, leadingzeros=0;
int negsignsize,decimalsepsize,thousandsepsize;
/* Default setting stuff - partially borrowed from GetFormatedDate */
if (!locale) {
locale = LOCALE_SYSTEM_DEFAULT;
}
if (locale == LOCALE_SYSTEM_DEFAULT) {
thislocale = GetSystemDefaultLCID();
} else if (locale == LOCALE_USER_DEFAULT) {
thislocale = GetUserDefaultLCID();
} else {
thislocale = locale;
}
/* Partial implementation: things like native digits are not considered */
if (lpFormat == NULL) {
GetLocaleInfoA(thislocale, LOCALE_IDIGITS,
misc_buf, sizeof(misc_buf));
thisnumdigits = atoi(misc_buf);
GetLocaleInfoA(thislocale, LOCALE_ILZERO,
misc_buf, sizeof(misc_buf));
thisleadingzero = atoi(misc_buf);
GetLocaleInfoA(thislocale, LOCALE_SGROUPING,
misc_buf, sizeof(misc_buf));
/* About grouping mechanism:
I parse the string and pour the group size values along the
thisgrouping[] array, starting by element 1. Then I convert these
values to indexes for insertion into the integer part.
thisgrouping[0]==-1, therefore I ensure index correctness without
need for range checking and related stuff.
The only drawback is the 7 separators limit, hopefully that means
it will fail with numbers bigger than 10^21 if using groups of three
as usual. */
for (i=1,gptr=misc_buf;*gptr!='\0';i++) {
/* In control panel, groups up 9 digits long are allowed. If there is any way to use larger groups,
then the next line must be replaced with the following code:
thisgrouping[i] = atoi(gptr);
for (;*gptr!=';' && *gptr!='\0';gptr++) ; */
thisgrouping[i] = *(gptr++)-'0';
if (*gptr==';')
gptr++;
}
/* Take care for repeating group size */
if (thisgrouping[i-1]==0) {
for (j=i-1;j<8;j++)
thisgrouping[j]=thisgrouping[i-2];
lastgroup=7;
} else
lastgroup=i-1;
for (i=2;i<=lastgroup;i++)
thisgrouping[i]+=thisgrouping[i-1];
GetLocaleInfoA(thislocale, LOCALE_SDECIMAL,
decimal_buf, sizeof(decimal_buf));
thisdecimalsep = decimal_buf;
GetLocaleInfoA(thislocale, LOCALE_STHOUSAND,
thousand_buf, sizeof(thousand_buf));
thisthousandsep = thousand_buf;
GetLocaleInfoA(thislocale, LOCALE_INEGNUMBER,
misc_buf, sizeof(misc_buf));
thisnegativeorder = atoi(misc_buf);
} else {
thisnumdigits = lpFormat->NumDigits;
thisleadingzero = lpFormat->LeadingZero;
thisgrouping[1] = lpFormat->Grouping;
for (i=2;i<8;i++)
thisgrouping[i]=thisgrouping[i-1]+lpFormat->Grouping;
lastgroup=7;
thisdecimalsep = lpFormat->lpDecimalSep;
thisthousandsep = lpFormat->lpThousandSep;
thisnegativeorder = lpFormat->NegativeOrder;
}
GetLocaleInfoA(thislocale, LOCALE_SNATIVEDIGITS,
digits_buf, sizeof(digits_buf));
GetLocaleInfoA(thislocale, LOCALE_SNEGATIVESIGN,
negative_buf, sizeof(negative_buf));
negsignsize=strlen(negative_buf);
decimalsepsize=strlen(thisdecimalsep);
thousandsepsize=strlen(thisthousandsep);
/* Size calculation */
sptr=lpValue;
if (*sptr=='-') {
negflag=1;
sptr++;
}
for (; *sptr=='0'; sptr++) leadingzeros++; /* Ignore leading zeros */
for (; *sptr!='\0'; sptr++) {
if (!dotflag && *sptr=='.') {
dotflag=1;
} else if (*sptr<'0' || *sptr>'9') {
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
} else {
if (dotflag) {
decsize++;
} else {
intsize++;
}
}
}
/* Take care of eventual rounding. Only, if I need to do it, then I write
the rounded lpValue copy into roundbuffer, and create the formatted
string from the proper source. This is smarter than copying it always
The buffer includes an extra leading zero, as the number can carry and
get and extra one. If it doesn't, the zero is ignored as any other
useless leading zero
*/
if (decsize>0 && decsize>thisnumdigits) {
sptr-=(decsize-thisnumdigits);
if (*sptr>='5') {
strcpy(roundbuffer+1,lpValue);
if (negflag) {
*roundbuffer='-';
*(roundbuffer+1)='0';
} else
*roundbuffer='0';
sptr=roundbuffer+(sptr-lpValue); // +1-1
while ( (++*sptr) > '9') {
*(sptr--)='0';
if (*sptr=='.') sptr--;
}
if ((negflag ? *(roundbuffer+leadingzeros+1) : *(roundbuffer+leadingzeros)) == '1')
intsize++;
sptr=roundbuffer;
} else
sptr=lpValue;
} else
sptr=lpValue;
totalsize=intsize;
if (intsize==0 && (decsize==0 || thisleadingzero))
totalsize++;
if (negflag)
totalsize+= thisnegativeorder == 1 || thisnegativeorder == 3 ? negsignsize
: thisnegativeorder == 2 || thisnegativeorder == 4 ? negsignsize+1 : 2 ;
/* Look for the first grouping to be done */
for (j=lastgroup;thisgrouping[j]>=intsize && j>0;j--) ;
totalsize+=thousandsepsize * j;
if (thisnumdigits>0)
totalsize+=decimalsepsize+thisnumdigits;
if (cchNumber==0) /* if cchNumber is zero, just return size needed */
return totalsize+1;
else
if (cchNumber<totalsize+1) { /* +1 = Null terminator (right?) */
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
} else {
/* Formatting stuff starts here */
dptr=lpNumberStr;
if (negflag) {
if (thisnegativeorder==0)
*dptr++='(';
else if (thisnegativeorder<=2) {
strcpy(dptr,negative_buf);
dptr+=negsignsize;
if (thisnegativeorder==2)
*dptr++=' ';
}
sptr++;
}
for (i=1;*sptr=='0' ;i++, sptr++) ; /* Ignore leading zeros from source*/
if (intsize==0 && (decsize==0 || thisleadingzero)) // Insert one leading zero into destination if required
*(dptr++)=digits_buf[0];
for (i=1;i<=intsize;i++) {
*(dptr++)=digits_buf[*(sptr++)-'0'];
/* Insert a group separator if we just reached the end of a group */
if (i==intsize-thisgrouping[j]) {
strcpy(dptr,thisthousandsep);
dptr+=thousandsepsize;
j--;
}
}
if (decsize>0)
sptr++;
if (thisnumdigits>0) {
strcpy(dptr,decimal_buf);
dptr+=decimalsepsize;
for (i=0;i<thisnumdigits;i++)
*(dptr++)=*sptr !='\0' ? digits_buf[*(sptr++)-'0'] : digits_buf[0];
}
if (negflag) {
if (thisnegativeorder==0)
*dptr++=')';
else if (thisnegativeorder>=3) {
if (thisnegativeorder==4)
*dptr++=' ';
strcpy(dptr,negative_buf);
dptr+=negsignsize;
sptr++;
}
}
*dptr='\0';
}
return totalsize+1;
}
/**************************************************************************
* GetNumberFormat32W (KERNEL32.xxx)
*/