import viperio from stdarg import arg, va_arg import t define TEMP_BUF_SIZE = 68 def get_digit_count(num: uint, base: int) -> int: count: int = 0 if num == 0: return 1 while num > 0: count += 1 num //= base return count # Return type must be int, matching the CRT `sprintf` and includes/stdio.vp; # return vsnprintf's write length directly (consistent with the CRT). export def sprintf(buf: str, rule: str, *args) -> int: if buf is None or rule is None: return 0 return vsnprintf(buf, 0x7FFFFFFF, rule, args) def vsprintf(buf: str, rule: str, *args) -> int: if buf is None or rule is None: return 0 return vsnprintf(buf, 0x7FFFFFFF, rule, args) export def snprintf(buf: str, size: sizet, fmt: str, *args) -> int: if fmt is None: return 0 if buf is None or size == 0: return vsnprintf(None, 0, fmt, args) ret: int = vsnprintf(buf, size, fmt, args) return ret # Check float special values (IEEE 754): 0=normal, 1=+inf, 2=-inf, 3=nan. # Do NOT read the bit pattern via `*&fbits = *&fv`: the assignment is silently dropped (fbits stays 0), so this function would always return 0 and inf would spin forever in the float formatting loops. Use pure float semantics instead (NaN: fv != fv; ±inf: fv - fv is NaN, finite gives 0.0). def _check_special_float(fv: double) -> int: if fv != fv: return 3 diff: double = fv - fv if diff != diff: if fv < 0.0: return 2 return 1 return 0 export def vsnprintf(buf: bytes, size: sizet, fmt: str, ap: str) -> int: if fmt is None: return 0 # Length detection mode: when buf is None, only calculate the formatted length, without actually writing # _step=0 makes ptr not advance, repeatedly writing the same dummy byte (harmless), write_count accumulates correctly count_mode: int = 0 _step: int = 1 _dummy: char = '\0' if buf is None or size == 0: count_mode = 1 _step = 0 buf = &_dummy size = 0x7FFFFFFF ptr: str = buf write_count: int = 0 temp: [68]char temp[0] = '\t' while *fmt != 0 and write_count < size - 1: if *fmt != 37: ptr[0] = *fmt write_count += 1 ptr += _step fmt += 1 else: fmt += 1 if *fmt == 0: break width: int = 0 pad_zero: int = 0 left_align: int = 0 show_sign: int = 0 space_sign: int = 0 alt_form: int = 0 precision: int = -1 is_long: int = 0 is_long_long: int = 0 is_size: int = 0 is_short: int = 0 is_char: int = 0 while True: if *fmt == 45: left_align = 1 fmt += 1 elif *fmt == 48: pad_zero = 1 fmt += 1 elif *fmt == 43: show_sign = 1 fmt += 1 elif *fmt == 32: space_sign = 1 fmt += 1 elif *fmt == 35: alt_form = 1 fmt += 1 else: break if show_sign: space_sign = 0 while *fmt >= 48 and *fmt <= 57: width = width * 10 + (*fmt - 48) fmt += 1 if *fmt == 46: fmt += 1 precision = 0 while *fmt >= 48 and *fmt <= 57: precision = precision * 10 + (*fmt - 48) fmt += 1 if left_align: pad_zero = 0 if *fmt == 108: is_long = 1 fmt += 1 if *fmt == 108: is_long_long = 1 is_long = 0 fmt += 1 elif *fmt == 104: is_short = 1 fmt += 1 if *fmt == 104: is_char = 1 is_short = 0 fmt += 1 elif *fmt == 122: is_size = 1 fmt += 1 elif *fmt == 106: is_long_long = 1 fmt += 1 elif *fmt == 116: is_long = 1 fmt += 1 if *fmt == 99: if write_count < size - 1: ptr_i: int = va_arg(ap) ptr[0] = char(ptr_i) write_count += 1 ptr += _step else: ptr_i: int = va_arg(ap) elif *fmt == 115: s: str = va_arg(ap, t.CPtr) if s is None: s = "(None)" slen: int = 0 sc: str = s while *sc != 0: slen += 1 sc += 1 if not left_align and width > slen: pad_count: int = width - slen while pad_count > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step pad_count -= 1 while *s != 0 and write_count < size - 1: ptr[0] = *s write_count += 1 ptr += _step s += 1 if left_align and width > slen: pad_count = width - slen while pad_count > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step pad_count -= 1 elif *fmt == 100 or *fmt == 105: if is_long_long or is_size or is_long: num_l: int64 = va_arg(ap, int64) else: num_l: int64 = int64(va_arg(ap, int)) if is_char: num_l = int64(char(num_l)) elif is_short: num_l = int64(short(num_l)) sign: int = 0 if num_l < 0: sign = 1 if num_l == (-9223372036854775807 - 1): u_num: uint64 = uint64(0x8000000000000000) else: u_num: uint64 = uint64(-num_l) else: u_num: uint64 = uint64(num_l) if show_sign: sign = 2 elif space_sign: sign = 3 i: int = 0 while True: if i >= TEMP_BUF_SIZE - 1: break temp[i] = char(u_num % 10 + 48) i += 1 u_num //= 10 if u_num <= 0: break if sign == 1 and i < TEMP_BUF_SIZE - 1: temp[i] = 45 i += 1 elif sign == 2 and i < TEMP_BUF_SIZE - 1: temp[i] = 43 i += 1 elif sign == 3 and i < TEMP_BUF_SIZE - 1: temp[i] = 32 i += 1 if not left_align and not pad_zero and width > i: pad_count = width - i while pad_count > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step pad_count -= 1 if pad_zero and width > i: pad_count = width - i while pad_count > 0 and write_count < size - 1: ptr[0] = 48 write_count += 1 ptr += _step pad_count -= 1 while i > 0 and write_count < size - 1: i -= 1 ptr[0] = temp[i] write_count += 1 ptr += _step if left_align and width > i: pad_count = width - i while pad_count > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step pad_count -= 1 elif *fmt == 117: if is_long or is_long_long or is_size: u_num_l: uint64 = va_arg(ap, uint64) else: u_num_l: uint64 = uint64(uint(va_arg(ap))) i = 0 while True: if i >= TEMP_BUF_SIZE - 1: break temp[i] = char(u_num_l % 10 + 48) i += 1 u_num_l //= 10 if u_num_l <= 0: break if not left_align and not pad_zero and width > i: pad_count = width - i while pad_count > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step pad_count -= 1 if pad_zero and width > i: pad_count = width - i while pad_count > 0 and write_count < size - 1: ptr[0] = 48 write_count += 1 ptr += _step pad_count -= 1 while i > 0 and write_count < size - 1: i -= 1 ptr[0] = temp[i] write_count += 1 ptr += _step if left_align and width > i: pad_count = width - i while pad_count > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step pad_count -= 1 elif *fmt == 120: if is_long or is_long_long or is_size: u_num_l: uint64 = va_arg(ap, uint64) else: u_num_l: uint64 = uint64(uint(va_arg(ap))) is_nonzero: int = 0 if u_num_l != 0: is_nonzero = 1 i = 0 while True: if i >= TEMP_BUF_SIZE - 1: break digit: int = int(u_num_l % 16) if digit < 10: temp[i] = char(digit + 48) else: temp[i] = char(digit - 10 + 97) u_num_l //= 16 i += 1 if u_num_l <= 0: break digit_count: int = i prefix_len: int = 0 if alt_form and is_nonzero: prefix_len = 2 effective_len: int = digit_count + prefix_len if not left_align and not pad_zero and width > effective_len: pad_count = width - effective_len while pad_count > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step pad_count -= 1 if prefix_len > 0: if write_count < size - 1: ptr[0] = 48 write_count += 1 ptr += _step if write_count < size - 1: ptr[0] = 120 write_count += 1 ptr += _step if pad_zero and width > effective_len: pad_count = width - effective_len while pad_count > 0 and write_count < size - 1: ptr[0] = 48 write_count += 1 ptr += _step pad_count -= 1 while i > 0 and write_count < size - 1: i -= 1 ptr[0] = temp[i] write_count += 1 ptr += _step if left_align and width > effective_len: pad_count = width - effective_len while pad_count > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step pad_count -= 1 elif *fmt == 88: if is_long or is_long_long or is_size: u_num_l: uint64 = va_arg(ap) else: u_num_l: uint64 = uint64(uint(va_arg(ap))) is_nonzero = 0 if u_num_l != 0: is_nonzero = 1 i = 0 while True: if i >= TEMP_BUF_SIZE - 1: break digit = int(u_num_l % 16) if digit < 10: temp[i] = char(digit + 48) else: temp[i] = char(digit - 10 + 65) u_num_l //= 16 i += 1 if u_num_l <= 0: break digit_count = i prefix_len = 0 if alt_form and is_nonzero: prefix_len = 2 effective_len = digit_count + prefix_len if not left_align and not pad_zero and width > effective_len: pad_count = width - effective_len while pad_count > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step pad_count -= 1 if prefix_len > 0: if write_count < size - 1: ptr[0] = 48 write_count += 1 ptr += _step if write_count < size - 1: ptr[0] = 88 write_count += 1 ptr += _step if pad_zero and width > effective_len: pad_count = width - effective_len while pad_count > 0 and write_count < size - 1: ptr[0] = 48 write_count += 1 ptr += _step pad_count -= 1 while i > 0 and write_count < size - 1: i -= 1 ptr[0] = temp[i] write_count += 1 ptr += _step if left_align and width > effective_len: pad_count = width - effective_len while pad_count > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step pad_count -= 1 elif *fmt == 111: if is_long or is_long_long or is_size: u_num_l: uint64 = va_arg(ap, uint64) else: u_num_l: uint64 = uint64(uint(va_arg(ap))) if is_char: u_num_l = uint64(char(u_num_l)) elif is_short: u_num_l = uint64(short(u_num_l)) i = 0 if u_num_l == 0 and not alt_form: temp[0] = 48 i = 1 else: while True: if i >= TEMP_BUF_SIZE - 1: break temp[i] = char(u_num_l % 8 + 48) i += 1 u_num_l //= 8 if u_num_l <= 0: break if alt_form and i < TEMP_BUF_SIZE - 1: temp[i] = 48 i += 1 if not left_align and not pad_zero and width > i: pad_count = width - i while pad_count > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step pad_count -= 1 if pad_zero and width > i: pad_count = width - i while pad_count > 0 and write_count < size - 1: ptr[0] = 48 write_count += 1 ptr += _step pad_count -= 1 while i > 0 and write_count < size - 1: i -= 1 ptr[0] = temp[i] write_count += 1 ptr += _step if left_align and width > i: pad_count = width - i while pad_count > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step pad_count -= 1 elif *fmt == 98: if is_long or is_long_long or is_size: u_num_l: uint64 = va_arg(ap, uint64) else: u_num_l: uint64 = uint64(uint(va_arg(ap))) if is_char: u_num_l = uint64(char(u_num_l)) elif is_short: u_num_l = uint64(short(u_num_l)) i = 0 if u_num_l == 0: temp[0] = 48 i = 1 else: while True: if i >= TEMP_BUF_SIZE - 1: break temp[i] = char(u_num_l % 2 + 48) i += 1 u_num_l //= 2 if u_num_l <= 0: break if alt_form and i < TEMP_BUF_SIZE - 1: temp[i] = 98 i += 1 if not left_align and not pad_zero and width > i: pad_count = width - i while pad_count > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step pad_count -= 1 if pad_zero and width > i: pad_count = width - i while pad_count > 0 and write_count < size - 1: ptr[0] = 48 write_count += 1 ptr += _step pad_count -= 1 while i > 0 and write_count < size - 1: i -= 1 ptr[0] = temp[i] write_count += 1 ptr += _step if left_align and width > i: pad_count = width - i while pad_count > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step pad_count -= 1 elif *fmt == 112: ptr_val: uint64 = uint64(va_arg(ap, t.CPtr)) if ptr_val == 0: temp[0] = 40 temp[1] = 110 temp[2] = 105 temp[3] = 108 temp[4] = 41 i = 5 else: u_num_l = ptr_val i = 0 while True: if i >= TEMP_BUF_SIZE - 1: break digit = int(u_num_l % 16) if digit < 10: temp[i] = char(digit + 48) else: temp[i] = char(digit - 10 + 97) u_num_l //= 16 i += 1 if u_num_l <= 0: break if i < TEMP_BUF_SIZE - 1: temp[i] = 120 i += 1 if i < TEMP_BUF_SIZE - 1: temp[i] = 48 i += 1 if not left_align and not pad_zero and width > i: pad_count = width - i while pad_count > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step pad_count -= 1 if pad_zero and width > i: pad_count = width - i while pad_count > 0 and write_count < size - 1: ptr[0] = 48 write_count += 1 ptr += _step pad_count -= 1 while i > 0 and write_count < size - 1: i -= 1 ptr[0] = temp[i] write_count += 1 ptr += _step if left_align and width > i: pad_count = width - i while pad_count > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step pad_count -= 1 elif *fmt == 102 or *fmt == 70: f_upper: int = 1 if *fmt == 70 else 0 if precision < 0: precision = 6 fv: double = va_arg(ap, double) f_sp: int = _check_special_float(fv) if f_sp != 0: f_sgn_len: int = 0 if f_sp == 2: f_sgn_len = 1 elif f_sp == 1 and show_sign: f_sgn_len = 1 elif f_sp == 1 and space_sign: f_sgn_len = 1 f_total_len: int = f_sgn_len + 3 if not left_align and width > f_total_len: f_pad: int = width - f_total_len while f_pad > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step f_pad -= 1 if f_sp == 2: if write_count < size - 1: ptr[0] = 45 write_count += 1 ptr += _step elif f_sp == 1 and show_sign: if write_count < size - 1: ptr[0] = 43 write_count += 1 ptr += _step elif f_sp == 1 and space_sign: if write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step fi_c: int = 0 while fi_c < 3 and write_count < size - 1: fc: int = 0 if f_sp == 3: # nan if fi_c == 0: fc = 110 elif fi_c == 1: fc = 97 else: fc = 110 else: # inf (f_sp==1 +inf or f_sp==2 -inf) if fi_c == 0: fc = 105 elif fi_c == 1: fc = 110 else: fc = 102 if f_upper and fc >= 97 and fc <= 122: fc -= 32 ptr[0] = char(fc) write_count += 1 ptr += _step fi_c += 1 if left_align and width > f_total_len: f_pad = width - f_total_len while f_pad > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step f_pad -= 1 fmt += 1 continue if fv < 0.0: if write_count < size - 1: ptr[0] = 45 write_count += 1 ptr += _step fv = 0.0 - fv elif show_sign: if write_count < size - 1: ptr[0] = 43 write_count += 1 ptr += _step elif space_sign: if write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step di: int = 0 work: double = fv if work < 1.0: temp[0] = 48 di = 1 else: scale: double = 1.0 # Upper-bound guard: inf makes `work >= scale*10.0` always true; finite values need at most 308 iterations scale_guard: int = 0 while work >= scale * 10.0 and scale_guard < 400: scale *= 10.0 scale_guard += 1 while scale >= 1.0 and di < TEMP_BUF_SIZE - 1: d: int = int(work / scale) if d > 9: d = 9 temp[di] = char(d + 48) di += 1 work = work - double(d) * scale scale /= 10.0 frac_val: double = work for p in range(precision): frac_val *= 10.0 frac_part: uint64 = uint64(frac_val + 0.5) f_total: int = di + (precision + 1 if precision > 0 else 0) if not left_align and not pad_zero and width > f_total: pad_count = width - f_total while pad_count > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step pad_count -= 1 if pad_zero and width > f_total: pad_count = width - f_total while pad_count > 0 and write_count < size - 1: ptr[0] = 48 write_count += 1 ptr += _step pad_count -= 1 while di > 0 and write_count < size - 1: di -= 1 ptr[0] = temp[di] write_count += 1 ptr += _step if precision > 0: if write_count < size - 1: ptr[0] = 46 write_count += 1 ptr += _step fi: int = 0 while fi < precision and fi < TEMP_BUF_SIZE - 1: temp[fi] = char(frac_part % 10 + 48) fi += 1 frac_part //= 10 while fi < precision and fi < TEMP_BUF_SIZE - 1: temp[fi] = 48 fi += 1 while fi > 0 and write_count < size - 1: fi -= 1 ptr[0] = temp[fi] write_count += 1 ptr += _step elif alt_form: if write_count < size - 1: ptr[0] = 46 write_count += 1 ptr += _step if left_align and width > f_total: pad_count = width - f_total while pad_count > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step pad_count -= 1 elif *fmt == 101 or *fmt == 69: if precision < 0: precision = 6 fv: double = va_arg(ap, double) e_upper: int = 1 if *fmt == 69 else 0 e_sp: int = _check_special_float(fv) if e_sp != 0: e_sgn_len: int = 0 if e_sp == 2: e_sgn_len = 1 elif e_sp == 1 and show_sign: e_sgn_len = 1 elif e_sp == 1 and space_sign: e_sgn_len = 1 e_total_len: int = e_sgn_len + 3 if not left_align and width > e_total_len: e_pad: int = width - e_total_len while e_pad > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step e_pad -= 1 if e_sp == 2: if write_count < size - 1: ptr[0] = 45 write_count += 1 ptr += _step elif e_sp == 1 and show_sign: if write_count < size - 1: ptr[0] = 43 write_count += 1 ptr += _step elif e_sp == 1 and space_sign: if write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step ei_c: int = 0 while ei_c < 3 and write_count < size - 1: ec: int = 0 if e_sp == 3: # nan if ei_c == 0: ec = 110 elif ei_c == 1: ec = 97 else: ec = 110 else: # inf (e_sp==1 +inf or e_sp==2 -inf) if ei_c == 0: ec = 105 elif ei_c == 1: ec = 110 else: ec = 102 if e_upper and ec >= 97 and ec <= 122: ec -= 32 ptr[0] = char(ec) write_count += 1 ptr += _step ei_c += 1 if left_align and width > e_total_len: e_pad = width - e_total_len while e_pad > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step e_pad -= 1 fmt += 1 continue if fv < 0.0: if write_count < size - 1: ptr[0] = 45 write_count += 1 ptr += _step fv = 0.0 - fv elif show_sign: if write_count < size - 1: ptr[0] = 43 write_count += 1 ptr += _step elif space_sign: if write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step exp10: int = 0 if fv != 0.0: # Upper-bound guard: inf makes the two loops below always true (inf/10==inf, inf*10==inf) exp_guard: int = 0 while fv >= 10.0 and exp_guard < 400: fv /= 10.0 exp10 += 1 exp_guard += 1 exp_guard = 0 while fv < 1.0 and exp_guard < 400: fv *= 10.0 exp10 -= 1 exp_guard += 1 int_digit: int = int(fv) if int_digit > 9: int_digit = 9 if int_digit < 0: int_digit = 0 frac_v: double = fv - double(int_digit) p: int = 0 while p < precision: frac_v *= 10.0 p += 1 frac_p: uint64 = uint64(frac_v + 0.5) carry: uint64 = 1 for p in range(precision): carry *= 10 if frac_p >= carry and carry > 0: frac_p = 0 int_digit += 1 if int_digit > 9: int_digit = 1 exp10 += 1 e_total: int = 1 + (precision + 1 if precision > 0 else 0) + 4 if not left_align and not pad_zero and width > e_total: pad_count = width - e_total while pad_count > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step pad_count -= 1 if pad_zero and width > e_total: pad_count = width - e_total while pad_count > 0 and write_count < size - 1: ptr[0] = 48 write_count += 1 ptr += _step pad_count -= 1 if write_count < size - 1: ptr[0] = char(int_digit + 48) write_count += 1 ptr += _step if precision > 0: if write_count < size - 1: ptr[0] = 46 write_count += 1 ptr += _step fi: int = 0 while fi < precision and fi < TEMP_BUF_SIZE - 1: temp[fi] = char(frac_p % 10 + 48) fi += 1 frac_p //= 10 while fi < precision and fi < TEMP_BUF_SIZE - 1: temp[fi] = 48 fi += 1 while fi > 0 and write_count < size - 1: fi -= 1 ptr[0] = temp[fi] write_count += 1 ptr += _step elif alt_form: if write_count < size - 1: ptr[0] = 46 write_count += 1 ptr += _step if write_count < size - 1: ptr[0] = 101 if e_upper == 0 else 69 write_count += 1 ptr += _step if write_count < size - 1: ptr[0] = 45 if exp10 < 0 else 43 write_count += 1 ptr += _step exp_abs: uint64 = uint64(exp10) if exp10 >= 0 else uint64(0 - exp10) ei: int = 0 if exp_abs == 0: temp[0] = 48 temp[1] = 48 ei = 2 else: while exp_abs > 0 and ei < TEMP_BUF_SIZE - 1: temp[ei] = char(exp_abs % 10 + 48) ei += 1 exp_abs //= 10 while ei < 2: temp[ei] = 48 ei += 1 while ei > 0 and write_count < size - 1: ei -= 1 ptr[0] = temp[ei] write_count += 1 ptr += _step if left_align and width > e_total: pad_count = width - e_total while pad_count > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step pad_count -= 1 elif *fmt == 103 or *fmt == 71: if precision < 0: precision = 6 if precision == 0: precision = 1 fv: double = va_arg(ap, double) g_upper: int = 1 if *fmt == 71 else 0 g_sp: int = _check_special_float(fv) if g_sp != 0: g_sgn_len: int = 0 if g_sp == 2: g_sgn_len = 1 elif g_sp == 1 and show_sign: g_sgn_len = 1 elif g_sp == 1 and space_sign: g_sgn_len = 1 g_total_len: int = g_sgn_len + 3 if not left_align and width > g_total_len: g_pad: int = width - g_total_len while g_pad > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step g_pad -= 1 if g_sp == 2: if write_count < size - 1: ptr[0] = 45 write_count += 1 ptr += _step elif g_sp == 1 and show_sign: if write_count < size - 1: ptr[0] = 43 write_count += 1 ptr += _step elif g_sp == 1 and space_sign: if write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step gi_c: int = 0 while gi_c < 3 and write_count < size - 1: gc: int = 0 if g_sp == 3: # nan if gi_c == 0: gc = 110 elif gi_c == 1: gc = 97 else: gc = 110 else: # inf (g_sp==1 +inf or g_sp==2 -inf) if gi_c == 0: gc = 105 elif gi_c == 1: gc = 110 else: gc = 102 if g_upper and gc >= 97 and gc <= 122: gc -= 32 ptr[0] = char(gc) write_count += 1 ptr += _step gi_c += 1 if left_align and width > g_total_len: g_pad = width - g_total_len while g_pad > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step g_pad -= 1 fmt += 1 continue if fv < 0.0: if write_count < size - 1: ptr[0] = 45 write_count += 1 ptr += _step fv = 0.0 - fv elif show_sign: if write_count < size - 1: ptr[0] = 43 write_count += 1 ptr += _step elif space_sign: if write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step fv_orig: double = fv exp10: int = 0 if fv != 0.0: # Upper-bound guard: this loop is where it hangs (inf makes fv>=10.0 always true, inf/10==inf) exp_guard: int = 0 while fv >= 10.0 and exp_guard < 400: fv /= 10.0 exp10 += 1 exp_guard += 1 exp_guard = 0 while fv < 1.0 and exp_guard < 400: fv *= 10.0 exp10 -= 1 exp_guard += 1 g_use_e: int = 0 if exp10 < -4 or exp10 >= precision: g_use_e = 1 g_len: int = 0 if g_use_e: int_digit: int = int(fv) if int_digit > 9: int_digit = 9 if int_digit < 0: int_digit = 0 frac_v: double = fv - double(int_digit) prec_e: int = precision - 1 p: int = 0 while p < prec_e: frac_v *= 10.0 p += 1 frac_p: uint64 = uint64(frac_v + 0.5) carry: uint64 = 1 for p in range(prec_e): carry *= 10 if frac_p >= carry and carry > 0: frac_p = 0 int_digit += 1 if int_digit > 9: int_digit = 1 exp10 += 1 temp[0] = char(int_digit + 48) g_len = 1 if prec_e > 0: temp[1] = 46 g_len = 2 # Store fraction digits in reverse order (ones place at g_len+prec_e-1) so temp is already forward-ordered. # The original swap-reverse loop fails in TPV output (digits not reversed, e.g. 456->654); reverse storage matches %f's output and avoids the three-variable swap. fi: int = 0 fp_inv: uint64 = frac_p fp_idx: int = g_len + prec_e - 1 while fi < prec_e and fp_idx < TEMP_BUF_SIZE - 1: temp[fp_idx] = char(fp_inv % 10 + 48) fp_idx -= 1 fp_inv //= 10 fi += 1 g_len += prec_e else: prec_f: int = precision - 1 - exp10 if prec_f < 0: prec_f = 0 work: double = fv_orig if work < 1.0: temp[0] = 48 g_len = 1 else: scale: double = 1.0 # Upper-bound guard: inf makes `work >= scale*10.0` always true; finite values need at most 308 iterations scale_guard: int = 0 while work >= scale * 10.0 and scale_guard < 400: scale *= 10.0 scale_guard += 1 while scale >= 1.0 and g_len < TEMP_BUF_SIZE - 1: d: int = int(work / scale) if d > 9: d = 9 temp[g_len] = char(d + 48) g_len += 1 work = work - double(d) * scale scale /= 10.0 if prec_f > 0 and g_len < TEMP_BUF_SIZE - 1: temp[g_len] = 46 g_len += 1 frac_val: double = work for p in range(prec_f): frac_val *= 10.0 frac_part: uint64 = uint64(frac_val + 0.5) # Store decimal digits in reverse order (ones place goes to g_len prec_f-1), temp is directly in forward order. # The original swap-reverse loop doesn't work in TPV compiled output (decimal digits aren't reversed, e.g., 456->654), # Change to reverse storage, consistent with %f's reverse output, avoiding three-variable swapping. fi = 0 fp_inv: uint64 = frac_part fp_idx: int = g_len + prec_f - 1 while fi < prec_f and fp_idx < TEMP_BUF_SIZE - 1: temp[fp_idx] = char(fp_inv % 10 + 48) fp_idx -= 1 fp_inv //= 10 fi += 1 g_len += prec_f if not alt_form and g_len > 0: while g_len > 0: if temp[g_len - 1] == 48: g_len -= 1 else: break if g_len > 0 and temp[g_len - 1] == 46: g_len -= 1 g_total: int = g_len if g_use_e: g_total = g_len + 4 if not left_align and not pad_zero and width > g_total: pad_count = width - g_total while pad_count > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step pad_count -= 1 if pad_zero and width > g_total: pad_count = width - g_total while pad_count > 0 and write_count < size - 1: ptr[0] = 48 write_count += 1 ptr += _step pad_count -= 1 gi: int = 0 while gi < g_len and write_count < size - 1: ptr[0] = temp[gi] write_count += 1 ptr += _step gi += 1 if g_use_e: if write_count < size - 1: ptr[0] = 101 if g_upper == 0 else 69 write_count += 1 ptr += _step if write_count < size - 1: ptr[0] = 45 if exp10 < 0 else 43 write_count += 1 ptr += _step exp_abs: uint64 = uint64(exp10) if exp10 >= 0 else uint64(0 - exp10) ei: int = 0 if exp_abs == 0: temp[0] = 48 temp[1] = 48 ei = 2 else: while exp_abs > 0 and ei < TEMP_BUF_SIZE - 1: temp[ei] = char(exp_abs % 10 + 48) ei += 1 exp_abs //= 10 while ei < 2: temp[ei] = 48 ei += 1 while ei > 0 and write_count < size - 1: ei -= 1 ptr[0] = temp[ei] write_count += 1 ptr += _step if left_align and width > g_total: pad_count = width - g_total while pad_count > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step pad_count -= 1 elif *fmt == 97 or *fmt == 65: a_upper: int = 1 if *fmt == 65 else 0 fv: double = va_arg(ap, double) a_sp: int = _check_special_float(fv) if a_sp != 0: a_sgn_len: int = 0 if a_sp == 2: a_sgn_len = 1 elif a_sp == 1 and show_sign: a_sgn_len = 1 elif a_sp == 1 and space_sign: a_sgn_len = 1 a_total_len: int = a_sgn_len + 3 if not left_align and width > a_total_len: a_pad: int = width - a_total_len while a_pad > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step a_pad -= 1 if a_sp == 2: if write_count < size - 1: ptr[0] = 45 write_count += 1 ptr += _step elif a_sp == 1 and show_sign: if write_count < size - 1: ptr[0] = 43 write_count += 1 ptr += _step elif a_sp == 1 and space_sign: if write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step ai_c: int = 0 while ai_c < 3 and write_count < size - 1: ac: int = 0 if a_sp == 3: # nan if ai_c == 0: ac = 110 elif ai_c == 1: ac = 97 else: ac = 110 else: # inf (a_sp==1 +inf or a_sp==2 -inf) if ai_c == 0: ac = 105 elif ai_c == 1: ac = 110 else: ac = 102 if a_upper and ac >= 97 and ac <= 122: ac -= 32 ptr[0] = char(ac) write_count += 1 ptr += _step ai_c += 1 if left_align and width > a_total_len: a_pad = width - a_total_len while a_pad > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step a_pad -= 1 fmt += 1 continue fbits: uint64 = 0 *&fbits = *&fv a_neg: int = 1 if (fbits >> 63) != 0 else 0 a_exp: int = int((fbits >> 52) & 0x7FF) a_frac: uint64 = fbits & 0x000FFFFFFFFFFFFF a_leading: int = 0 a_binexp: int = 0 if a_exp == 0: a_leading = 0 if a_frac == 0: a_binexp = 0 else: a_binexp = -1022 else: a_leading = 1 a_binexp = a_exp - 1023 a_prec: int = precision if a_prec < 0: a_prec = 13 if a_prec > 50: a_prec = 50 a_hi: int = 0 while a_hi < 13 and a_hi < a_prec: a_digit: int = int((a_frac >> (48 - 4 * a_hi)) & 0xF) if a_digit < 10: temp[a_hi] = char(a_digit + 48) else: if a_upper: temp[a_hi] = char(a_digit - 10 + 65) else: temp[a_hi] = char(a_digit - 10 + 97) a_hi += 1 while a_hi < a_prec: temp[a_hi] = 48 a_hi += 1 a_hd_count: int = a_prec if precision < 0: while a_hd_count > 0 and temp[a_hd_count - 1] == 48: a_hd_count -= 1 a_has_dot: int = 0 if a_hd_count > 0: a_has_dot = 1 elif alt_form: a_has_dot = 1 a_eb: int = a_binexp a_esign: int = 0 if a_binexp < 0: a_esign = 1 a_eb = -a_binexp a_ei: int = 0 if a_eb == 0: temp[60] = 48 a_ei = 1 else: while a_eb > 0 and a_ei < 7: temp[60 + a_ei] = char(a_eb % 10 + 48) a_ei += 1 a_eb //= 10 a_ecount: int = a_ei a_sign_len: int = 0 if a_neg: a_sign_len = 1 elif show_sign: a_sign_len = 1 elif space_sign: a_sign_len = 1 a_content_len: int = a_sign_len + 2 + 1 + a_has_dot + a_hd_count + 1 + 1 + a_ecount if not left_align and not pad_zero and width > a_content_len: a_pad = width - a_content_len while a_pad > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step a_pad -= 1 if a_neg: if write_count < size - 1: ptr[0] = 45 write_count += 1 ptr += _step elif show_sign: if write_count < size - 1: ptr[0] = 43 write_count += 1 ptr += _step elif space_sign: if write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step if pad_zero and width > a_content_len: a_pad = width - a_content_len while a_pad > 0 and write_count < size - 1: ptr[0] = 48 write_count += 1 ptr += _step a_pad -= 1 if write_count < size - 1: ptr[0] = 48 write_count += 1 ptr += _step if write_count < size - 1: if a_upper: ptr[0] = 88 else: ptr[0] = 120 write_count += 1 ptr += _step if write_count < size - 1: ptr[0] = char(a_leading + 48) write_count += 1 ptr += _step if a_has_dot: if write_count < size - 1: ptr[0] = 46 write_count += 1 ptr += _step a_hj: int = 0 while a_hj < a_hd_count and write_count < size - 1: ptr[0] = temp[a_hj] write_count += 1 ptr += _step a_hj += 1 if write_count < size - 1: if a_upper: ptr[0] = 80 else: ptr[0] = 112 write_count += 1 ptr += _step if write_count < size - 1: if a_esign: ptr[0] = 45 else: ptr[0] = 43 write_count += 1 ptr += _step a_ek: int = a_ecount while a_ek > 0 and write_count < size - 1: a_ek -= 1 ptr[0] = temp[60 + a_ek] write_count += 1 ptr += _step if left_align and width > a_content_len: a_pad = width - a_content_len while a_pad > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 ptr += _step a_pad -= 1 elif *fmt == 110: if is_long_long or is_long: np: int64* = va_arg(ap, int64*) if np != None: np[0] = int64(write_count) elif is_short: sp: short* = va_arg(ap, short*) if sp != None: sp[0] = short(write_count) elif is_char: cp: str = va_arg(ap, str) if cp != None: cp[0] = char(write_count) else: ip: int* = va_arg(ap, int*) if ip != None: ip[0] = write_count elif *fmt == 37: if write_count < size - 1: ptr[0] = 37 write_count += 1 ptr += _step else: if write_count < size - 1: ptr[0] = *fmt write_count += 1 ptr += _step fmt += 1 ptr[0] = 0 return write_count