#include #include #include #include #include #include #include #include #include #include #include #define MAX_SIG_DIG 32 #define LDBL_MANT_DIG 24 #define LDBL_MAX_EXP 128 #define TARGET_FLOAT_BITS 32 #define TARGET_FLOAT_BYTES (TARGET_FLOAT_BITS / 8) #define TARGET_FLOAT_MAX_EXP LDBL_MAX_EXP #define TARGET_FLOAT_MANT_DIG LDBL_MANT_DIG #define TARGET_FLOAT_IMPLICIT_J_BIT 1 #define TARGET_FLOAT_MANT_BITS (TARGET_FLOAT_MANT_DIG - TARGET_FLOAT_IMPLICIT_J_BIT) #define TARGET_FLOAT_EXP_BITS (TARGET_FLOAT_BITS - TARGET_FLOAT_MANT_BITS - 1) typedef long long intmax_t; #define PTRDIFF __typeof__((char *) 0 - (char *) 0) typedef PTRDIFF ptrdiff_t; int vswprintf(wchar_t *s, size_t n, const wchar_t *format, va_list arg); enum justification_options { left_justification, right_justification, zero_fill }; enum sign_options { only_minus, sign_always, space_holder }; enum argument_options { // normal_argument, // char_argument, // short_argument, // long_argument, // long_long_argument, // wchar_argument, // intmax_argument, // size_t_argument, // ptrdiff_argument, // long_double_argument normal_argument, char_argument, short_argument, long_argument, long_long_argument, wchar_argument, intmax_argument, size_t_argument, ptrdiff_argument, long_double_argument }; typedef struct { unsigned char justification_options; unsigned char sign_options; unsigned char precision_specified; unsigned char alternate_form; unsigned char argument_options; wchar_t conversion_char; int field_width; int precision; } print_format; typedef struct { char *CharStr; size_t MaxCharCount; size_t CharsWritten; } __OutStrCtrl; #define conversion_buff_size 512 #define conversion_max 509 #define bad_conversion 0xFFFF static const wchar_t *parse_format(const wchar_t *format_string, va_list *arg, print_format *format) { print_format f; const wchar_t *s = format_string; int c; int flag_found; f.justification_options = right_justification; f.sign_options = only_minus; f.precision_specified = 0; f.alternate_form = 0; f.argument_options = normal_argument; f.field_width = 0; f.precision = 0; if ((c = *++s) == L'%') { f.conversion_char = c; *format = f; return ((const wchar_t *) s + 1); } while (true) { flag_found = 1; switch (c) { case L'-': f.justification_options = left_justification; break; case L'+': f.sign_options = sign_always; break; case L' ': if (f.sign_options != sign_always) { f.sign_options = space_holder; } break; case L'#': f.alternate_form = 1; break; case L'0': if (f.justification_options != left_justification) { f.justification_options = zero_fill; } break; default: flag_found = 0; break; } if (flag_found) { c = *++s; } else { break; } } if (c == L'*') { if ((f.field_width = va_arg(*arg, int)) < 0) { f.justification_options = left_justification; f.field_width = -f.field_width; } c = *++s; } else { while (isdigit(c)) { f.field_width = (f.field_width * 10) + (c - L'0'); c = *++s; } } if (f.field_width > conversion_max) { f.conversion_char = bad_conversion; *format = f; return ((const wchar_t *) s + 1); } if (c == L'.') { f.precision_specified = 1; if ((c = *++s) == L'*') { if ((f.precision = va_arg(*arg, int)) < 0) { f.precision_specified = 0; } c = *++s; } else { while (isdigit(c)) { f.precision = (f.precision * 10) + (c - L'0'); c = *++s; } } } flag_found = 1; switch (c) { case L'h': f.argument_options = short_argument; if (s[1] == L'h') { f.argument_options = char_argument; c = *++s; } break; case L'l': f.argument_options = long_argument; if (s[1] == L'l') { f.argument_options = long_long_argument; c = *++s; } break; case L'L': f.argument_options = long_double_argument; break; case L'j': f.argument_options = intmax_argument; break; case L't': f.argument_options = ptrdiff_argument; break; case L'z': f.argument_options = size_t_argument; break; default: flag_found = 0; break; } if (flag_found) { c = *++s; } f.conversion_char = c; switch (c) { case L'd': case L'i': case L'u': case L'o': case L'x': case L'X': if (f.argument_options == long_double_argument) { f.argument_options = long_long_argument; } if (!f.precision_specified) { f.precision = 1; } else if (f.justification_options == zero_fill) { f.justification_options = right_justification; } break; case L'f': case L'F': if (f.argument_options == short_argument || f.argument_options == intmax_argument || f.argument_options == size_t_argument || f.argument_options == ptrdiff_argument || f.argument_options == long_long_argument) { f.conversion_char = bad_conversion; break; } if (!f.precision_specified) { f.precision = 6; } break; case L'a': case L'A': if (!f.precision_specified) { f.precision = 0x0D; } if (f.argument_options == short_argument || f.argument_options == intmax_argument || f.argument_options == size_t_argument || f.argument_options == ptrdiff_argument || f.argument_options == long_long_argument || f.argument_options == char_argument) { f.conversion_char = bad_conversion; } break; case L'g': case L'G': if (!f.precision) { f.precision = 1; } case L'e': case L'E': if (f.argument_options == short_argument || f.argument_options == char_argument || f.argument_options == intmax_argument || f.argument_options == size_t_argument || f.argument_options == ptrdiff_argument || f.argument_options == long_long_argument) { f.conversion_char = bad_conversion; break; } if (!f.precision_specified) { f.precision = 6; } break; case L'p': f.argument_options = long_argument; f.alternate_form = 1; f.conversion_char = L'x'; f.precision = 8; break; case L'c': if (f.argument_options == long_argument) { f.argument_options = wchar_argument; } else if (f.precision_specified || f.argument_options != normal_argument) { f.conversion_char = bad_conversion; } break; case L's': if (f.argument_options == long_argument) { f.argument_options = wchar_argument; } else if (f.argument_options != normal_argument) { f.conversion_char = bad_conversion; } break; case L'n': if (f.argument_options == long_double_argument) { f.argument_options = long_long_argument; } break; default: f.conversion_char = bad_conversion; break; } *format = f; return ((const wchar_t *) s + 1); } wchar_t *long2str(long num, wchar_t *buff, print_format format) { unsigned long unsigned_num, base; wchar_t *p; int n, digits; int minus = 0; unsigned_num = num; minus = 0; p = buff; *--p = 0; digits = 0; if (!num && !format.precision && !(format.alternate_form && format.conversion_char == L'o')) { return p; } switch (format.conversion_char) { case L'd': case L'i': base = 10; if (num < 0) { if (num != 0x80000000) { unsigned_num = -num; } minus = 1; } break; case L'o': base = 8; format.sign_options = only_minus; break; case L'u': base = 10; format.sign_options = only_minus; break; case L'x': case L'X': base = 16; format.sign_options = only_minus; break; } do { n = unsigned_num % base; unsigned_num /= base; if (n < 10) { n += L'0'; } else { n -= 10; if (format.conversion_char == L'x') { n += L'a'; } else { n += L'A'; } } *--p = n; ++digits; } while (unsigned_num != 0); if (base == 8 && format.alternate_form && *p != L'0') { *--p = L'0'; ++digits; } if (format.justification_options == zero_fill) { format.precision = format.field_width; if (minus || format.sign_options != only_minus) { --format.precision; } if (base == 16 && format.alternate_form) { format.precision -= 2; } } if (buff - p + format.precision > conversion_max) { return 0; } while (digits < format.precision) { *--p = L'0'; ++digits; } if (base == 16 && format.alternate_form) { *--p = format.conversion_char; *--p = L'0'; } if (minus) { *--p = L'-'; } else if (format.sign_options == sign_always) { *--p = L'+'; } else if (format.sign_options == space_holder) { *--p = L' '; } return p; } wchar_t *longlong2str(long long num, wchar_t *pBuf, print_format fmt) { unsigned long long unsigned_num, base; wchar_t *p; int n, digits; int minus = 0; unsigned_num = num; minus = 0; p = pBuf; *--p = 0; digits = 0; if (!num && !fmt.precision && !(fmt.alternate_form && fmt.conversion_char == L'o')) { return p; } switch (fmt.conversion_char) { case L'd': case L'i': base = 10; if (num < 0) { if (num != 0x8000000000000000) { unsigned_num = -num; } minus = 1; } break; case L'o': base = 8; fmt.sign_options = only_minus; break; case L'u': base = 10; fmt.sign_options = only_minus; break; case L'x': case L'X': base = 16; fmt.sign_options = only_minus; break; } do { n = unsigned_num % base; unsigned_num /= base; if (n < 10) { n += L'0'; } else { n -= 10; if (fmt.conversion_char == L'x') { n += L'a'; } else { n += L'A'; } } *--p = n; ++digits; } while (unsigned_num != 0); if (base == 8 && fmt.alternate_form && *p != L'0') { *--p = L'0'; ++digits; } if (fmt.justification_options == zero_fill) { fmt.precision = fmt.field_width; if (minus || fmt.sign_options != only_minus) { --fmt.precision; } if (base == 16 && fmt.alternate_form) { fmt.precision -= 2; } } if (pBuf - p + fmt.precision > conversion_max) { return 0; } while (digits < fmt.precision) { *--p = L'0'; ++digits; } if (base == 16 && fmt.alternate_form) { *--p = fmt.conversion_char; *--p = L'0'; } if (minus) { *--p = L'-'; } else if (fmt.sign_options == sign_always) { *--p = L'+'; } else if (fmt.sign_options == space_holder) { *--p = L' '; } return p; } static wchar_t *double2hex(long double num, wchar_t *buff, print_format format) { wchar_t *p; unsigned char *q; unsigned char working_byte; long double ld; int expbits, expmask; unsigned snum; long exp; print_format exp_format; int hex_precision; int mantissa_bit; decform form; decimal dec; int radix_marker; radix_marker = '.'; p = buff; ld = num; if (format.precision > 509) { return 0; } form.style = (char) 0; form.digits = 0x20; __num2dec(&form, num, &dec); switch (*dec.sig.text) { case '0': dec.exp = 0; if (dec.sgn) { p = buff - 5; if (format.conversion_char == L'A') { wcscpy(p, L"-0X0"); } else { wcscpy(p, L"-0x0"); } } else { p = buff - 4; if (format.conversion_char == L'A') { wcscpy(p, L"0X0"); } else { wcscpy(p, L"0x0"); } } return p; case 'I': if (dec.sgn) { p = buff - 5; if (format.conversion_char == L'A') { wcscpy(p, L"-INF"); } else { wcscpy(p, L"-inf"); } } else { p = buff - 4; if (format.conversion_char == L'A') { wcscpy(p, L"INF"); } else { wcscpy(p, L"inf"); } } return p; case 'N': if (dec.sgn) { p = buff - 5; if (format.conversion_char == L'A') { wcscpy(p, L"-NAN"); } else { wcscpy(p, L"-nan"); } } else { p = buff - 4; if (format.conversion_char == L'A') { wcscpy(p, L"NAN"); } else { wcscpy(p, L"nan"); } } return p; } exp_format.justification_options = right_justification; exp_format.sign_options = sign_always; exp_format.precision_specified = 0; exp_format.alternate_form = 0; exp_format.argument_options = normal_argument; exp_format.field_width = 0; exp_format.precision = 1; exp_format.conversion_char = L'd'; int i; unsigned char *nump = (unsigned char *) # for (i = 0; i < TARGET_FLOAT_BYTES; i++) { unsigned char x = nump[i]; nump[i] = nump[TARGET_FLOAT_BYTES - i + 3]; nump[TARGET_FLOAT_BYTES - i + 3] = x; } expbits = TARGET_FLOAT_EXP_BITS; expmask = 0x7FF; snum = ((unsigned char *) &num)[0] << 25; if (TARGET_FLOAT_EXP_BITS > 7) { snum |= ((unsigned char *) &num)[1] << 17; } if (TARGET_FLOAT_EXP_BITS > 15) { snum |= ((unsigned char *) &num)[2] << 9; } if (TARGET_FLOAT_EXP_BITS > 23) { snum |= ((unsigned char *) &num)[3] << 1; } snum = (snum >> (29 - expbits)) & expmask; if (snum != 0) { exp = snum - 0x3FF; } else { exp = 0; } p = long2str(exp, buff, exp_format); if (format.conversion_char == L'a') { *--p = L'p'; } else { *--p = L'P'; } q = (unsigned char *) # if (TARGET_FLOAT_IMPLICIT_J_BIT) { mantissa_bit = (4 + expbits + format.precision * 4) - 1; } else { mantissa_bit = (1 + expbits + format.precision * 4) - 4; } for (hex_precision = format.precision; hex_precision >= 1; hex_precision--) { if (mantissa_bit < 64) { int mantissa_byte; mantissa_byte = mantissa_bit >> 3; working_byte = (*(q + mantissa_byte)) >> (7 - (mantissa_bit & 7)); if ((mantissa_bit & ~7) != ((mantissa_bit - 4) & ~7)) { working_byte |= ((*(q + (mantissa_byte - 1))) << 8) >> (7 - ((mantissa_bit) & 7)); } if (!TARGET_FLOAT_IMPLICIT_J_BIT) { if (mantissa_bit == 1 + expbits) { *--p = radix_marker; working_byte &= 0x1; } } if ((working_byte &= 0xF) < 10) { working_byte += L'0'; } else if (format.conversion_char == L'a') { working_byte += L'a' - 10; } else { working_byte += L'A' - 10; } } else { working_byte = L'0'; } *--p = working_byte; mantissa_bit -= 4; } if (TARGET_FLOAT_IMPLICIT_J_BIT) { if (format.precision || format.alternate_form) { *--p = radix_marker; } if (fabsl(ld) != 0.0) { *--p = '1'; } else { *--p = '0'; } } if (format.conversion_char == L'a') { *--p = L'x'; } else { *--p = L'X'; } *--p = L'0'; if (dec.sgn) { *--p = L'-'; } else if (format.sign_options == sign_always) { *--p = L'+'; } else if (format.sign_options == space_holder) { *--p = L' '; } return p; } void round_decimal(decimal *dec, int new_length) { unsigned char c; unsigned char *p; int carry; if (new_length < 0) { return_zero: dec->exp = 0; dec->sig.length = 1; *dec->sig.text = L'0'; return; } if (new_length >= dec->sig.length) { return; } p = (unsigned char *) dec->sig.text + new_length + 1; c = *--p - L'0'; if (c == 5) { unsigned char *q = &((unsigned char *) dec->sig.text)[dec->sig.length]; while (--q > p && *q == L'0') ; carry = (q == p) ? p[-1] & 1 : 1; } else { carry = (c > 5); } while (new_length != 0) { c = *--p - L'0' + carry; if ((carry = (c > 9)) != 0 || c == 0) { --new_length; } else { *p = c + L'0'; break; } } if (carry != 0) { dec->exp += 1; dec->sig.length = 1; *dec->sig.text = L'1'; return; } else if (new_length == 0) { goto return_zero; } dec->sig.length = new_length; } wchar_t *float2str(long double num, wchar_t *wbuff, print_format format) { decimal dec; decform form; wchar_t *pw; unsigned char *p; unsigned char buff[512]; unsigned char *q; int n, digits, sign; int int_digits, frac_digits; int radix_marker; radix_marker = '.'; if (format.precision > conversion_max) { return 0; } form.style = 0; form.digits = 0x20; __num2dec(&form, num, &dec); p = (unsigned char *) dec.sig.text + dec.sig.length; while (dec.sig.length > 1 && *--p == L'0') { --dec.sig.length; ++dec.exp; } switch (*dec.sig.text) { case L'0': dec.exp = 0; break; case L'I': if (num < 0) { pw = wbuff - 5; if (isupper(format.conversion_char)) { wcscpy(pw, L"-INF"); } else { wcscpy(pw, L"-inf"); } } else { pw = wbuff - 4; if (isupper(format.conversion_char)) { wcscpy(pw, L"INF"); } else { wcscpy(pw, L"inf"); } } return pw; case L'N': if (dec.sgn) { pw = wbuff - 5; if (isupper(format.conversion_char)) { wcscpy(pw, L"-NAN"); } else { wcscpy(pw, L"-nan"); } } else { pw = wbuff - 4; if (isupper(format.conversion_char)) { wcscpy(pw, L"NAN"); } else { wcscpy(pw, L"nan"); } } return pw; } dec.exp += dec.sig.length - 1; p = buff + 512; *--p = 0; switch (format.conversion_char) { case L'g': case L'G': if (dec.sig.length > format.precision) { round_decimal(&dec, format.precision); } if (dec.exp < -4 || dec.exp >= format.precision) { if (format.alternate_form) { --format.precision; } else { format.precision = dec.sig.length - 1; } if (format.conversion_char == L'g') { format.conversion_char = L'e'; } else { format.conversion_char = L'E'; } goto e_format; } if (format.alternate_form) { format.precision -= dec.exp + 1; } else { if ((format.precision = dec.sig.length - (dec.exp + 1)) < 0) { format.precision = 0; } } goto f_format; case L'e': case L'E': e_format: if (dec.sig.length > format.precision + 1) { round_decimal(&dec, format.precision + 1); } n = dec.exp; sign = L'+'; if (n < 0) { n = -n; sign = L'-'; } for (digits = 0; n || digits < 2; ++digits) { *--p = n % 10 + '0'; n /= 10; } *--p = sign; *--p = format.conversion_char; if (buff - p + format.precision > conversion_max) { return 0; } if (dec.sig.length < format.precision + 1) { for (n = format.precision + 1 - dec.sig.length + 1; --n;) { *--p = L'0'; } } for (n = dec.sig.length, q = (unsigned char *) dec.sig.text + dec.sig.length; --n;) { *--p = *--q; } if (format.precision || format.alternate_form) { *--p = radix_marker; } *--p = *dec.sig.text; if (dec.sgn) { *--p = L'-'; } else if (format.sign_options == sign_always) { *--p = L'+'; } else if (format.sign_options == space_holder) { *--p = L' '; } break; case L'f': case L'F': f_format: if ((frac_digits = -dec.exp + dec.sig.length - 1) < 0) { frac_digits = 0; } if (frac_digits > format.precision) { round_decimal(&dec, dec.sig.length - (frac_digits - format.precision)); if ((frac_digits = -dec.exp + dec.sig.length - 1) < 0) { frac_digits = 0; } } if ((int_digits = dec.exp + 1) < 0) { int_digits = 0; } if (int_digits + frac_digits > conversion_max) { return 0; } q = (unsigned char *) dec.sig.text + dec.sig.length; for (digits = 0; digits < (format.precision - frac_digits); ++digits) { *--p = L'0'; } for (digits = 0; digits < frac_digits && digits < dec.sig.length; ++digits) { *--p = *--q; } for (; digits < frac_digits; ++digits) { *--p = L'0'; } if (format.precision || format.alternate_form) { *--p = radix_marker; } if (int_digits) { for (digits = 0; digits < int_digits - dec.sig.length; ++digits) { *--p = L'0'; } for (; digits < int_digits; ++digits) { *--p = *--q; } } else { *--p = L'0'; } if (dec.sgn) { *--p = L'-'; } else if (format.sign_options == sign_always) { *--p = L'+'; } else if (format.sign_options == space_holder) { *--p = L' '; } break; } pw = wbuff - strlen(p) - 1; mbstowcs(pw, p, strlen(p)); return pw; } // non-matching: https://decomp.me/scratch/bV2T9 int __wpformatter(void *(*WriteProc)(void *, const wchar_t *, size_t), void *WriteProcArg, const wchar_t *format_str, va_list arg, bool is_secure) { int num_chars, chars_written, field_width; const wchar_t *format_ptr; const wchar_t *curr_format; print_format format; long long_num; long long long_long_num; long double long_double_num; wchar_t buff[512]; wchar_t *buff_ptr; wchar_t *string_end; char *cstring_end; wchar_t fill_char = ' '; char *strptr; format_ptr = format_str; chars_written = 0; while (*format_ptr) { if (!(curr_format = wcschr(format_ptr, L'%'))) { num_chars = wcslen(format_ptr); chars_written += num_chars; if (num_chars && !(*WriteProc)(WriteProcArg, format_ptr, num_chars)) { return -1; } break; } num_chars = curr_format - format_ptr; chars_written += num_chars; if (num_chars && !(*WriteProc)(WriteProcArg, format_ptr, num_chars)) { return -1; } format_ptr = curr_format; format_ptr = parse_format(format_ptr, &arg, &format); switch (format.conversion_char) { case L'd': case L'i': if (format.argument_options == long_argument) { long_num = va_arg(arg, long); } else if (format.argument_options == long_long_argument) { long_long_num = va_arg(arg, long long); } else if (format.argument_options == intmax_argument) { long_long_num = va_arg(arg, intmax_t); } else if (format.argument_options == size_t_argument) { long_num = va_arg(arg, size_t); } else if (format.argument_options == ptrdiff_argument) { long_num = va_arg(arg, ptrdiff_t); } else { long_num = va_arg(arg, int); } if (format.argument_options == short_argument) { long_num = (short) long_num; } if ((format.argument_options == long_long_argument) || (format.argument_options == intmax_argument)) { if (!(buff_ptr = longlong2str(long_long_num, buff + 512, format))) { goto conversion_error; } } else { if (!(buff_ptr = long2str(long_num, buff + 512, format))) { goto conversion_error; } } num_chars = buff + 512 - 1 - buff_ptr; break; case L'o': case L'u': case L'x': case L'X': if (format.argument_options == long_argument) { long_num = va_arg(arg, unsigned long); } else if (format.argument_options == long_long_argument) { long_long_num = va_arg(arg, long long); } else if (format.argument_options == intmax_argument) { long_long_num = va_arg(arg, intmax_t); } else if (format.argument_options == size_t_argument) { long_num = va_arg(arg, size_t); } else if (format.argument_options == ptrdiff_argument) { long_num = va_arg(arg, ptrdiff_t); } else { long_num = va_arg(arg, unsigned int); } if (format.argument_options == short_argument) { long_num = (unsigned short) long_num; } if ((format.argument_options == long_long_argument) || (format.argument_options == intmax_argument)) { if (!(buff_ptr = longlong2str(long_long_num, buff + 512, format))) { goto conversion_error; } } else { if (!(buff_ptr = long2str(long_num, buff + 512, format))) { goto conversion_error; } } num_chars = buff + 512 - 1 - buff_ptr; break; case L'f': case L'F': case L'e': case L'E': case L'g': case L'G': if (format.argument_options == long_double_argument) { long_double_num = va_arg(arg, long double); } else { long_double_num = va_arg(arg, double); } if (!(buff_ptr = float2str(long_double_num, buff + 512, format))) { goto conversion_error; } num_chars = buff + 512 - 1 - buff_ptr; break; case L'a': case L'A': if (format.argument_options == long_double_argument) { long_double_num = va_arg(arg, long double); } else { long_double_num = va_arg(arg, double); } if (!(buff_ptr = double2hex(long_double_num, buff + 512, format))) { goto conversion_error; } num_chars = buff + 512 - 1 - buff_ptr; break; case L's': if (format.argument_options == wchar_argument) { buff_ptr = va_arg(arg, wchar_t *); if (is_secure && buff_ptr == NULL) { __msl_runtime_constraint_violation_s(NULL, NULL, -1); return -1; } if (buff_ptr == NULL) { buff_ptr = L""; } if (format.alternate_form) { num_chars = (unsigned char) *buff_ptr++; if (format.precision_specified && num_chars > format.precision) { num_chars = format.precision; } } else if (format.precision_specified) { num_chars = format.precision; if ((string_end = (wchar_t *) wmemchr(buff_ptr, 0, num_chars)) != 0) { num_chars = string_end - buff_ptr; } } else { num_chars = wcslen(buff_ptr); } } else { strptr = va_arg(arg, char *); if (is_secure && strptr == NULL) { __msl_runtime_constraint_violation_s(0, 0, -1); return -1; } if (strptr == NULL) { strptr = ""; } if (format.alternate_form) { num_chars = (unsigned char) *buff_ptr++; if (format.precision_specified && num_chars > format.precision) { num_chars = format.precision; } } else if (format.precision_specified) { num_chars = format.precision; if ((cstring_end = (char *) memchr(strptr, 0, num_chars)) != 0) { num_chars = cstring_end - strptr; } } else { num_chars = strlen(strptr); } if ((num_chars = mbstowcs(buff, strptr, num_chars)) < 0) { goto conversion_error; } buff_ptr = &buff[0]; } break; case L'n': if (is_secure) { __msl_runtime_constraint_violation_s(0, 0, -1); return -1; } buff_ptr = va_arg(arg, wchar_t *); switch (format.argument_options) { case normal_argument: *(int *) buff_ptr = chars_written; break; case short_argument: *(short *) buff_ptr = chars_written; break; case long_argument: *(long *) buff_ptr = chars_written; break; case intmax_argument: *(intmax_t *) buff_ptr = chars_written; break; case size_t_argument: *(size_t *) buff_ptr = chars_written; break; case ptrdiff_argument: *(ptrdiff_t *) buff_ptr = chars_written; break; case long_long_argument: *(long long *) buff_ptr = chars_written; break; } continue; case L'c': buff_ptr = buff; if (format.argument_options == wchar_argument) { *buff_ptr = va_arg(arg, int); num_chars = 1; } else { char chint = va_arg(arg, int); num_chars = mbtowc(buff, &chint, 1); } break; case L'%': buff_ptr = buff; *buff_ptr = L'%'; num_chars = 1; break; case L'p': case 0xFFFF: default: conversion_error: num_chars = wcslen(curr_format); chars_written += num_chars; if (num_chars && !(*WriteProc)(WriteProcArg, curr_format, num_chars)) { return -1; } return chars_written; } field_width = num_chars; if (format.justification_options != left_justification) { fill_char = (format.justification_options == zero_fill) ? '0' : ' '; if (((*buff_ptr == L'+') || (*buff_ptr == L'-') || (*buff_ptr == L' ')) && (fill_char == '0')) { if ((*WriteProc)(WriteProcArg, buff_ptr, 1) == 0) { return -1; } ++buff_ptr; num_chars--; } if ((format.justification_options == zero_fill) && ((format.conversion_char == L'a') || (format.conversion_char == L'A'))) { if (num_chars < 2) { return -1; } if ((*WriteProc)(WriteProcArg, buff_ptr, 2) == 0) { return -1; } num_chars -= 2; buff_ptr += 2; } while (field_width < format.field_width) { if ((*WriteProc)(WriteProcArg, &fill_char, 1) == 0) { return -1; } ++field_width; } } if (num_chars && !(*WriteProc)(WriteProcArg, buff_ptr, num_chars)) { return -1; } if (format.justification_options == left_justification) { while (field_width < format.field_width) { wchar_t blank = L' '; if ((*WriteProc)(WriteProcArg, &blank, 1) == 0) { return -1; } ++field_width; } } chars_written += field_width; } return chars_written; } typedef struct { wchar_t *wCharStr; size_t MaxCharCount; size_t CharsWritten; } __wOutStrCtrl; void *__wStringWrite(void *wosc, const wchar_t *buffer, size_t numchars) { size_t tobewritten; void *res; __wOutStrCtrl *wOscp = (__wOutStrCtrl *) wosc; tobewritten = ((wOscp->CharsWritten + numchars) <= wOscp->MaxCharCount) ? numchars : wOscp->MaxCharCount - wOscp->CharsWritten; res = (void *) wmemcpy(wOscp->wCharStr + wOscp->CharsWritten, buffer, tobewritten); wOscp->CharsWritten += tobewritten; return res; } int swprintf(wchar_t *s, size_t n, const wchar_t *format, ...) { va_list args; va_start(args, format); return vswprintf(s, n, format, args); } int vswprintf(wchar_t *s, size_t n, const wchar_t *format, va_list arg) { int count; __wOutStrCtrl wosc; wosc.wCharStr = s; wosc.MaxCharCount = n; wosc.CharsWritten = 0; count = __wpformatter(&__wStringWrite, &wosc, format, arg, 0); if (count >= 0) { if (count < n) { s[count] = 0; } else { *(s + n - 1) = 0; count = -1; } } return count; }