Files
Viper_VRTE/viperlib.vp
T

1375 lines
57 KiB
Plaintext

import t, c
import viperio
from stdarg import arg, va_arg
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
# 返回类型必须与 CRT `sprintf` 以及 includes/stdio.vp 的
# 语义上直接返回 vsnprintf 的写入长度(与 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 floating-point special values (IEEE 754)
# Return: 0=normal, 1=+inf, 2=-inf, 3=nan
def _check_special_float(fv: double) -> int:
fbits: uint64 = 0
*&fbits = *&fv
if ((fbits >> 52) & 0x7FF) != 0x7FF: return 0
is_neg: int = 1 if (fbits >> 63) != 0 else 0
if (fbits & 0x000FFFFFFFFFFFFF) == 0:
if is_neg: return 2
return 1
return 3
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: t.CArray[char, 68]
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 c.Deref(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 c.Deref(s) != 0 and write_count < size - 1:
ptr[0] = c.Deref(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 或 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
while work >= scale * 10.0:
scale *= 10.0
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
p: int = 0
while p < precision:
frac_val *= 10.0
p += 1
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 或 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:
while fv >= 10.0:
fv /= 10.0
exp10 += 1
while fv < 1.0:
fv *= 10.0
exp10 -= 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
p = 0
while p < precision:
carry *= 10
p += 1
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 或 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:
while fv >= 10.0:
fv /= 10.0
exp10 += 1
while fv < 1.0:
fv *= 10.0
exp10 -= 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
p = 0
while p < prec_e:
carry *= 10
p += 1
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
# 小数位逆序存入(个位放 g_len+prec_e-1),temp 直接为正序。
# 原交换反转循环在 TPV 编译产物中失效(小数位未反转,如 456->654),
# 改逆序存储,与 %f 的倒序输出一致,绕开三变量交换。
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
while work >= scale * 10.0:
scale *= 10.0
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
p = 0
while p < prec_f:
frac_val *= 10.0
p += 1
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 或 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
c.Load(c.Addr(fbits), c.Addr(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