home *** CD-ROM | disk | FTP | other *** search
- /**********************************************************
-
- Copyright (c) Dale Semchishen 1995
- All Rights Reserved
-
- locfmt.c
-
- Description:
- Localized string formatting library.
-
- The routines in this package will convert numbers into
- localized pascal strings. In other words the strings
- will be formatted appropriately for the region you are
- in as defined by the International Resources 'itl0', etc.
-
- Global functions:
- locfmt_Num2Str() - convert an integer to a local number str
- locfmt_Str2Str() - convert pascal str to a local number str
- locfmt_Dec2Str() - convert 'decimal' str to a local number str
-
- locfmt_Num2CurrStr() - convert an integer to a local currency str
- locfmt_Dec2CurrStr() - convert 'decimal' str to a local currency str
-
-
- History:
- Apr 20 1995 - Creation
-
- **********************************************************/
-
- #include "locfmt.h"
-
- #include <TextUtils.h>
- #include <IntlResources.h>
- #include <string.h>
-
-
-
- /*--------------- Local Function Prototypes ---------------*/
-
- static Intl0Hndl locfmt_GetIntl0
- (
- char *thousands_ref, /* out: thousands separator */
- char *decimal_ref /* out: decimal separator */
- );
-
-
-
- /**********************************************************
-
- locfmt_Num2Str - convert an integer to a local number str
-
- Description:
- This routine will convert a signed integer to a
- formatted string that is localized for your region.
-
- (eg) -1024 will be converted to
- "-1,024" for North America
- "-1.024" for Dutch
- "-1 024" for Finnish
-
- Return value:
-
- **********************************************************/
- void locfmt_Num2Str
- (
- Byte *localstr_ref, /* out: formatted string (Pascal) */
- long number /* in: the integer to convert */
- )
- {
- Str15 unformated_str;
-
-
- /* convert to a localized number string */
- NumToString( number, unformated_str );
- locfmt_Str2Str( localstr_ref, unformated_str );
- }
-
-
-
- /**********************************************************
-
- locfmt_Dec2Str - convert 'decimal' str to a local number str
-
- Description:
- This routine will convert a 'decimal' string
- to a formatted string that is localized for your region.
-
- For a simple integer string, number_str->exp should be 0
-
- If number_str->exp is negative, then a fractional
- number is being converted and will be formatted as such.
-
- For more information about the 'decimal' type
- see SANE documentation.
-
- Return value:
-
- **********************************************************/
- void locfmt_Dec2Str
- (
- Byte *localstr_ref, /* out: formatted string (Pascal) */
- decimal *number_str /* in: the 'decimal' string to convert */
- )
- {
- short idx;
- Str32 unformated_str;
-
-
- /* IF invalid parameters */
- if( (number_str == NULL) ||
- (localstr_ref == NULL) ||
- (localstr_ref == (Byte *)number_str) )
- {
- return;
- }
-
-
- /* IF a negative number */
- if( number_str->sgn )
- {
- unformated_str[0] = number_str->sig.length + 1;
- unformated_str[1] = '-';
- memcpy( &unformated_str[2], number_str->sig.text, number_str->sig.length );
- }
- /* ELSE a positive number */
- else
- {
- unformated_str[0] = number_str->sig.length;
- memcpy( &unformated_str[1], number_str->sig.text, number_str->sig.length );
- }
-
-
- /* IF number has a fractional part */
- if( number_str->exp < 0 )
- {
- /* make room for decimal point */
- idx = unformated_str[0] + number_str->exp + 1;
- memmove( &unformated_str[ idx+1 ], &unformated_str[ idx ],
- unformated_str[0] - idx + 1 );
-
- /* insert decimal point in the string */
- unformated_str[ idx ] = '.';
- unformated_str[0] += 1;
- }
- /* ELSE IF number has to be multiplied by a power of 10 */
- else if( number_str->exp > 0 )
- {
- /* append zeros */
- memset( &unformated_str[ unformated_str[0] + 1 ], '0', number_str->exp );
- unformated_str[0] += number_str->exp;
- }
-
-
- /* convert to a localized number string */
- locfmt_Str2Str( localstr_ref, unformated_str );
- }
-
-
-
- /**********************************************************
-
- locfmt_Str2Str - convert pascal str to a local number str
-
- Description:
- This routine will convert a pascal string
- to a formatted string that is localized for your region.
-
- For the input string parameter 'number_str' a decimal point
- can be used to indicate the fractional part of the number.
- If your numeric string is an integer, then do not include
- a decimal point.
-
- (eg) "-2048.5" will be converted to
- "-2,048.5" for North America
- "-2.048,5" for Dutch
- "-2 048,5" for Finnish
-
- Note:
- The address of the input and output strings must be different
-
- Return value:
-
- **********************************************************/
- void locfmt_Str2Str
- (
- Byte *localstr_ref, /* out: formatted string (Pascal) */
- Byte *number_str /* in: string to convert (Pascal) */
- )
- {
- char decimal_separator;
- char thousands_separator;
- char *fractionpart_ptr;
- char *input_ptr;
- Byte *outputstart_ptr;
- short integer_digits;
- short fraction_digits;
- short counter;
-
-
- /* IF invalid parameters */
- if( (number_str == NULL) ||
- (localstr_ref == NULL) ||
- (localstr_ref == number_str) )
- {
- return;
- }
-
-
- outputstart_ptr = localstr_ref++;
-
- /* get the separator characters for your region */
- locfmt_GetIntl0( &thousands_separator, &decimal_separator );
-
- /* IF a negative number */
- if( number_str[1] == '-' )
- {
- input_ptr = (char *) &number_str[2];
- counter = number_str[0] - 1;
-
- /* output negative sign */
- *localstr_ref++ = '-';
- }
- /* ELSE a positive number */
- else
- {
- input_ptr = (char *) &number_str[1];
- counter = number_str[0];
- }
-
-
- /* IF there is a fractional part */
- fractionpart_ptr = memchr( input_ptr, '.', counter );
- if( fractionpart_ptr != NULL )
- {
- integer_digits = fractionpart_ptr - input_ptr;
- fraction_digits = counter - integer_digits - 1;
- }
- /* ELSE no fractions */
- else
- {
- integer_digits = counter;
- fraction_digits = 0;
- }
-
-
- /* WHILE there are integer digits to output */
- while( integer_digits-- > 0 )
- {
- /* output a single digit */
- *localstr_ref++ = *input_ptr++;
-
- /* IF its time to insert the thousand's separator */
- if( (integer_digits > 0) &&
- (integer_digits % 3) == 0 )
- {
- *localstr_ref++ = thousands_separator;
- }
- }
-
-
- /* IF there is a fractional part */
- if( fractionpart_ptr != NULL )
- {
- *localstr_ref++ = decimal_separator;
-
- /* output trailing digits */
- memcpy( localstr_ref, &input_ptr[1], fraction_digits );
- }
-
-
- /* output length of formatted string */
- *outputstart_ptr = (localstr_ref - outputstart_ptr) + fraction_digits - 1;
- }
-
-
-
-
- /**********************************************************
-
- locfmt_Num2CurrStr - convert an integer to a local currency str
-
- Description:
- This routine will convert a signed integer to a
- formatted currency string that is localized for
- your region.
-
- The signed integer will be converted to a string
- and then decimal point character for your region
- will be inserted based on the value of 'fraction_digits'
- parameter.
-
- (eg) locfmt_Num2CurrStr( buf, -1024, 2) will generate
- the following strings
-
- "($1,024.00)" for North America
- "(Fl.1.024,00)" for Dutch
- "-1 024,00mk" for Finnish
- Note:
- Typically the 'fraction_digits' parameter will have
- a value of 2, but if you specify a value of 0 then
- a decimal separator will not be inserted in the
- formatted currency string because you are displaying
- an integer.
-
- Return value:
-
- **********************************************************/
- void locfmt_Num2CurrStr
- (
- Byte *localstr_ref, /* out: formatted currency string (Pascal) */
- long number, /* in: the integer to convert */
- short fraction_digits /* in: number of digits to right of decimal point */
- )
- {
- decimal unformated_str;
-
-
- /* IF negative amount */
- if( number < 0 )
- {
- /* convert to 'decimal' string */
- unformated_str.sgn = 1;
- unformated_str.exp = 0;
- NumToString( -number, &unformated_str.sig.length );
- }
- /* ELSE positive amount */
- else
- {
- /* convert to 'decimal' string */
- unformated_str.sgn = 0;
- unformated_str.exp = 0;
- NumToString( number, &unformated_str.sig.length );
- }
-
- /* convert to a localized currency string */
- locfmt_Dec2CurrStr( localstr_ref, &unformated_str, fraction_digits );
- }
-
-
-
- /**********************************************************
-
- locfmt_Dec2CurrStr - convert pascal str to a local currency str
-
- Description:
- This routine will convert a pascal string
- to a formatted currency string that is localized
- for your region.
-
- The signed integer will be converted to a string
- and then decimal point character for your region
- will be inserted based on the value of 'fraction_digits'
- parameter.
-
- (eg) dec_number.sgn = 1;
- dec_number.exp = 0;
- dec_number.sig.length = 4;
- dec_number.sig.text[0] = 1;
- dec_number.sig.text[1] = 0;
- dec_number.sig.text[2] = 2;
- dec_number.sig.text[3] = 4;
- locfmt_Str2CurrStr( buf, &dec_number, 2);
-
- will generate the following strings
-
- "($1,024.00)" for North America
- "(Fl.1.024,00)" for Dutch
- "-1 024,00mk" for Finnish
-
- Note:
- Typically the 'fraction_digits' parameter will have
- a value of 2, but if you specify a value of 0 then
- a decimal separator will not be inserted in the
- formatted currency string because you are displaying
- an integer.
-
- Return value:
-
- **********************************************************/
- void locfmt_Dec2CurrStr
- (
- Byte *localstr_ref, /* out: formatted currency string (Pascal) */
- decimal *number_ptr, /* in: string to convert */
- short fraction_digits /* in: number of digits to right of decimal point */
- )
- {
- Byte format;
- short count;
- Boolean integer_part;
- short integer_digits;
- Byte *outputstart_ptr;
- char *input_ptr;
- char *last_ptr;
- char *trail_ptr;
- char currency_symbol[ 4 ];
- char decimal_separator;
- char thousands_separator;
- Intl0Ptr international_ptr;
- Intl0Hndl international_hdl;
-
-
- /* IF invalid parameters */
- if( (number_ptr == NULL) ||
- (localstr_ref == NULL) ||
- (localstr_ref == (Byte *)number_ptr) )
- {
- return;
- }
-
-
- outputstart_ptr = localstr_ref++;
-
- /* IF able to get the separator characters for your region */
- international_hdl = locfmt_GetIntl0( &thousands_separator, &decimal_separator );
- if( international_hdl != NULL )
- {
- international_ptr = (*international_hdl);
-
- format = international_ptr->currFmt;
- currency_symbol[ 0 ] = international_ptr->currSym1;
- currency_symbol[ 1 ] = international_ptr->currSym2;
- currency_symbol[ 2 ] = international_ptr->currSym3;
- currency_symbol[ 3 ] = '\0';
- }
- /* ELSE no international resource */
- else
- {
- /* use North American formatting */
- format = currSymLead | currTrailingZ | currLeadingZ;
- currency_symbol[ 0 ] = '$';
- currency_symbol[ 1 ] = '\0';
- }
-
-
- /* IF a negative number */
- if( number_ptr->sgn )
- {
- /* IF minus sign should be used for a negative number */
- if( format & currNegSym )
- {
- *localstr_ref++ = '-';
- }
- /* ELSE use brackets for negative number */
- else
- {
- *localstr_ref++ = '(';
- }
- }
-
- /* IF the currency symbol should be displayed in front of the number */
- if( format & currSymLead )
- {
- /* output currency symbol(s) */
- for( input_ptr=currency_symbol; *input_ptr; )
- *localstr_ref++ = *input_ptr++;
- }
-
- integer_part = false;
- input_ptr = (char *) number_ptr->sig.text;
- integer_digits = number_ptr->sig.length - fraction_digits;
-
- /* IF there should be leading zeros AND there are no digits before separator */
- if( (format & currLeadingZ) && (integer_digits <= 0) )
- {
- *localstr_ref++ = '0';
- integer_part = true;
- }
- /* ELSE WHILE there are digits before the decimal separator */
- else while( integer_digits-- > 0 )
- {
- /* output a single digit */
- *localstr_ref++ = *input_ptr++;
- integer_part = true;
-
- /* IF its time to insert the thousand's separator */
- if( (integer_digits > 0) &&
- (integer_digits % 3) == 0 )
- {
- *localstr_ref++ = thousands_separator;
- }
- }
-
- trail_ptr = (char *) &number_ptr->sig.text[ number_ptr->sig.length ];
-
- /* IF there can be trailing zeros */
- if( format & currTrailingZ )
- {
- /* output decimal separator */
- if( fraction_digits > 0 )
- *localstr_ref++ = decimal_separator;
-
- /* pad with zeros if required to right justify the fraction digits */
- for( count=fraction_digits - (trail_ptr - input_ptr); count-- > 0; )
- *localstr_ref++ = '0';
-
- /* output digits after the decimal separator */
- while( input_ptr < trail_ptr )
- *localstr_ref++ = *input_ptr++;
- }
- /* ELSE no trailing zeros */
- else
- {
- if( fraction_digits > 0 )
- {
- /* determine where the last non-zero digit is */
- while( trail_ptr > input_ptr )
- {
- if( *--trail_ptr != '0' )
- break;
- }
-
- /* IF there are any non-zero digits after decimal separator */
- if( *trail_ptr != '0' )
- {
- /* output decimal separator */
- *localstr_ref++ = decimal_separator;
-
- last_ptr = (char *) &number_ptr->sig.text[number_ptr->sig.length];
- count = fraction_digits - (last_ptr - trail_ptr) - (trail_ptr - input_ptr);
-
- /* pad with zeros if required to right justify the fraction digits */
- while( count-- > 0 )
- *localstr_ref++ = '0';
-
- /* output digits after the decimal separator */
- while( (fraction_digits-- > 0) && (input_ptr <= trail_ptr) )
- *localstr_ref++ = *input_ptr++;
- }
- /* ELSE IF there were no integer digits output */
- else if( !integer_part )
- {
- *localstr_ref++ = '0';
- }
- }
- }
-
- /* IF the currency symbol should be displayed in after the number */
- if( !(format & currSymLead) )
- {
- /* output currency symbol(s) */
- for( input_ptr=currency_symbol; *input_ptr; )
- *localstr_ref++ = *input_ptr++;
- }
-
- /* IF a negative number AND brackets should be used for it */
- if( number_ptr->sgn && !(format & currNegSym) )
- {
- *localstr_ref++ = ')';
- }
-
- /* output length of formatted string */
- *outputstart_ptr = (localstr_ref - outputstart_ptr) - 1;
- }
-
-
-
-
- /**********************************************************
-
- locfmt_GetIntl0 - get the Intl0 resource handle
-
- Description:
- This routine will return the Intl10 resource
- handle. Also the thousands separator and decimal separator
- will be validated and returned.
-
- Return value:
- A handle to the Intl0 resource
- or
- NULL if failed
-
- **********************************************************/
- static Intl0Hndl locfmt_GetIntl0
- (
- char *thousands_ref, /* out: thousands separator */
- char *decimal_ref /* out: decimal separator */
- )
- {
- Intl0Hndl international_hdl;
- char decimal_separator;
- char thousands_separator;
-
-
- /* IF unable to get International Resource 'itl0' */
- international_hdl = (Intl0Hndl) GetIntlResource( 0 );
- if( international_hdl == NULL )
- {
- /* use North American standard */
- thousands_separator = ',';
- decimal_separator = '.';
- }
- else
- {
- thousands_separator = (*international_hdl)->thousSep;
-
- /* IF the thousand's separator is invalid */
- if( (thousands_separator == '-') ||
- ((thousands_separator >= '0') && (thousands_separator <= '9')) )
- {
- thousands_separator = '?';
- }
-
- decimal_separator = (*international_hdl)->decimalPt;
-
- /* IF the decimal separator is invalid */
- if( (decimal_separator == thousands_separator) ||
- (decimal_separator == '-') ||
- ((decimal_separator >= '0') && (decimal_separator <= '9')) )
- {
- decimal_separator = '?';
- }
- }
-
-
- *decimal_ref = decimal_separator;
- *thousands_ref = thousands_separator;
- }