1738 lines
46 KiB
C
1738 lines
46 KiB
C
|
/*
|
||
|
*******************************************************************************
|
||
|
* *
|
||
|
* COPYRIGHT: *
|
||
|
* (C) Copyright International Business Machines Corporation, 1998 *
|
||
|
* Licensed Material - Program-Property of IBM - All Rights Reserved. *
|
||
|
* US Government Users Restricted Rights - Use, duplication, or disclosure *
|
||
|
* restricted by GSA ADP Schedule Contract with IBM Corp. *
|
||
|
* *
|
||
|
*******************************************************************************
|
||
|
*
|
||
|
* File uprintf.c
|
||
|
*
|
||
|
* Modification History:
|
||
|
*
|
||
|
* Date Name Description
|
||
|
* 11/19/98 stephen Creation.
|
||
|
* 03/12/99 stephen Modified for new C API.
|
||
|
* Added conversion from default codepage.
|
||
|
*******************************************************************************
|
||
|
*/
|
||
|
|
||
|
#include "uprintf.h"
|
||
|
#include "uprntf_p.h"
|
||
|
#include "ustdio.h"
|
||
|
#include "ufile.h"
|
||
|
#include "ustring.h"
|
||
|
#include "locbund.h"
|
||
|
#include "umutex.h"
|
||
|
#include "unum.h"
|
||
|
#include "udat.h"
|
||
|
|
||
|
#include <string.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <math.h>
|
||
|
#include <float.h>
|
||
|
#include <limits.h>
|
||
|
#include <wchar.h>
|
||
|
|
||
|
|
||
|
u_printf_handler g_u_printf_handlers [256];
|
||
|
u_printf_info g_u_printf_infos [256];
|
||
|
bool_t g_u_printf_inited = FALSE;
|
||
|
|
||
|
/* buffer size for formatting */
|
||
|
#define UFPRINTF_BUFFER_SIZE 1024
|
||
|
|
||
|
int32_t
|
||
|
u_fprintf( UFILE *f,
|
||
|
const char *patternSpecification,
|
||
|
... )
|
||
|
{
|
||
|
va_list ap;
|
||
|
int32_t count;
|
||
|
|
||
|
va_start(ap, patternSpecification);
|
||
|
count = u_vfprintf(f, patternSpecification, ap);
|
||
|
va_end(ap);
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_fprintf_u( UFILE *f,
|
||
|
const UChar *patternSpecification,
|
||
|
... )
|
||
|
{
|
||
|
va_list ap;
|
||
|
int32_t count;
|
||
|
|
||
|
va_start(ap, patternSpecification);
|
||
|
count = u_vfprintf_u(f, patternSpecification, ap);
|
||
|
va_end(ap);
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_vfprintf( UFILE *f,
|
||
|
const char *patternSpecification,
|
||
|
va_list ap)
|
||
|
{
|
||
|
int32_t count;
|
||
|
UChar *pattern;
|
||
|
|
||
|
/* convert from the default codepage to Unicode */
|
||
|
pattern = ufmt_defaultCPToUnicode(patternSpecification,
|
||
|
strlen(patternSpecification));
|
||
|
if(pattern == 0) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* do the work */
|
||
|
count = u_vfprintf_u(f, pattern, ap);
|
||
|
|
||
|
/* clean up */
|
||
|
free(pattern);
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_printf_register_handler(UChar spec,
|
||
|
u_printf_info info,
|
||
|
u_printf_handler handler)
|
||
|
{
|
||
|
/* lock the cache */
|
||
|
umtx_lock(0);
|
||
|
|
||
|
/* add to our list of function pointers */
|
||
|
g_u_printf_infos[ (unsigned char) spec ] = info;
|
||
|
g_u_printf_handlers[ (unsigned char) spec ] = handler;
|
||
|
|
||
|
/* unlock the cache */
|
||
|
umtx_unlock(0);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* handle a '%' */
|
||
|
|
||
|
int32_t
|
||
|
u_printf_simple_percent_info(const u_printf_spec_info *info,
|
||
|
int32_t *argtypes,
|
||
|
int32_t n)
|
||
|
{
|
||
|
/* we don't need any arguments */
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_printf_simple_percent_handler(UFILE *stream,
|
||
|
const u_printf_spec_info *info,
|
||
|
const ufmt_args *args)
|
||
|
{
|
||
|
/* put a single '%' on the stream */
|
||
|
u_fputc(0x0025, stream);
|
||
|
/* we wrote one character */
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
/* handle 's' */
|
||
|
|
||
|
int32_t
|
||
|
u_printf_string_info(const u_printf_spec_info *info,
|
||
|
int32_t *argtypes,
|
||
|
int32_t n)
|
||
|
{
|
||
|
/* handle error */
|
||
|
if(n < 1)
|
||
|
return 0;
|
||
|
|
||
|
/* we need 1 argument of type string */
|
||
|
argtypes[0] = ufmt_string;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_printf_string_handler(UFILE *stream,
|
||
|
const u_printf_spec_info *info,
|
||
|
const ufmt_args *args)
|
||
|
{
|
||
|
UChar *s;
|
||
|
int32_t len, written, i;
|
||
|
const char *arg = (const char*)(args[0].ptrValue);
|
||
|
|
||
|
/* convert from the default codepage to Unicode */
|
||
|
s = ufmt_defaultCPToUnicode(arg, strlen(arg));
|
||
|
if(s == 0) {
|
||
|
return 0;
|
||
|
}
|
||
|
len = u_strlen(s);
|
||
|
|
||
|
/* width = minimum # of characters to write */
|
||
|
/* precision = maximum # of characters to write */
|
||
|
|
||
|
/* precision takes precedence over width */
|
||
|
/* determine if the string should be truncated */
|
||
|
if(info->fPrecision != -1 && len > info->fPrecision) {
|
||
|
written = u_file_write(s, info->fPrecision, stream);
|
||
|
}
|
||
|
|
||
|
/* determine if the string should be padded */
|
||
|
else if(info->fWidth != -1 && len < info->fWidth) {
|
||
|
/* left justify */
|
||
|
if(info->fLeft) {
|
||
|
written = u_file_write(s, len, stream);
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
}
|
||
|
/* right justify */
|
||
|
else {
|
||
|
written = 0;
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
written += u_file_write(s, len, stream);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* just write the string */
|
||
|
else
|
||
|
written = u_file_write(s, len, stream);
|
||
|
|
||
|
/* clean up */
|
||
|
free(s);
|
||
|
|
||
|
return written;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_printf_integer_info(const u_printf_spec_info *info,
|
||
|
int32_t *argtypes,
|
||
|
int32_t n)
|
||
|
{
|
||
|
/* handle error */
|
||
|
if(n < 1)
|
||
|
return 0;
|
||
|
|
||
|
/* we need 1 argument of type int */
|
||
|
argtypes[0] = ufmt_int;
|
||
|
return 1;
|
||
|
}
|
||
|
/* HSYS */
|
||
|
int32_t
|
||
|
u_printf_integer_handler(UFILE *stream,
|
||
|
const u_printf_spec_info *info,
|
||
|
const ufmt_args *args)
|
||
|
{
|
||
|
int32_t written = 0;
|
||
|
int32_t len;
|
||
|
long num = (long) (args[0].intValue);
|
||
|
UNumberFormat *format;
|
||
|
UChar result [UFPRINTF_BUFFER_SIZE];
|
||
|
int32_t i, minDigits = -1;
|
||
|
UErrorCode status = ZERO_ERROR;
|
||
|
|
||
|
|
||
|
/* mask off any necessary bits */
|
||
|
if(info->fIsShort)
|
||
|
num &= SHRT_MAX;
|
||
|
else if(! info->fIsLong || ! info->fIsLongLong)
|
||
|
num &= INT_MAX;
|
||
|
|
||
|
/* get the formatter */
|
||
|
format = u_locbund_getNumberFormat(stream->fBundle);
|
||
|
|
||
|
/* handle error */
|
||
|
if(format == 0)
|
||
|
return 0;
|
||
|
|
||
|
/* set the appropriate flags on the formatter */
|
||
|
|
||
|
/* set the minimum integer digits */
|
||
|
if(info->fPrecision != -1) {
|
||
|
/* clone the stream's bundle if it isn't owned */
|
||
|
if(! stream->fOwnBundle) {
|
||
|
stream->fBundle = u_locbund_clone(stream->fBundle);
|
||
|
stream->fOwnBundle = TRUE;
|
||
|
format = u_locbund_getNumberFormat(stream->fBundle);
|
||
|
}
|
||
|
|
||
|
/* set the minimum # of digits */
|
||
|
minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS);
|
||
|
unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision);
|
||
|
}
|
||
|
|
||
|
/* set whether to show the sign */
|
||
|
if(info->fShowSign) {
|
||
|
/* clone the stream's bundle if it isn't owned */
|
||
|
if(! stream->fOwnBundle) {
|
||
|
stream->fBundle = u_locbund_clone(stream->fBundle);
|
||
|
stream->fOwnBundle = TRUE;
|
||
|
format = u_locbund_getNumberFormat(stream->fBundle);
|
||
|
}
|
||
|
|
||
|
/* set whether to show the sign*/
|
||
|
/* {sfb} TBD */
|
||
|
}
|
||
|
|
||
|
/* format the number */
|
||
|
unum_format(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status);
|
||
|
len = u_strlen(result);
|
||
|
|
||
|
/* pad and justify, if needed */
|
||
|
if(info->fWidth != -1 && len < info->fWidth) {
|
||
|
/* left justify */
|
||
|
if(info->fLeft) {
|
||
|
written = u_file_write(result, len, stream);
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
}
|
||
|
/* right justify */
|
||
|
else {
|
||
|
written = 0;
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
written += u_file_write(result, len, stream);
|
||
|
}
|
||
|
}
|
||
|
/* just write the formatted output */
|
||
|
else
|
||
|
written = u_file_write(result, len, stream);
|
||
|
|
||
|
/* restore the number format */
|
||
|
if(minDigits != -1)
|
||
|
unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits);
|
||
|
|
||
|
return written;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_printf_hex_info(const u_printf_spec_info *info,
|
||
|
int32_t *argtypes,
|
||
|
int32_t n)
|
||
|
{
|
||
|
/* handle error */
|
||
|
if(n < 1)
|
||
|
return 0;
|
||
|
|
||
|
/* we need 1 argument of type int */
|
||
|
argtypes[0] = ufmt_int;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_printf_hex_handler(UFILE *stream,
|
||
|
const u_printf_spec_info *info,
|
||
|
const ufmt_args *args)
|
||
|
{
|
||
|
int32_t written = 0;
|
||
|
long num = (long) (args[0].intValue);
|
||
|
int32_t i;
|
||
|
UChar result [UFPRINTF_BUFFER_SIZE];
|
||
|
int32_t len = UFPRINTF_BUFFER_SIZE;
|
||
|
|
||
|
|
||
|
/* mask off any necessary bits */
|
||
|
if(info->fIsShort)
|
||
|
num &= SHRT_MAX;
|
||
|
else if(! info->fIsLong || ! info->fIsLongLong)
|
||
|
num &= INT_MAX;
|
||
|
|
||
|
/* format the number, preserving the minimum # of digits */
|
||
|
ufmt_ltou(result, &len, num, 16,
|
||
|
(bool_t)(info->fSpec == 0x0078),
|
||
|
(info->fPrecision == -1 && info->fZero) ? info->fWidth : info->fPrecision);
|
||
|
|
||
|
/* convert to alt form, if desired */
|
||
|
if(num != 0 && info->fAlt && len < UFPRINTF_BUFFER_SIZE - 2) {
|
||
|
/* shift the formatted string right by 2 chars */
|
||
|
memmove(result + 2, result, len * sizeof(UChar));
|
||
|
result[0] = 0x0030;
|
||
|
result[1] = info->fSpec;
|
||
|
len += 2;
|
||
|
}
|
||
|
|
||
|
/* pad and justify, if needed */
|
||
|
if(info->fWidth != -1 && len < info->fWidth) {
|
||
|
/* left justify */
|
||
|
if(info->fLeft) {
|
||
|
written = u_file_write(result, len, stream);
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
}
|
||
|
/* right justify */
|
||
|
else {
|
||
|
written = 0;
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
written += u_file_write(result, len, stream);
|
||
|
}
|
||
|
}
|
||
|
/* just write the formatted output */
|
||
|
else
|
||
|
written = u_file_write(result, len, stream);
|
||
|
|
||
|
return written;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_printf_octal_info(const u_printf_spec_info *info,
|
||
|
int32_t *argtypes,
|
||
|
int32_t n)
|
||
|
{
|
||
|
/* handle error */
|
||
|
if(n < 1)
|
||
|
return 0;
|
||
|
|
||
|
/* we need 1 argument of type int */
|
||
|
argtypes[0] = ufmt_int;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_printf_octal_handler(UFILE *stream,
|
||
|
const u_printf_spec_info *info,
|
||
|
const ufmt_args *args)
|
||
|
{
|
||
|
int32_t written = 0;
|
||
|
long num = (long) (args[0].intValue);
|
||
|
int32_t i;
|
||
|
UChar result [UFPRINTF_BUFFER_SIZE];
|
||
|
int32_t len = UFPRINTF_BUFFER_SIZE;
|
||
|
|
||
|
|
||
|
/* mask off any necessary bits */
|
||
|
if(info->fIsShort)
|
||
|
num &= SHRT_MAX;
|
||
|
else if(! info->fIsLong || ! info->fIsLongLong)
|
||
|
num &= INT_MAX;
|
||
|
|
||
|
/* format the number, preserving the minimum # of digits */
|
||
|
ufmt_ltou(result, &len, num, 8,
|
||
|
FALSE, /* doesn't matter for octal */
|
||
|
info->fPrecision == -1 && info->fZero ? info->fWidth : info->fPrecision);
|
||
|
|
||
|
/* convert to alt form, if desired */
|
||
|
if(info->fAlt && result[0] != 0x0030 && len < UFPRINTF_BUFFER_SIZE - 1) {
|
||
|
/* shift the formatted string right by 1 char */
|
||
|
memmove(result + 1, result, len * sizeof(UChar));
|
||
|
result[0] = 0x0030;
|
||
|
len += 1;
|
||
|
}
|
||
|
|
||
|
/* pad and justify, if needed */
|
||
|
if(info->fWidth != -1 && len < info->fWidth) {
|
||
|
/* left justify */
|
||
|
if(info->fLeft) {
|
||
|
written = u_file_write(result, len, stream);
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
}
|
||
|
/* right justify */
|
||
|
else {
|
||
|
written = 0;
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
written += u_file_write(result, len, stream);
|
||
|
}
|
||
|
}
|
||
|
/* just write the formatted output */
|
||
|
else
|
||
|
written = u_file_write(result, len, stream);
|
||
|
|
||
|
return written;
|
||
|
}
|
||
|
|
||
|
|
||
|
int32_t
|
||
|
u_printf_double_info(const u_printf_spec_info *info,
|
||
|
int32_t *argtypes,
|
||
|
int32_t n)
|
||
|
{
|
||
|
/* handle error */
|
||
|
if(n < 1)
|
||
|
return 0;
|
||
|
|
||
|
/* we need 1 argument of type double */
|
||
|
argtypes[0] = ufmt_double;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_printf_double_handler(UFILE *stream,
|
||
|
const u_printf_spec_info *info,
|
||
|
const ufmt_args *args)
|
||
|
{
|
||
|
int32_t written = 0;
|
||
|
int32_t len;
|
||
|
double num = (double) (args[0].doubleValue);
|
||
|
UNumberFormat *format;
|
||
|
UChar result [UFPRINTF_BUFFER_SIZE];
|
||
|
int32_t i, minDecimalDigits;
|
||
|
int32_t maxDecimalDigits;
|
||
|
UErrorCode status = ZERO_ERROR;
|
||
|
|
||
|
/* mask off any necessary bits */
|
||
|
/* if(! info->fIsLongDouble)
|
||
|
num &= DBL_MAX;*/
|
||
|
|
||
|
/* get the formatter */
|
||
|
format = u_locbund_getNumberFormat(stream->fBundle);
|
||
|
|
||
|
/* handle error */
|
||
|
if(format == 0)
|
||
|
return 0;
|
||
|
|
||
|
/* set the appropriate flags on the formatter */
|
||
|
|
||
|
/* clone the stream's bundle if it isn't owned */
|
||
|
if(! stream->fOwnBundle) {
|
||
|
stream->fBundle = u_locbund_clone(stream->fBundle);
|
||
|
stream->fOwnBundle = TRUE;
|
||
|
format = u_locbund_getNumberFormat(stream->fBundle);
|
||
|
}
|
||
|
|
||
|
/* set the number of decimal digits */
|
||
|
|
||
|
/* save the formatter's state */
|
||
|
minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
|
||
|
maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
|
||
|
|
||
|
if(info->fPrecision != -1) {
|
||
|
/* set the # of decimal digits */
|
||
|
unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
|
||
|
}
|
||
|
else if(info->fPrecision == 0 && ! info->fAlt) {
|
||
|
/* no decimal point in this case */
|
||
|
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0);
|
||
|
}
|
||
|
else if(info->fAlt) {
|
||
|
/* '#' means always show decimal point */
|
||
|
/* copy of printf behavior on Solaris - '#' shows 6 digits */
|
||
|
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
|
||
|
}
|
||
|
else {
|
||
|
/* # of decimal digits is 6 if precision not specified */
|
||
|
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
|
||
|
}
|
||
|
|
||
|
/* set whether to show the sign */
|
||
|
if(info->fShowSign) {
|
||
|
/* set whether to show the sign*/
|
||
|
/* {sfb} TBD */
|
||
|
}
|
||
|
|
||
|
/* format the number */
|
||
|
unum_formatDouble(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status);
|
||
|
len = u_strlen(result);
|
||
|
|
||
|
/* pad and justify, if needed */
|
||
|
if(info->fWidth != -1 && len < info->fWidth) {
|
||
|
/* left justify */
|
||
|
if(info->fLeft) {
|
||
|
written = u_file_write(result, len, stream);
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
}
|
||
|
/* right justify */
|
||
|
else {
|
||
|
written = 0;
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
written += u_file_write(result, len, stream);
|
||
|
}
|
||
|
}
|
||
|
/* just write the formatted output */
|
||
|
else
|
||
|
written = u_file_write(result, len, stream);
|
||
|
|
||
|
/* restore the number format */
|
||
|
unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
|
||
|
unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
|
||
|
|
||
|
return written;
|
||
|
}
|
||
|
|
||
|
|
||
|
int32_t
|
||
|
u_printf_char_info(const u_printf_spec_info *info,
|
||
|
int32_t *argtypes,
|
||
|
int32_t n)
|
||
|
{
|
||
|
/* handle error */
|
||
|
if(n < 1)
|
||
|
return 0;
|
||
|
|
||
|
/* we need 1 argument of type char */
|
||
|
argtypes[0] = ufmt_char;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_printf_char_handler(UFILE *stream,
|
||
|
const u_printf_spec_info *info,
|
||
|
const ufmt_args *args)
|
||
|
{
|
||
|
UChar *s;
|
||
|
int32_t len, written = 0, i;
|
||
|
unsigned char arg = (unsigned char)(args[0].intValue);
|
||
|
|
||
|
/* convert from default codepage to Unicode */
|
||
|
s = ufmt_defaultCPToUnicode(&arg, 1);
|
||
|
if(s == 0) {
|
||
|
return 0;
|
||
|
}
|
||
|
len = u_strlen(s);
|
||
|
|
||
|
/* width = minimum # of characters to write */
|
||
|
/* precision = maximum # of characters to write */
|
||
|
|
||
|
/* precision takes precedence over width */
|
||
|
/* determine if the string should be truncated */
|
||
|
if(info->fPrecision != -1 && len > info->fPrecision) {
|
||
|
written = u_file_write(s, info->fPrecision, stream);
|
||
|
}
|
||
|
|
||
|
/* determine if the string should be padded */
|
||
|
else if(info->fWidth != -1 && len < info->fWidth) {
|
||
|
/* left justify */
|
||
|
if(info->fLeft) {
|
||
|
written = u_file_write(s, len, stream);
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
}
|
||
|
/* right justify */
|
||
|
else {
|
||
|
written = 0;
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
written += u_file_write(s, len, stream);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* just write the string */
|
||
|
else
|
||
|
written = u_file_write(s, len, stream);
|
||
|
|
||
|
/* clean up */
|
||
|
free(s);
|
||
|
|
||
|
return written;
|
||
|
}
|
||
|
|
||
|
|
||
|
int32_t
|
||
|
u_printf_pointer_info(const u_printf_spec_info *info,
|
||
|
int32_t *argtypes,
|
||
|
int32_t n)
|
||
|
{
|
||
|
/* handle error */
|
||
|
if(n < 1)
|
||
|
return 0;
|
||
|
|
||
|
/* we need 1 argument of type void* */
|
||
|
argtypes[0] = ufmt_pointer;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_printf_pointer_handler(UFILE *stream,
|
||
|
const u_printf_spec_info *info,
|
||
|
const ufmt_args *args)
|
||
|
{
|
||
|
int32_t written = 0;
|
||
|
long num = (long) (args[0].intValue);
|
||
|
int32_t i;
|
||
|
UChar result [UFPRINTF_BUFFER_SIZE];
|
||
|
int32_t len = UFPRINTF_BUFFER_SIZE;
|
||
|
|
||
|
|
||
|
/* format the pointer in hex */
|
||
|
ufmt_ltou(result, &len, num, 16, TRUE, info->fPrecision);
|
||
|
|
||
|
/* pad and justify, if needed */
|
||
|
if(info->fWidth != -1 && len < info->fWidth) {
|
||
|
/* left justify */
|
||
|
if(info->fLeft) {
|
||
|
written = u_file_write(result, len, stream);
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
}
|
||
|
/* right justify */
|
||
|
else {
|
||
|
written = 0;
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
written += u_file_write(result, len, stream);
|
||
|
}
|
||
|
}
|
||
|
/* just write the formatted output */
|
||
|
else
|
||
|
written = u_file_write(result, len, stream);
|
||
|
|
||
|
return written;
|
||
|
}
|
||
|
|
||
|
|
||
|
int32_t
|
||
|
u_printf_scientific_info(const u_printf_spec_info *info,
|
||
|
int32_t *argtypes,
|
||
|
int32_t n)
|
||
|
{
|
||
|
/* handle error */
|
||
|
if(n < 1)
|
||
|
return 0;
|
||
|
|
||
|
/* we need 1 argument of type double */
|
||
|
argtypes[0] = ufmt_double;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_printf_scientific_handler(UFILE *stream,
|
||
|
const u_printf_spec_info *info,
|
||
|
const ufmt_args *args)
|
||
|
{
|
||
|
int32_t written = 0;
|
||
|
int32_t len;
|
||
|
double num = (double) (args[0].doubleValue);
|
||
|
UNumberFormat *format;
|
||
|
UChar result [UFPRINTF_BUFFER_SIZE];
|
||
|
int32_t i, minDecimalDigits;
|
||
|
int32_t maxDecimalDigits;
|
||
|
UErrorCode status = ZERO_ERROR;
|
||
|
|
||
|
|
||
|
/* mask off any necessary bits */
|
||
|
/* if(! info->fIsLongDouble)
|
||
|
num &= DBL_MAX;*/
|
||
|
|
||
|
/* get the formatter */
|
||
|
format = u_locbund_getScientificFormat(stream->fBundle);
|
||
|
|
||
|
/* handle error */
|
||
|
if(format == 0)
|
||
|
return 0;
|
||
|
|
||
|
/* set the appropriate flags on the formatter */
|
||
|
|
||
|
/* clone the stream's bundle if it isn't owned */
|
||
|
if(! stream->fOwnBundle) {
|
||
|
stream->fBundle = u_locbund_clone(stream->fBundle);
|
||
|
stream->fOwnBundle = TRUE;
|
||
|
format = u_locbund_getScientificFormat(stream->fBundle);
|
||
|
}
|
||
|
|
||
|
/* set the number of decimal digits */
|
||
|
|
||
|
/* save the formatter's state */
|
||
|
minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
|
||
|
maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
|
||
|
|
||
|
if(info->fPrecision != -1) {
|
||
|
/* set the # of decimal digits */
|
||
|
unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
|
||
|
}
|
||
|
else if(info->fPrecision == 0 && ! info->fAlt) {
|
||
|
/* no decimal point in this case */
|
||
|
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0);
|
||
|
}
|
||
|
else if(info->fAlt) {
|
||
|
/* '#' means always show decimal point */
|
||
|
/* copy of printf behavior on Solaris - '#' shows 6 digits */
|
||
|
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
|
||
|
}
|
||
|
else {
|
||
|
/* # of decimal digits is 6 if precision not specified */
|
||
|
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
|
||
|
}
|
||
|
|
||
|
/* set whether to show the sign */
|
||
|
if(info->fShowSign) {
|
||
|
/* set whether to show the sign*/
|
||
|
/* {sfb} TBD */
|
||
|
}
|
||
|
|
||
|
/* format the number */
|
||
|
unum_formatDouble(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status);
|
||
|
len = u_strlen(result);
|
||
|
|
||
|
/* pad and justify, if needed */
|
||
|
if(info->fWidth != -1 && len < info->fWidth) {
|
||
|
/* left justify */
|
||
|
if(info->fLeft) {
|
||
|
written = u_file_write(result, len, stream);
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
}
|
||
|
/* right justify */
|
||
|
else {
|
||
|
written = 0;
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
written += u_file_write(result, len, stream);
|
||
|
}
|
||
|
}
|
||
|
/* just write the formatted output */
|
||
|
else
|
||
|
written = u_file_write(result, len, stream);
|
||
|
|
||
|
/* restore the number format */
|
||
|
unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
|
||
|
unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
|
||
|
|
||
|
return written;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_printf_date_info(const u_printf_spec_info *info,
|
||
|
int32_t *argtypes,
|
||
|
int32_t n)
|
||
|
{
|
||
|
/* handle error */
|
||
|
if(n < 1)
|
||
|
return 0;
|
||
|
|
||
|
/* we need 1 argument of type Date */
|
||
|
argtypes[0] = ufmt_date;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_printf_date_handler(UFILE *stream,
|
||
|
const u_printf_spec_info *info,
|
||
|
const ufmt_args *args)
|
||
|
{
|
||
|
int32_t written = 0;
|
||
|
int32_t len;
|
||
|
UDate num = (UDate) (args[0].dateValue);
|
||
|
UDateFormat *format;
|
||
|
UChar result [UFPRINTF_BUFFER_SIZE];
|
||
|
int32_t i;
|
||
|
UErrorCode status = ZERO_ERROR;
|
||
|
|
||
|
|
||
|
/* get the formatter */
|
||
|
format = u_locbund_getDateFormat(stream->fBundle);
|
||
|
|
||
|
/* handle error */
|
||
|
if(format == 0)
|
||
|
return 0;
|
||
|
|
||
|
/* format the date */
|
||
|
udat_format(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status);
|
||
|
len = u_strlen(result);
|
||
|
|
||
|
/* pad and justify, if needed */
|
||
|
if(info->fWidth != -1 && len < info->fWidth) {
|
||
|
/* left justify */
|
||
|
if(info->fLeft) {
|
||
|
written = u_file_write(result, len, stream);
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
}
|
||
|
/* right justify */
|
||
|
else {
|
||
|
written = 0;
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
written += u_file_write(result, len, stream);
|
||
|
}
|
||
|
}
|
||
|
/* just write the formatted output */
|
||
|
else
|
||
|
written = u_file_write(result, len, stream);
|
||
|
|
||
|
return written;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_printf_time_info(const u_printf_spec_info *info,
|
||
|
int32_t *argtypes,
|
||
|
int32_t n)
|
||
|
{
|
||
|
/* handle error */
|
||
|
if(n < 1)
|
||
|
return 0;
|
||
|
|
||
|
/* we need 1 argument of type date */
|
||
|
argtypes[0] = ufmt_date;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_printf_time_handler(UFILE *stream,
|
||
|
const u_printf_spec_info *info,
|
||
|
const ufmt_args *args)
|
||
|
{
|
||
|
int32_t written = 0;
|
||
|
int32_t len;
|
||
|
UDate num = (UDate) (args[0].dateValue);
|
||
|
UDateFormat *format;
|
||
|
UChar result [UFPRINTF_BUFFER_SIZE];
|
||
|
int32_t i;
|
||
|
UErrorCode status = ZERO_ERROR;
|
||
|
|
||
|
|
||
|
/* get the formatter */
|
||
|
format = u_locbund_getTimeFormat(stream->fBundle);
|
||
|
|
||
|
/* handle error */
|
||
|
if(format == 0)
|
||
|
return 0;
|
||
|
|
||
|
/* format the time */
|
||
|
udat_format(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status);
|
||
|
len = u_strlen(result);
|
||
|
|
||
|
/* pad and justify, if needed */
|
||
|
if(info->fWidth != -1 && len < info->fWidth) {
|
||
|
/* left justify */
|
||
|
if(info->fLeft) {
|
||
|
written = u_file_write(result, len, stream);
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
}
|
||
|
/* right justify */
|
||
|
else {
|
||
|
written = 0;
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
written += u_file_write(result, len, stream);
|
||
|
}
|
||
|
}
|
||
|
/* just write the formatted output */
|
||
|
else
|
||
|
written = u_file_write(result, len, stream);
|
||
|
|
||
|
return written;
|
||
|
}
|
||
|
|
||
|
|
||
|
int32_t
|
||
|
u_printf_percent_info(const u_printf_spec_info *info,
|
||
|
int32_t *argtypes,
|
||
|
int32_t n)
|
||
|
{
|
||
|
/* handle error */
|
||
|
if(n < 1)
|
||
|
return 0;
|
||
|
|
||
|
/* we need 1 argument of type double */
|
||
|
argtypes[0] = ufmt_double;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_printf_percent_handler(UFILE *stream,
|
||
|
const u_printf_spec_info *info,
|
||
|
const ufmt_args *args)
|
||
|
{
|
||
|
int32_t written = 0;
|
||
|
int32_t len;
|
||
|
double num = (double) (args[0].doubleValue);
|
||
|
UNumberFormat *format;
|
||
|
UChar result [UFPRINTF_BUFFER_SIZE];
|
||
|
int32_t i, minDecimalDigits;
|
||
|
int32_t maxDecimalDigits;
|
||
|
UErrorCode status = ZERO_ERROR;
|
||
|
|
||
|
|
||
|
/* mask off any necessary bits */
|
||
|
/* if(! info->fIsLongDouble)
|
||
|
num &= DBL_MAX;*/
|
||
|
|
||
|
/* get the formatter */
|
||
|
format = u_locbund_getPercentFormat(stream->fBundle);
|
||
|
|
||
|
/* handle error */
|
||
|
if(format == 0)
|
||
|
return 0;
|
||
|
|
||
|
/* set the appropriate flags on the formatter */
|
||
|
|
||
|
/* clone the stream's bundle if it isn't owned */
|
||
|
if(! stream->fOwnBundle) {
|
||
|
stream->fBundle = u_locbund_clone(stream->fBundle);
|
||
|
stream->fOwnBundle = TRUE;
|
||
|
format = u_locbund_getPercentFormat(stream->fBundle);
|
||
|
}
|
||
|
|
||
|
/* set the number of decimal digits */
|
||
|
|
||
|
/* save the formatter's state */
|
||
|
minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
|
||
|
maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
|
||
|
|
||
|
if(info->fPrecision != -1) {
|
||
|
/* set the # of decimal digits */
|
||
|
unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
|
||
|
}
|
||
|
else if(info->fPrecision == 0 && ! info->fAlt) {
|
||
|
/* no decimal point in this case */
|
||
|
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0);
|
||
|
}
|
||
|
else if(info->fAlt) {
|
||
|
/* '#' means always show decimal point */
|
||
|
/* copy of printf behavior on Solaris - '#' shows 6 digits */
|
||
|
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
|
||
|
}
|
||
|
else {
|
||
|
/* # of decimal digits is 6 if precision not specified */
|
||
|
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
|
||
|
}
|
||
|
|
||
|
/* set whether to show the sign */
|
||
|
if(info->fShowSign) {
|
||
|
/* set whether to show the sign*/
|
||
|
/* {sfb} TBD */
|
||
|
}
|
||
|
|
||
|
/* format the number */
|
||
|
unum_formatDouble(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status);
|
||
|
len = u_strlen(result);
|
||
|
|
||
|
/* pad and justify, if needed */
|
||
|
if(info->fWidth != -1 && len < info->fWidth) {
|
||
|
/* left justify */
|
||
|
if(info->fLeft) {
|
||
|
written = u_file_write(result, len, stream);
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
}
|
||
|
/* right justify */
|
||
|
else {
|
||
|
written = 0;
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
written += u_file_write(result, len, stream);
|
||
|
}
|
||
|
}
|
||
|
/* just write the formatted output */
|
||
|
else
|
||
|
written = u_file_write(result, len, stream);
|
||
|
|
||
|
/* restore the number format */
|
||
|
unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
|
||
|
unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
|
||
|
|
||
|
return written;
|
||
|
}
|
||
|
|
||
|
|
||
|
int32_t
|
||
|
u_printf_currency_info(const u_printf_spec_info *info,
|
||
|
int32_t *argtypes,
|
||
|
int32_t n)
|
||
|
{
|
||
|
/* handle error */
|
||
|
if(n < 1)
|
||
|
return 0;
|
||
|
|
||
|
/* we need 1 argument of type double */
|
||
|
argtypes[0] = ufmt_double;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_printf_currency_handler(UFILE *stream,
|
||
|
const u_printf_spec_info *info,
|
||
|
const ufmt_args *args)
|
||
|
{
|
||
|
int32_t written = 0;
|
||
|
int32_t len;
|
||
|
double num = (double) (args[0].doubleValue);
|
||
|
UNumberFormat *format;
|
||
|
UChar result [UFPRINTF_BUFFER_SIZE];
|
||
|
int32_t i, minDecimalDigits;
|
||
|
int32_t maxDecimalDigits;
|
||
|
UErrorCode status = ZERO_ERROR;
|
||
|
|
||
|
|
||
|
/* mask off any necessary bits */
|
||
|
/* if(! info->fIsLongDouble)
|
||
|
num &= DBL_MAX;*/
|
||
|
|
||
|
/* get the formatter */
|
||
|
format = u_locbund_getCurrencyFormat(stream->fBundle);
|
||
|
|
||
|
/* handle error */
|
||
|
if(format == 0)
|
||
|
return 0;
|
||
|
|
||
|
/* set the appropriate flags on the formatter */
|
||
|
|
||
|
/* clone the stream's bundle if it isn't owned */
|
||
|
if(! stream->fOwnBundle) {
|
||
|
stream->fBundle = u_locbund_clone(stream->fBundle);
|
||
|
stream->fOwnBundle = TRUE;
|
||
|
format = u_locbund_getCurrencyFormat(stream->fBundle);
|
||
|
}
|
||
|
|
||
|
/* set the number of decimal digits */
|
||
|
|
||
|
/* save the formatter's state */
|
||
|
minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
|
||
|
maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
|
||
|
|
||
|
if(info->fPrecision != -1) {
|
||
|
/* set the # of decimal digits */
|
||
|
unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
|
||
|
}
|
||
|
else if(info->fPrecision == 0 && ! info->fAlt) {
|
||
|
/* no decimal point in this case */
|
||
|
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0);
|
||
|
}
|
||
|
else if(info->fAlt) {
|
||
|
/* '#' means always show decimal point */
|
||
|
/* copy of printf behavior on Solaris - '#' shows 6 digits */
|
||
|
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
|
||
|
}
|
||
|
else {
|
||
|
/* # of decimal digits is 6 if precision not specified */
|
||
|
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
|
||
|
}
|
||
|
|
||
|
/* set whether to show the sign */
|
||
|
if(info->fShowSign) {
|
||
|
/* set whether to show the sign*/
|
||
|
/* {sfb} TBD */
|
||
|
}
|
||
|
|
||
|
/* format the number */
|
||
|
unum_formatDouble(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status);
|
||
|
len = u_strlen(result);
|
||
|
|
||
|
/* pad and justify, if needed */
|
||
|
if(info->fWidth != -1 && len < info->fWidth) {
|
||
|
/* left justify */
|
||
|
if(info->fLeft) {
|
||
|
written = u_file_write(result, len, stream);
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
}
|
||
|
/* right justify */
|
||
|
else {
|
||
|
written = 0;
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
written += u_file_write(result, len, stream);
|
||
|
}
|
||
|
}
|
||
|
/* just write the formatted output */
|
||
|
else
|
||
|
written = u_file_write(result, len, stream);
|
||
|
|
||
|
/* restore the number format */
|
||
|
unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
|
||
|
unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
|
||
|
|
||
|
return written;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_printf_ustring_info(const u_printf_spec_info *info,
|
||
|
int32_t *argtypes,
|
||
|
int32_t n)
|
||
|
{
|
||
|
/* handle error */
|
||
|
if(n < 1)
|
||
|
return 0;
|
||
|
|
||
|
/* we need 1 argument of type ustring */
|
||
|
argtypes[0] = ufmt_ustring;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_printf_ustring_handler(UFILE *stream,
|
||
|
const u_printf_spec_info *info,
|
||
|
const ufmt_args *args)
|
||
|
{
|
||
|
int32_t len, written, i;
|
||
|
const UChar *arg = (const UChar*)(args[0].ptrValue);
|
||
|
|
||
|
/* allocate enough space for the buffer */
|
||
|
len = u_strlen(arg);
|
||
|
|
||
|
/* width = minimum # of characters to write */
|
||
|
/* precision = maximum # of characters to write */
|
||
|
|
||
|
/* precision takes precedence over width */
|
||
|
/* determine if the string should be truncated */
|
||
|
if(info->fPrecision != -1 && len > info->fPrecision) {
|
||
|
written = u_file_write(arg, info->fPrecision, stream);
|
||
|
}
|
||
|
|
||
|
/* determine if the string should be padded */
|
||
|
else if(info->fWidth != -1 && len < info->fWidth) {
|
||
|
/* left justify */
|
||
|
if(info->fLeft) {
|
||
|
written = u_file_write(arg, len, stream);
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
}
|
||
|
/* right justify */
|
||
|
else {
|
||
|
written = 0;
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
written += u_file_write(arg, len, stream);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* just write the string */
|
||
|
else
|
||
|
written = u_file_write(arg, len, stream);
|
||
|
|
||
|
return written;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
int32_t
|
||
|
u_printf_uchar_info(const u_printf_spec_info *info,
|
||
|
int32_t *argtypes,
|
||
|
int32_t n)
|
||
|
{
|
||
|
/* handle error */
|
||
|
if(n < 1)
|
||
|
return 0;
|
||
|
|
||
|
/* we need 1 argument of type uchar */
|
||
|
argtypes[0] = ufmt_uchar;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_printf_uchar_handler(UFILE *stream,
|
||
|
const u_printf_spec_info *info,
|
||
|
const ufmt_args *args)
|
||
|
{
|
||
|
int32_t written = 0, i;
|
||
|
UChar arg = (UChar)(args[0].intValue);
|
||
|
|
||
|
|
||
|
/* width = minimum # of characters to write */
|
||
|
/* precision = maximum # of characters to write */
|
||
|
|
||
|
/* precision takes precedence over width */
|
||
|
/* determine if the char should be printed */
|
||
|
if(info->fPrecision != -1 && info->fPrecision < 1) {
|
||
|
/* write nothing */
|
||
|
written = 0;
|
||
|
}
|
||
|
|
||
|
/* determine if the character should be padded */
|
||
|
else if(info->fWidth != -1 && info->fWidth > 1) {
|
||
|
/* left justify */
|
||
|
if(info->fLeft) {
|
||
|
written = u_file_write(&arg, 1, stream);
|
||
|
for(i = 0; i < info->fWidth - 1; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
}
|
||
|
/* right justify */
|
||
|
else {
|
||
|
written = 0;
|
||
|
for(i = 0; i < info->fWidth - 1; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
written += u_file_write(&arg, 1, stream);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* just write the character */
|
||
|
else
|
||
|
written = u_file_write(&arg, 1, stream);
|
||
|
|
||
|
return written;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_printf_scidbl_info(const u_printf_spec_info *info,
|
||
|
int32_t *argtypes,
|
||
|
int32_t n)
|
||
|
{
|
||
|
/* handle error */
|
||
|
if(n < 1)
|
||
|
return 0;
|
||
|
|
||
|
/* we need 1 argument of type double */
|
||
|
argtypes[0] = ufmt_double;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_printf_scidbl_handler(UFILE *stream,
|
||
|
const u_printf_spec_info *info,
|
||
|
const ufmt_args *args)
|
||
|
{
|
||
|
double num = (double)(args[0].doubleValue);
|
||
|
bool_t useE;
|
||
|
|
||
|
/* a precision of 0 is taken as 1 */
|
||
|
if(info->fPrecision == 0)
|
||
|
((u_printf_spec_info*)info)->fPrecision = 1;
|
||
|
|
||
|
/* determine whether to use 'e' or 'f' */
|
||
|
useE = (num < 0.0001 || (info->fPrecision != -1 && num > pow(10.0, info->fPrecision)));
|
||
|
|
||
|
/* use 'e' */
|
||
|
if(useE) {
|
||
|
/* adjust the specifier */
|
||
|
((u_printf_spec_info*)info)->fSpec = 0x0065;
|
||
|
/* call the scientific handler */
|
||
|
return u_printf_scientific_handler(stream, info, args);
|
||
|
}
|
||
|
/* use 'f' */
|
||
|
else {
|
||
|
/* adjust the specifier */
|
||
|
((u_printf_spec_info*)info)->fSpec = 0x0066;
|
||
|
/* call the double handler */
|
||
|
return u_printf_double_handler(stream, info, args);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
int32_t
|
||
|
u_printf_count_info(const u_printf_spec_info *info,
|
||
|
int32_t *argtypes,
|
||
|
int32_t n)
|
||
|
{
|
||
|
/* handle error */
|
||
|
if(n < 1)
|
||
|
return 0;
|
||
|
|
||
|
/* we need 1 argument of type count */
|
||
|
argtypes[0] = ufmt_count;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_printf_count_handler(UFILE *stream,
|
||
|
const u_printf_spec_info *info,
|
||
|
const ufmt_args *args)
|
||
|
{
|
||
|
int *count = (int*)(args[0].ptrValue);
|
||
|
|
||
|
/* in the special case of count, the u_printf_spec_info's width */
|
||
|
/* will contain the # of chars written thus far */
|
||
|
*count = info->fWidth;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
int32_t
|
||
|
u_printf_spellout_info(const u_printf_spec_info *info,
|
||
|
int32_t *argtypes,
|
||
|
int32_t n)
|
||
|
{
|
||
|
/* handle error */
|
||
|
if(n < 1)
|
||
|
return 0;
|
||
|
|
||
|
/* we need 1 argument of type double */
|
||
|
argtypes[0] = ufmt_double;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int32_t
|
||
|
u_printf_spellout_handler(UFILE *stream,
|
||
|
const u_printf_spec_info *info,
|
||
|
const ufmt_args *args)
|
||
|
{
|
||
|
int32_t written = 0;
|
||
|
int32_t len;
|
||
|
double num = (double) (args[0].doubleValue);
|
||
|
UNumberFormat *format;
|
||
|
UChar result [UFPRINTF_BUFFER_SIZE];
|
||
|
int32_t i, minDecimalDigits;
|
||
|
int32_t maxDecimalDigits;
|
||
|
UErrorCode status = ZERO_ERROR;
|
||
|
|
||
|
|
||
|
/* mask off any necessary bits */
|
||
|
/* if(! info->fIsLongDouble)
|
||
|
num &= DBL_MAX;*/
|
||
|
|
||
|
/* get the formatter */
|
||
|
format = u_locbund_getSpelloutFormat(stream->fBundle);
|
||
|
|
||
|
/* handle error */
|
||
|
if(format == 0)
|
||
|
return 0;
|
||
|
|
||
|
/* set the appropriate flags on the formatter */
|
||
|
|
||
|
/* clone the stream's bundle if it isn't owned */
|
||
|
if(! stream->fOwnBundle) {
|
||
|
stream->fBundle = u_locbund_clone(stream->fBundle);
|
||
|
stream->fOwnBundle = TRUE;
|
||
|
format = u_locbund_getSpelloutFormat(stream->fBundle);
|
||
|
}
|
||
|
|
||
|
/* set the number of decimal digits */
|
||
|
|
||
|
/* save the formatter's state */
|
||
|
minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
|
||
|
maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
|
||
|
|
||
|
if(info->fPrecision != -1) {
|
||
|
/* set the # of decimal digits */
|
||
|
unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
|
||
|
}
|
||
|
else if(info->fPrecision == 0 && ! info->fAlt) {
|
||
|
/* no decimal point in this case */
|
||
|
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0);
|
||
|
}
|
||
|
else if(info->fAlt) {
|
||
|
/* '#' means always show decimal point */
|
||
|
/* copy of printf behavior on Solaris - '#' shows 6 digits */
|
||
|
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
|
||
|
}
|
||
|
else {
|
||
|
/* # of decimal digits is 6 if precision not specified */
|
||
|
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
|
||
|
}
|
||
|
|
||
|
/* set whether to show the sign */
|
||
|
if(info->fShowSign) {
|
||
|
/* set whether to show the sign*/
|
||
|
/* {sfb} TBD */
|
||
|
}
|
||
|
|
||
|
/* format the number */
|
||
|
unum_formatDouble(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status);
|
||
|
len = u_strlen(result);
|
||
|
|
||
|
/* pad and justify, if needed */
|
||
|
if(info->fWidth != -1 && len < info->fWidth) {
|
||
|
/* left justify */
|
||
|
if(info->fLeft) {
|
||
|
written = u_file_write(result, len, stream);
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
}
|
||
|
/* right justify */
|
||
|
else {
|
||
|
written = 0;
|
||
|
for(i = 0; i < info->fWidth - len; ++i)
|
||
|
written += u_file_write(&info->fPadChar, 1, stream);
|
||
|
written += u_file_write(result, len, stream);
|
||
|
}
|
||
|
}
|
||
|
/* just write the formatted output */
|
||
|
else
|
||
|
written = u_file_write(result, len, stream);
|
||
|
|
||
|
/* restore the number format */
|
||
|
unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
|
||
|
unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
|
||
|
|
||
|
return written;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
u_printf_init()
|
||
|
{
|
||
|
int32_t i;
|
||
|
/*Mutex *lock;*/
|
||
|
|
||
|
/* if we're already inited, do nothing */
|
||
|
if(g_u_printf_inited)
|
||
|
return;
|
||
|
|
||
|
/* lock the cache */
|
||
|
umtx_lock(0);
|
||
|
|
||
|
/* if we're already inited, do nothing */
|
||
|
if(g_u_printf_inited) {
|
||
|
umtx_unlock(0);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* initialize all handlers and infos to 0 */
|
||
|
for(i = 0; i < 256; ++i) {
|
||
|
g_u_printf_infos[i] = 0;
|
||
|
g_u_printf_handlers[i] = 0;
|
||
|
}
|
||
|
|
||
|
/* register the handlers for standard specifiers */
|
||
|
/* don't use u_printf_register_handler to avoid mutex creation */
|
||
|
|
||
|
/* handle '%' */
|
||
|
g_u_printf_infos[ 0x0025 ] = u_printf_simple_percent_info;
|
||
|
g_u_printf_handlers[ 0x0025 ] = u_printf_simple_percent_handler;
|
||
|
|
||
|
/* handle 's' */
|
||
|
g_u_printf_infos[ 0x0073 ] = u_printf_string_info;
|
||
|
g_u_printf_handlers[ 0x0073 ] = u_printf_string_handler;
|
||
|
|
||
|
/* handle 'd' */
|
||
|
g_u_printf_infos[ 0x0064 ] = u_printf_integer_info;
|
||
|
g_u_printf_handlers[ 0x0064 ] = u_printf_integer_handler;
|
||
|
|
||
|
/* handle 'i' */
|
||
|
g_u_printf_infos[ 0x0069 ] = u_printf_integer_info;
|
||
|
g_u_printf_handlers[ 0x0069 ] = u_printf_integer_handler;
|
||
|
|
||
|
/* handle 'o' */
|
||
|
g_u_printf_infos[ 0x006F ] = u_printf_octal_info;
|
||
|
g_u_printf_handlers[ 0x006F ] = u_printf_octal_handler;
|
||
|
|
||
|
/* handle 'u' */
|
||
|
g_u_printf_infos[ 0x0075 ] = u_printf_integer_info;
|
||
|
g_u_printf_handlers[ 0x0075 ] = u_printf_integer_handler;
|
||
|
|
||
|
/* handle 'x' */
|
||
|
g_u_printf_infos[ 0x0078 ] = u_printf_hex_info;
|
||
|
g_u_printf_handlers[ 0x0078 ] = u_printf_hex_handler;
|
||
|
|
||
|
/* handle 'X' */
|
||
|
g_u_printf_infos[ 0x0058 ] = u_printf_hex_info;
|
||
|
g_u_printf_handlers[ 0x0058 ] = u_printf_hex_handler;
|
||
|
|
||
|
/* handle 'f' */
|
||
|
g_u_printf_infos[ 0x0066 ] = u_printf_double_info;
|
||
|
g_u_printf_handlers[ 0x0066 ] = u_printf_double_handler;
|
||
|
|
||
|
/* handle 'c' */
|
||
|
g_u_printf_infos[ 0x0063 ] = u_printf_char_info;
|
||
|
g_u_printf_handlers[ 0x0063 ] = u_printf_char_handler;
|
||
|
|
||
|
/* handle 'p' */
|
||
|
g_u_printf_infos[ 0x0070 ] = u_printf_pointer_info;
|
||
|
g_u_printf_handlers[ 0x0070 ] = u_printf_pointer_handler;
|
||
|
|
||
|
/* handle 'e' */
|
||
|
g_u_printf_infos[ 0x0065 ] = u_printf_scientific_info;
|
||
|
g_u_printf_handlers[ 0x0065 ] = u_printf_scientific_handler;
|
||
|
|
||
|
/* handle 'E' */
|
||
|
g_u_printf_infos[ 0x0045 ] = u_printf_scientific_info;
|
||
|
g_u_printf_handlers[ 0x0045 ] = u_printf_scientific_handler;
|
||
|
|
||
|
/* handle 'D' */
|
||
|
g_u_printf_infos[ 0x0044 ] = u_printf_date_info;
|
||
|
g_u_printf_handlers[ 0x0044 ] = u_printf_date_handler;
|
||
|
|
||
|
/* handle 'P' */
|
||
|
g_u_printf_infos[ 0x0050 ] = u_printf_percent_info;
|
||
|
g_u_printf_handlers[ 0x0050 ] = u_printf_percent_handler;
|
||
|
|
||
|
/* handle 'M' */
|
||
|
g_u_printf_infos[ 0x004D ] = u_printf_currency_info;
|
||
|
g_u_printf_handlers[ 0x004D ] = u_printf_currency_handler;
|
||
|
|
||
|
/* handle 'T' */
|
||
|
g_u_printf_infos[ 0x0054 ] = u_printf_time_info;
|
||
|
g_u_printf_handlers[ 0x0054 ] = u_printf_time_handler;
|
||
|
|
||
|
/* handle 'K' */
|
||
|
g_u_printf_infos[ 0x004B ] = u_printf_uchar_info;
|
||
|
g_u_printf_handlers[ 0x004B ] = u_printf_uchar_handler;
|
||
|
|
||
|
/* handle 'U' */
|
||
|
g_u_printf_infos[ 0x0055 ] = u_printf_ustring_info;
|
||
|
g_u_printf_handlers[ 0x0055 ] = u_printf_ustring_handler;
|
||
|
|
||
|
/* handle 'g' */
|
||
|
g_u_printf_infos[ 0x0067 ] = u_printf_scidbl_info;
|
||
|
g_u_printf_handlers[ 0x0067 ] = u_printf_scidbl_handler;
|
||
|
|
||
|
/* handle 'G' */
|
||
|
g_u_printf_infos[ 0x0047 ] = u_printf_scidbl_info;
|
||
|
g_u_printf_handlers[ 0x0047 ] = u_printf_scidbl_handler;
|
||
|
|
||
|
/* handle 'n' */
|
||
|
g_u_printf_infos[ 0x006E ] = u_printf_count_info;
|
||
|
g_u_printf_handlers[ 0x006E ] = u_printf_count_handler;
|
||
|
|
||
|
/* handle 'V' */
|
||
|
g_u_printf_infos[ 0x0056 ] = u_printf_spellout_info;
|
||
|
g_u_printf_handlers[ 0x0056 ] = u_printf_spellout_handler;
|
||
|
|
||
|
|
||
|
/* we're finished */
|
||
|
g_u_printf_inited = TRUE;
|
||
|
|
||
|
/* unlock the cache */
|
||
|
umtx_unlock(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
#define U_PRINTF_MAX_ARGS 32
|
||
|
#define UP_PERCENT 0x0025
|
||
|
|
||
|
int32_t
|
||
|
u_vfprintf_u( UFILE *f,
|
||
|
const UChar *patternSpecification,
|
||
|
va_list ap)
|
||
|
{
|
||
|
u_printf_spec spec;
|
||
|
const UChar *alias;
|
||
|
int32_t count, written;
|
||
|
|
||
|
int32_t num_args_wanted;
|
||
|
int32_t ufmt_types [U_PRINTF_MAX_ARGS];
|
||
|
ufmt_args args[U_PRINTF_MAX_ARGS];
|
||
|
|
||
|
u_printf_info info;
|
||
|
u_printf_handler handler;
|
||
|
|
||
|
int32_t cur_arg;
|
||
|
|
||
|
|
||
|
/* init our function tables */
|
||
|
if(! g_u_printf_inited)
|
||
|
u_printf_init();
|
||
|
|
||
|
/* alias the pattern */
|
||
|
alias = patternSpecification;
|
||
|
|
||
|
/* haven't written anything yet */
|
||
|
written = 0;
|
||
|
|
||
|
/* iterate through the pattern */
|
||
|
for(;;) {
|
||
|
|
||
|
/* find the next '%' */
|
||
|
count = 0;
|
||
|
while(*alias != UP_PERCENT && *alias != 0x0000) {
|
||
|
*alias++;
|
||
|
++count;
|
||
|
}
|
||
|
|
||
|
/* write any characters before the '%' */
|
||
|
if(count > 0)
|
||
|
written += u_file_write(alias - count, count, f);
|
||
|
|
||
|
/* break if at end of string */
|
||
|
if(*alias == 0x0000)
|
||
|
break;
|
||
|
|
||
|
/* parse the specifier */
|
||
|
count = u_printf_parse_spec(alias, &spec);
|
||
|
|
||
|
/* fill in the precision and width, if specified out of line */
|
||
|
|
||
|
/* width specified out of line */
|
||
|
if(spec.fInfo.fWidth == -2) {
|
||
|
if(spec.fWidthPos != -1) {
|
||
|
/* handle positional parameter */
|
||
|
}
|
||
|
else {
|
||
|
/* read the width from the argument list */
|
||
|
spec.fInfo.fWidth = va_arg(ap, int);
|
||
|
}
|
||
|
|
||
|
/* if it's negative, take the absolute value and set left alignment */
|
||
|
if(spec.fInfo.fWidth < 0) {
|
||
|
spec.fInfo.fWidth *= -1;
|
||
|
spec.fInfo.fLeft = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* precision specified out of line */
|
||
|
if(spec.fInfo.fPrecision == -2) {
|
||
|
if(spec.fPrecisionPos != -1) {
|
||
|
/* handle positional parameter */
|
||
|
}
|
||
|
else {
|
||
|
/* read the precision from the argument list */
|
||
|
spec.fInfo.fPrecision = va_arg(ap, int);
|
||
|
}
|
||
|
|
||
|
/* if it's negative, set it to zero */
|
||
|
if(spec.fInfo.fPrecision < 0)
|
||
|
spec.fInfo.fPrecision = 0;
|
||
|
}
|
||
|
|
||
|
/* query the info function for argument information */
|
||
|
info = g_u_printf_infos[ (unsigned char) spec.fInfo.fSpec ];
|
||
|
if(info != 0) {
|
||
|
num_args_wanted = (*info)(&spec.fInfo,
|
||
|
ufmt_types,
|
||
|
U_PRINTF_MAX_ARGS);
|
||
|
}
|
||
|
else
|
||
|
num_args_wanted = 0;
|
||
|
|
||
|
/* fill in the requested arguments */
|
||
|
for(cur_arg = 0;
|
||
|
cur_arg < num_args_wanted && cur_arg < U_PRINTF_MAX_ARGS;
|
||
|
++cur_arg) {
|
||
|
|
||
|
switch(ufmt_types[cur_arg]) {
|
||
|
|
||
|
case ufmt_count:
|
||
|
args[cur_arg].intValue = va_arg(ap, int);
|
||
|
/* set the spec's width to the # of chars written */
|
||
|
spec.fInfo.fWidth = written;
|
||
|
break;
|
||
|
|
||
|
case ufmt_int:
|
||
|
args[cur_arg].intValue = va_arg(ap, int);
|
||
|
break;
|
||
|
|
||
|
case ufmt_char:
|
||
|
args[cur_arg].intValue = va_arg(ap, int);
|
||
|
break;
|
||
|
|
||
|
case ufmt_wchar:
|
||
|
args[cur_arg].wcharValue = va_arg(ap, wchar_t);
|
||
|
break;
|
||
|
|
||
|
case ufmt_string:
|
||
|
args[cur_arg].ptrValue = va_arg(ap, char*);
|
||
|
break;
|
||
|
|
||
|
case ufmt_wstring:
|
||
|
args[cur_arg].ptrValue = va_arg(ap, wchar_t*);
|
||
|
break;
|
||
|
|
||
|
case ufmt_pointer:
|
||
|
args[cur_arg].ptrValue = va_arg(ap, void*);
|
||
|
break;
|
||
|
|
||
|
case ufmt_float:
|
||
|
args[cur_arg].floatValue = va_arg(ap, float);
|
||
|
break;
|
||
|
|
||
|
case ufmt_double:
|
||
|
args[cur_arg].doubleValue = va_arg(ap, double);
|
||
|
break;
|
||
|
|
||
|
case ufmt_date:
|
||
|
args[cur_arg].dateValue = va_arg(ap, UDate);
|
||
|
break;
|
||
|
|
||
|
case ufmt_ustring:
|
||
|
args[cur_arg].ptrValue = va_arg(ap, UChar*);
|
||
|
break;
|
||
|
|
||
|
case ufmt_uchar:
|
||
|
args[cur_arg].intValue = va_arg(ap, int);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* call the handler function */
|
||
|
handler = g_u_printf_handlers[ (unsigned char) spec.fInfo.fSpec ];
|
||
|
if(handler != 0) {
|
||
|
written += (*handler)(f, &spec.fInfo, args);
|
||
|
}
|
||
|
/* just echo unknown tags */
|
||
|
else
|
||
|
written += u_file_write(alias, count, f);
|
||
|
|
||
|
/* update the pointer in pattern and continue */
|
||
|
alias += count;
|
||
|
}
|
||
|
|
||
|
/* return # of UChars written */
|
||
|
return written;
|
||
|
}
|
||
|
|