// © 2016 and later: Unicode, Inc. and others. // License & terms of use: http://www.unicode.org/copyright.html /* ****************************************************************************** * * Copyright (C) 2001-2014, International Business Machines * Corporation and others. All Rights Reserved. * ****************************************************************************** * * File sprintf.c * * Modification History: * * Date Name Description * 02/08/2001 george Creation. Copied from uprintf.c * 03/27/2002 Mark Schneckloth Many fixes regarding alignment, null termination * (mschneckloth@atomz.com) and other various problems. * 08/07/2003 george Reunify printf implementations ******************************************************************************* */ #include "unicode/utypes.h" #if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_CONVERSION #include "unicode/ustdio.h" #include "unicode/ustring.h" #include "unicode/putil.h" #include "uprintf.h" #include "locbund.h" #include "cmemory.h" #include /* u_minstrncpy copies the minimum number of code units of (count or output->available) */ static int32_t u_sprintf_write(void *context, const char16_t *str, int32_t count) { u_localized_print_string *output = (u_localized_print_string *)context; /* just calculating buffer size */ if (output->str == nullptr) { return count; } int32_t size = ufmt_min(count, output->available); u_strncpy(output->str + (output->len - output->available), str, size); output->available -= size; return size; } static int32_t u_sprintf_pad_and_justify(void *context, const u_printf_spec_info *info, const char16_t *result, int32_t resultLen) { u_localized_print_string *output = (u_localized_print_string *)context; int32_t written = 0; int32_t lengthOfResult = resultLen; /* just calculating buffer size */ if (output->str == nullptr && info->fWidth != -1 && resultLen < info->fWidth) { return info->fWidth; } resultLen = ufmt_min(resultLen, output->available); /* pad and justify, if needed */ if(info->fWidth != -1 && resultLen < info->fWidth) { int32_t paddingLeft = info->fWidth - resultLen; int32_t outputPos = output->len - output->available; if (paddingLeft + resultLen > output->available) { paddingLeft = output->available - resultLen; if (paddingLeft < 0) { paddingLeft = 0; } /* paddingLeft = output->available - resultLen;*/ } written += paddingLeft; /* left justify */ if(info->fLeft) { written += u_sprintf_write(output, result, resultLen); u_memset(&output->str[outputPos + resultLen], info->fPadChar, paddingLeft); output->available -= paddingLeft; } /* right justify */ else { u_memset(&output->str[outputPos], info->fPadChar, paddingLeft); output->available -= paddingLeft; written += u_sprintf_write(output, result, resultLen); } } /* just write the formatted output */ else { written = u_sprintf_write(output, result, resultLen); } if (written >= 0 && lengthOfResult > written) { return lengthOfResult; } return written; } U_CAPI int32_t U_EXPORT2 u_sprintf(char16_t *buffer, const char *patternSpecification, ... ) { va_list ap; int32_t written; va_start(ap, patternSpecification); written = u_vsnprintf(buffer, INT32_MAX, patternSpecification, ap); va_end(ap); return written; } U_CAPI int32_t U_EXPORT2 u_sprintf_u(char16_t *buffer, const char16_t *patternSpecification, ... ) { va_list ap; int32_t written; va_start(ap, patternSpecification); written = u_vsnprintf_u(buffer, INT32_MAX, patternSpecification, ap); va_end(ap); return written; } U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ u_vsprintf(char16_t *buffer, const char *patternSpecification, va_list ap) { return u_vsnprintf(buffer, INT32_MAX, patternSpecification, ap); } U_CAPI int32_t U_EXPORT2 u_snprintf(char16_t *buffer, int32_t count, const char *patternSpecification, ... ) { va_list ap; int32_t written; va_start(ap, patternSpecification); written = u_vsnprintf(buffer, count, patternSpecification, ap); va_end(ap); return written; } U_CAPI int32_t U_EXPORT2 u_snprintf_u(char16_t *buffer, int32_t count, const char16_t *patternSpecification, ... ) { va_list ap; int32_t written; va_start(ap, patternSpecification); written = u_vsnprintf_u(buffer, count, patternSpecification, ap); va_end(ap); return written; } U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ u_vsnprintf(char16_t *buffer, int32_t count, const char *patternSpecification, va_list ap) { int32_t written; char16_t *pattern; char16_t patBuffer[UFMT_DEFAULT_BUFFER_SIZE]; int32_t size = (int32_t)strlen(patternSpecification) + 1; /* convert from the default codepage to Unicode */ if (size >= (int32_t)MAX_UCHAR_BUFFER_SIZE(patBuffer)) { pattern = (char16_t *)uprv_malloc(size * sizeof(char16_t)); if (pattern == nullptr) { return 0; } } else { pattern = patBuffer; } u_charsToUChars(patternSpecification, pattern, size); /* do the work */ written = u_vsnprintf_u(buffer, count, pattern, ap); /* clean up */ if (pattern != patBuffer) { uprv_free(pattern); } return written; } U_CAPI int32_t U_EXPORT2 u_vsprintf_u(char16_t *buffer, const char16_t *patternSpecification, va_list ap) { return u_vsnprintf_u(buffer, INT32_MAX, patternSpecification, ap); } static const u_printf_stream_handler g_sprintf_stream_handler = { u_sprintf_write, u_sprintf_pad_and_justify }; U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ u_vsnprintf_u(char16_t *buffer, int32_t count, const char16_t *patternSpecification, va_list ap) { int32_t written = 0; /* haven't written anything yet */ int32_t result = 0; /* test the return value of u_printf_parse */ u_localized_print_string outStr; if (count < 0) { count = INT32_MAX; } outStr.str = buffer; outStr.len = count; outStr.available = count; if (u_locbund_init(&outStr.fBundle, "en_US_POSIX") == nullptr) { return 0; } /* parse and print the whole format string */ result = u_printf_parse(&g_sprintf_stream_handler, patternSpecification, &outStr, &outStr, &outStr.fBundle, &written, ap); /* Terminate the buffer, if there's room. */ if (outStr.available > 0) { buffer[outStr.len - outStr.available] = 0x0000; } /* Release the cloned bundle, if we cloned it. */ u_locbund_close(&outStr.fBundle); /* parsing error */ if (result < 0) { return result; } /* return # of UChars written */ return written; } #endif /* #if !UCONFIG_NO_FORMATTING */