diff --git a/engine/common/common.c b/engine/common/common.c index c5d7a7a84..bfb0e93de 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -328,6 +328,54 @@ int Q_strcasecmp (char *s1, char *s2) #endif +// Q_ftoa: convert IEEE 754 float to a base-10 string with "infinite" decimal places +void Q_ftoa(char *str, float in) +{ + unsigned int i = *((float *)&in); + + int signbit = (i & 0x80000000) >> 31; + int exp = (signed int)((i & 0x7F800000) >> 23) - 127; + int mantissa = (i & 0x007FFFFF); + + if (exp == 128) // 255(NaN/Infinity bits) - 127(bias) + { + if (signbit) + { + *str = '-'; + str++; + } + if (mantissa == 0) // infinity + strcpy(str, "1.#INF"); + else // NaN or indeterminate + strcpy(str, "1.#NAN"); + return; + } + + exp = -exp; + exp = (int)(exp * 0.30102999957f); // convert base 2 to base 10 + exp += 11; // + + if (exp <= 0) + sprintf(str, "%f", in); + else + { + char tstr[8]; + char *lsig = str - 1; // last significant character + sprintf(tstr, "%%.%if", exp); + sprintf(str, tstr, in); + // find last significant digit and trim + while (*str) + { + if (*str >= '1' && *str <= '9') + lsig = str; + else if (*str == '.') + lsig = str - 1; + str++; + } + lsig[1] = '\0'; + } +} + char *Q_strlwr(char *s) { char *ret=s; diff --git a/engine/common/common.h b/engine/common/common.h index dce209de1..6fc35f54f 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -169,6 +169,7 @@ void MSG_ReadData (void *data, int len); char *Q_strcpyline(char *out, char *in, int maxlen); //stops at '\n' (and '\r') +void Q_ftoa(char *str, float in); char *Q_strlwr(char *str); int wildcmp(char *wild, char *string); //1 if match diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index b1d054d49..cc9da8a50 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -3525,7 +3525,7 @@ void PF_ftos (progfuncs_t *prinst, struct globalvars_s *pr_globals) else if (pr_brokenfloatconvert.value) sprintf (pr_string_temp, "%5.1f",v); else - sprintf (pr_string_temp, "%f",v); + Q_ftoa (pr_string_temp, v); RETURN_TSTRING(pr_string_temp); }