From dac8a746a7f80b50834e750927335d8d1a00c1c1 Mon Sep 17 00:00:00 2001 From: thilo Date: Tue, 25 Mar 2008 21:36:09 +0000 Subject: - Replace vsprintf function in bg_lib.c with vsnprintf implementation started by Patrick Powell. - Remove all calls to vsprintf in the engine and gamecode and replace them with calls to vsnprintf. git-svn-id: svn://svn.icculus.org/quake3/trunk@1277 edf5b092-35ff-0310-97b2-ce42778d08ea --- code/botlib/be_aas_main.c | 2 +- code/botlib/l_precomp.c | 4 +- code/botlib/l_script.c | 4 +- code/cgame/cg_main.c | 8 +- code/game/ai_main.c | 2 +- code/game/bg_lib.c | 951 +++++++++++++++++++++++++++++++++++----------- code/game/bg_lib.h | 4 +- code/game/g_main.c | 10 +- code/game/g_team.c | 2 +- code/q3_ui/ui_atoms.c | 4 +- code/qcommon/common.c | 2 +- code/qcommon/q_shared.c | 15 +- code/qcommon/q_shared.h | 50 ++- code/qcommon/qcommon.h | 10 - code/server/sv_bot.c | 2 +- code/server/sv_rankings.c | 2 +- code/ui/ui_atoms.c | 4 +- code/ui/ui_shared.c | 4 +- 18 files changed, 792 insertions(+), 288 deletions(-) (limited to 'code') diff --git a/code/botlib/be_aas_main.c b/code/botlib/be_aas_main.c index 2963ecd..0296b1a 100644 --- a/code/botlib/be_aas_main.c +++ b/code/botlib/be_aas_main.c @@ -60,7 +60,7 @@ void QDECL AAS_Error(char *fmt, ...) va_list arglist; va_start(arglist, fmt); - vsprintf(str, fmt, arglist); + Q_vsnprintf(str, sizeof(str), fmt, arglist); va_end(arglist); botimport.Print(PRT_FATAL, "%s", str); } //end of the function AAS_Error diff --git a/code/botlib/l_precomp.c b/code/botlib/l_precomp.c index a84ca2c..06e7877 100644 --- a/code/botlib/l_precomp.c +++ b/code/botlib/l_precomp.c @@ -131,7 +131,7 @@ void QDECL SourceError(source_t *source, char *str, ...) va_list ap; va_start(ap, str); - vsprintf(text, str, ap); + Q_vsnprintf(text, sizeof(text), str, ap); va_end(ap); #ifdef BOTLIB botimport.Print(PRT_ERROR, "file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); @@ -155,7 +155,7 @@ void QDECL SourceWarning(source_t *source, char *str, ...) va_list ap; va_start(ap, str); - vsprintf(text, str, ap); + Q_vsnprintf(text, sizeof(text), str, ap); va_end(ap); #ifdef BOTLIB botimport.Print(PRT_WARNING, "file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); diff --git a/code/botlib/l_script.c b/code/botlib/l_script.c index 333e1ec..3e43fda 100644 --- a/code/botlib/l_script.c +++ b/code/botlib/l_script.c @@ -236,7 +236,7 @@ void QDECL ScriptError(script_t *script, char *str, ...) if (script->flags & SCFL_NOERRORS) return; va_start(ap, str); - vsprintf(text, str, ap); + Q_vsnprintf(text, sizeof(text), str, ap); va_end(ap); #ifdef BOTLIB botimport.Print(PRT_ERROR, "file %s, line %d: %s\n", script->filename, script->line, text); @@ -262,7 +262,7 @@ void QDECL ScriptWarning(script_t *script, char *str, ...) if (script->flags & SCFL_NOWARNINGS) return; va_start(ap, str); - vsprintf(text, str, ap); + Q_vsnprintf(text, sizeof(text), str, ap); va_end(ap); #ifdef BOTLIB botimport.Print(PRT_WARNING, "file %s, line %d: %s\n", script->filename, script->line, text); diff --git a/code/cgame/cg_main.c b/code/cgame/cg_main.c index 3740bca..15f4db5 100644 --- a/code/cgame/cg_main.c +++ b/code/cgame/cg_main.c @@ -419,7 +419,7 @@ void QDECL CG_Printf( const char *msg, ... ) { char text[1024]; va_start (argptr, msg); - vsprintf (text, msg, argptr); + Q_vsnprintf (text, sizeof(text), msg, argptr); va_end (argptr); trap_Print( text ); @@ -430,7 +430,7 @@ void QDECL CG_Error( const char *msg, ... ) { char text[1024]; va_start (argptr, msg); - vsprintf (text, msg, argptr); + Q_vsnprintf (text, sizeof(text), msg, argptr); va_end (argptr); trap_Error( text ); @@ -441,7 +441,7 @@ void QDECL Com_Error( int level, const char *error, ... ) { char text[1024]; va_start (argptr, error); - vsprintf (text, error, argptr); + Q_vsnprintf (text, sizeof(text), error, argptr); va_end (argptr); CG_Error( "%s", text); @@ -452,7 +452,7 @@ void QDECL Com_Printf( const char *msg, ... ) { char text[1024]; va_start (argptr, msg); - vsprintf (text, msg, argptr); + Q_vsnprintf (text, sizeof(text), msg, argptr); va_end (argptr); CG_Printf ("%s", text); diff --git a/code/game/ai_main.c b/code/game/ai_main.c index 0250dd9..fb37c28 100644 --- a/code/game/ai_main.c +++ b/code/game/ai_main.c @@ -99,7 +99,7 @@ void QDECL BotAI_Print(int type, char *fmt, ...) { va_list ap; va_start(ap, fmt); - vsprintf(str, fmt, ap); + Q_vsnprintf(str, sizeof(str), fmt, ap); va_end(ap); switch(type) { diff --git a/code/game/bg_lib.c b/code/game/bg_lib.c index 2b1af69..2027d6f 100644 --- a/code/game/bg_lib.c +++ b/code/game/bg_lib.c @@ -998,261 +998,762 @@ double fabs( double x ) { //========================================================= +/* + * New implementation by Patrick Powell and others for vsnprintf. + * Supports length checking in strings. +*/ -#define ALT 0x00000001 /* alternate form */ -#define HEXPREFIX 0x00000002 /* add 0x or 0X prefix */ -#define LADJUST 0x00000004 /* left adjustment */ -#define LONGDBL 0x00000008 /* long double */ -#define LONGINT 0x00000010 /* long integer */ -#define QUADINT 0x00000020 /* quad integer */ -#define SHORTINT 0x00000040 /* short integer */ -#define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */ -#define FPT 0x00000100 /* floating point number */ - -#define to_digit(c) ((c) - '0') -#define is_digit(c) ((unsigned)to_digit(c) <= 9) -#define to_char(n) ((n) + '0') - -void AddInt( char **buf_p, int val, int width, int flags ) { - char text[32]; - int digits; - int signedVal; - char *buf; - - digits = 0; - signedVal = val; - if ( val < 0 ) { - val = -val; - } - do { - text[digits++] = '0' + val % 10; - val /= 10; - } while ( val ); +/* + * Copyright Patrick Powell 1995 + * This code is based on code written by Patrick Powell (papowell@astart.com) + * It may be used for any purpose as long as this notice remains intact + * on all source code distributions + */ - if ( signedVal < 0 ) { - text[digits++] = '-'; - } +/************************************************************** + * Original: + * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 + * A bombproof version of doprnt (dopr) included. + * Sigh. This sort of thing is always nasty do deal with. Note that + * the version here does not include floating point... + * + * snprintf() is used instead of sprintf() as it does limit checks + * for string length. This covers a nasty loophole. + * + * The other functions are there to prevent NULL pointers from + * causing nast effects. + * + * More Recently: + * Brandon Long 9/15/96 for mutt 0.43 + * This was ugly. It is still ugly. I opted out of floating point + * numbers, but the formatter understands just about everything + * from the normal C string format, at least as far as I can tell from + * the Solaris 2.5 printf(3S) man page. + * + * Brandon Long 10/22/97 for mutt 0.87.1 + * Ok, added some minimal floating point support, which means this + * probably requires libm on most operating systems. Don't yet + * support the exponent (e,E) and sigfig (g,G). Also, fmtint() + * was pretty badly broken, it just wasn't being exercised in ways + * which showed it, so that's been fixed. Also, formated the code + * to mutt conventions, and removed dead code left over from the + * original. Also, there is now a builtin-test, just compile with: + * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm + * and run snprintf for results. + * + * Thomas Roessler 01/27/98 for mutt 0.89i + * The PGP code was using unsigned hexadecimal formats. + * Unfortunately, unsigned formats simply didn't work. + * + * Michael Elkins 03/05/98 for mutt 0.90.8 + * The original code assumed that both snprintf() and vsnprintf() were + * missing. Some systems only have snprintf() but not vsnprintf(), so + * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. + * + * Andrew Tridgell (tridge@samba.org) Oct 1998 + * fixed handling of %.0f + * added test for HAVE_LONG_DOUBLE + * + * Russ Allbery 2000-08-26 + * fixed return value to comply with C99 + * fixed handling of snprintf(NULL, ...) + * + * Hrvoje Niksic 2000-11-04 + * include instead of "config.h". + * moved TEST_SNPRINTF stuff out of HAVE_SNPRINTF ifdef. + * include for NULL. + * added support and test cases for long long. + * don't declare argument types to (v)snprintf if stdarg is not used. + * use int instead of short int as 2nd arg to va_arg. + * + **************************************************************/ - buf = *buf_p; +/* BDR 2002-01-13 %e and %g were being ignored. Now do something, + if not necessarily correctly */ - if( !( flags & LADJUST ) ) { - while ( digits < width ) { - *buf++ = ( flags & ZEROPAD ) ? '0' : ' '; - width--; - } - } +#if (SIZEOF_LONG_DOUBLE > 0) +/* #ifdef HAVE_LONG_DOUBLE */ +#define LDOUBLE long double +#else +#define LDOUBLE double +#endif - while ( digits-- ) { - *buf++ = text[digits]; - width--; - } +#if (SIZEOF_LONG_LONG > 0) +/* #ifdef HAVE_LONG_LONG */ +# define LLONG long long +#else +# define LLONG long +#endif - if( flags & LADJUST ) { - while ( width-- > 0) { - *buf++ = ( flags & ZEROPAD ) ? '0' : ' '; - } - } +static int dopr (char *buffer, size_t maxlen, const char *format, + va_list args); +static int fmtstr (char *buffer, size_t *currlen, size_t maxlen, + char *value, int flags, int min, int max); +static int fmtint (char *buffer, size_t *currlen, size_t maxlen, + LLONG value, int base, int min, int max, int flags); +static int fmtfp (char *buffer, size_t *currlen, size_t maxlen, + LDOUBLE fvalue, int min, int max, int flags); +static int dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c ); - *buf_p = buf; -} +/* + * dopr(): poor man's version of doprintf + */ -void AddFloat( char **buf_p, float fval, int width, int prec ) { - char text[32]; - int digits; - float signedVal; - char *buf; - int val; - - // get the sign - signedVal = fval; - if ( fval < 0 ) { - fval = -fval; +/* format read states */ +#define DP_S_DEFAULT 0 +#define DP_S_FLAGS 1 +#define DP_S_MIN 2 +#define DP_S_DOT 3 +#define DP_S_MAX 4 +#define DP_S_MOD 5 +#define DP_S_MOD_L 6 +#define DP_S_CONV 7 +#define DP_S_DONE 8 + +/* format flags - Bits */ +#define DP_F_MINUS (1 << 0) +#define DP_F_PLUS (1 << 1) +#define DP_F_SPACE (1 << 2) +#define DP_F_NUM (1 << 3) +#define DP_F_ZERO (1 << 4) +#define DP_F_UP (1 << 5) +#define DP_F_UNSIGNED (1 << 6) + +/* Conversion Flags */ +#define DP_C_SHORT 1 +#define DP_C_LONG 2 +#define DP_C_LLONG 3 +#define DP_C_LDOUBLE 4 + +#define char_to_int(p) (p - '0') +#define MAX(p,q) ((p >= q) ? p : q) +#define MIN(p,q) ((p <= q) ? p : q) + +static int dopr (char *buffer, size_t maxlen, const char *format, va_list args) +{ + char ch; + LLONG value; + LDOUBLE fvalue; + char *strvalue; + int min; + int max; + int state; + int flags; + int cflags; + int total; + size_t currlen; + + state = DP_S_DEFAULT; + currlen = flags = cflags = min = 0; + max = -1; + ch = *format++; + total = 0; + + while (state != DP_S_DONE) + { + if (ch == '\0') + state = DP_S_DONE; + + switch(state) + { + case DP_S_DEFAULT: + if (ch == '%') + state = DP_S_FLAGS; + else + total += dopr_outch (buffer, &currlen, maxlen, ch); + ch = *format++; + break; + case DP_S_FLAGS: + switch (ch) + { + case '-': + flags |= DP_F_MINUS; + ch = *format++; + break; + case '+': + flags |= DP_F_PLUS; + ch = *format++; + break; + case ' ': + flags |= DP_F_SPACE; + ch = *format++; + break; + case '#': + flags |= DP_F_NUM; + ch = *format++; + break; + case '0': + flags |= DP_F_ZERO; + ch = *format++; + break; + default: + state = DP_S_MIN; + break; + } + break; + case DP_S_MIN: + if ('0' <= ch && ch <= '9') + { + min = 10*min + char_to_int (ch); + ch = *format++; + } + else if (ch == '*') + { + min = va_arg (args, int); + ch = *format++; + state = DP_S_DOT; + } + else + state = DP_S_DOT; + break; + case DP_S_DOT: + if (ch == '.') + { + state = DP_S_MAX; + ch = *format++; + } + else + state = DP_S_MOD; + break; + case DP_S_MAX: + if ('0' <= ch && ch <= '9') + { + if (max < 0) + max = 0; + max = 10*max + char_to_int (ch); + ch = *format++; + } + else if (ch == '*') + { + max = va_arg (args, int); + ch = *format++; + state = DP_S_MOD; + } + else + state = DP_S_MOD; + break; + case DP_S_MOD: + switch (ch) + { + case 'h': + cflags = DP_C_SHORT; + ch = *format++; + break; + case 'l': + cflags = DP_C_LONG; + ch = *format++; + break; + case 'L': + cflags = DP_C_LDOUBLE; + ch = *format++; + break; + default: + break; + } + if (cflags != DP_C_LONG) + state = DP_S_CONV; + else + state = DP_S_MOD_L; + break; + case DP_S_MOD_L: + switch (ch) + { + case 'l': + cflags = DP_C_LLONG; + ch = *format++; + break; + default: + break; } + state = DP_S_CONV; + break; + case DP_S_CONV: + switch (ch) + { + case 'd': + case 'i': + if (cflags == DP_C_SHORT) + value = (short int)va_arg (args, int); + else if (cflags == DP_C_LONG) + value = va_arg (args, long int); + else if (cflags == DP_C_LLONG) + value = va_arg (args, LLONG); + else + value = va_arg (args, int); + total += fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); + break; + case 'o': + flags |= DP_F_UNSIGNED; + if (cflags == DP_C_SHORT) +// value = (unsigned short int) va_arg (args, unsigned short int); // Thilo: This does not work because the rcc compiler cannot do that cast correctly. + value = va_arg (args, unsigned int) & 0xFFFF; // Using this workaround instead. + else if (cflags == DP_C_LONG) + value = va_arg (args, unsigned long int); + else if (cflags == DP_C_LLONG) + value = va_arg (args, unsigned LLONG); + else + value = va_arg (args, unsigned int); + total += fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags); + break; + case 'u': + flags |= DP_F_UNSIGNED; + if (cflags == DP_C_SHORT) + value = va_arg (args, unsigned int) & 0xFFFF; + else if (cflags == DP_C_LONG) + value = va_arg (args, unsigned long int); + else if (cflags == DP_C_LLONG) + value = va_arg (args, unsigned LLONG); + else + value = va_arg (args, unsigned int); + total += fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); + break; + case 'X': + flags |= DP_F_UP; + case 'x': + flags |= DP_F_UNSIGNED; + if (cflags == DP_C_SHORT) + value = va_arg (args, unsigned int) & 0xFFFF; + else if (cflags == DP_C_LONG) + value = va_arg (args, unsigned long int); + else if (cflags == DP_C_LLONG) + value = va_arg (args, unsigned LLONG); + else + value = va_arg (args, unsigned int); + total += fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags); + break; + case 'f': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg (args, LDOUBLE); + else + fvalue = va_arg (args, double); + /* um, floating point? */ + total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); + break; + case 'E': + flags |= DP_F_UP; + case 'e': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg (args, LDOUBLE); + else + fvalue = va_arg (args, double); + /* um, floating point? */ + total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); + break; + case 'G': + flags |= DP_F_UP; + case 'g': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg (args, LDOUBLE); + else + fvalue = va_arg (args, double); + /* um, floating point? */ + total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); + break; + case 'c': + total += dopr_outch (buffer, &currlen, maxlen, va_arg (args, int)); + break; + case 's': + strvalue = va_arg (args, char *); + total += fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max); + break; + case 'p': + strvalue = va_arg (args, void *); + total += fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, + max, flags); + break; + case 'n': + if (cflags == DP_C_SHORT) + { + short int *num; + num = va_arg (args, short int *); + *num = currlen; + } + else if (cflags == DP_C_LONG) + { + long int *num; + num = va_arg (args, long int *); + *num = currlen; + } + else if (cflags == DP_C_LLONG) + { + LLONG *num; + num = va_arg (args, LLONG *); + *num = currlen; + } + else + { + int *num; + num = va_arg (args, int *); + *num = currlen; + } + break; + case '%': + total += dopr_outch (buffer, &currlen, maxlen, ch); + break; + case 'w': + /* not supported yet, treat as next char */ + ch = *format++; + break; + default: + /* Unknown, skip */ + break; + } + ch = *format++; + state = DP_S_DEFAULT; + flags = cflags = min = 0; + max = -1; + break; + case DP_S_DONE: + break; + default: + /* hmm? */ + break; /* some picky compilers need this */ + } + } + if (buffer != NULL) + { + if (currlen < maxlen - 1) + buffer[currlen] = '\0'; + else + buffer[maxlen - 1] = '\0'; + } + return total; +} - // write the float number - digits = 0; - val = (int)fval; - do { - text[digits++] = '0' + val % 10; - val /= 10; - } while ( val ); +static int fmtstr (char *buffer, size_t *currlen, size_t maxlen, + char *value, int flags, int min, int max) +{ + int padlen, strln; /* amount to pad */ + int cnt = 0; + int total = 0; + + if (value == 0) + { + value = ""; + } + + for (strln = 0; value[strln]; ++strln); /* strlen */ + if (max >= 0 && max < strln) + strln = max; + padlen = min - strln; + if (padlen < 0) + padlen = 0; + if (flags & DP_F_MINUS) + padlen = -padlen; /* Left Justify */ + + while (padlen > 0) + { + total += dopr_outch (buffer, currlen, maxlen, ' '); + --padlen; + } + while (*value && ((max < 0) || (cnt < max))) + { + total += dopr_outch (buffer, currlen, maxlen, *value++); + ++cnt; + } + while (padlen < 0) + { + total += dopr_outch (buffer, currlen, maxlen, ' '); + ++padlen; + } + return total; +} - if ( signedVal < 0 ) { - text[digits++] = '-'; - } +/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ - buf = *buf_p; +static int fmtint (char *buffer, size_t *currlen, size_t maxlen, + LLONG value, int base, int min, int max, int flags) +{ + int signvalue = 0; + unsigned LLONG uvalue; + char convert[24]; + int place = 0; + int spadlen = 0; /* amount to space pad */ + int zpadlen = 0; /* amount to zero pad */ + const char *digits; + int total = 0; + + if (max < 0) + max = 0; + + uvalue = value; + + if(!(flags & DP_F_UNSIGNED)) + { + if( value < 0 ) { + signvalue = '-'; + uvalue = -value; + } + else + if (flags & DP_F_PLUS) /* Do a sign (+/i) */ + signvalue = '+'; + else + if (flags & DP_F_SPACE) + signvalue = ' '; + } + + if (flags & DP_F_UP) + /* Should characters be upper case? */ + digits = "0123456789ABCDEF"; + else + digits = "0123456789abcdef"; + + do { + convert[place++] = digits[uvalue % (unsigned)base]; + uvalue = (uvalue / (unsigned)base ); + } while(uvalue && (place < sizeof (convert))); + if (place == sizeof (convert)) place--; + convert[place] = 0; + + zpadlen = max - place; + spadlen = min - MAX (max, place) - (signvalue ? 1 : 0); + if (zpadlen < 0) zpadlen = 0; + if (spadlen < 0) spadlen = 0; + if (flags & DP_F_ZERO) + { + zpadlen = MAX(zpadlen, spadlen); + spadlen = 0; + } + if (flags & DP_F_MINUS) + spadlen = -spadlen; /* Left Justifty */ + +#ifdef DEBUG_SNPRINTF + dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n", + zpadlen, spadlen, min, max, place)); +#endif - while ( digits < width ) { - *buf++ = ' '; - width--; - } + /* Spaces */ + while (spadlen > 0) + { + total += dopr_outch (buffer, currlen, maxlen, ' '); + --spadlen; + } + + /* Sign */ + if (signvalue) + total += dopr_outch (buffer, currlen, maxlen, signvalue); + + /* Zeros */ + if (zpadlen > 0) + { + while (zpadlen > 0) + { + total += dopr_outch (buffer, currlen, maxlen, '0'); + --zpadlen; + } + } + + /* Digits */ + while (place > 0) + total += dopr_outch (buffer, currlen, maxlen, convert[--place]); + + /* Left Justified spaces */ + while (spadlen < 0) { + total += dopr_outch (buffer, currlen, maxlen, ' '); + ++spadlen; + } + + return total; +} - while ( digits-- ) { - *buf++ = text[digits]; - } +static LDOUBLE abs_val (LDOUBLE value) +{ + LDOUBLE result = value; - *buf_p = buf; - - if (prec < 0) - prec = 6; - // write the fraction - digits = 0; - while (digits < prec) { - fval -= (int) fval; - fval *= 10.0; - val = (int) fval; - text[digits++] = '0' + val % 10; - } + if (value < 0) + result = -value; - if (digits > 0) { - buf = *buf_p; - *buf++ = '.'; - for (prec = 0; prec < digits; prec++) { - *buf++ = text[prec]; - } - *buf_p = buf; - } + return result; } +static LDOUBLE pow10 (int exp) +{ + LDOUBLE result = 1; + + while (exp) + { + result *= 10; + exp--; + } + + return result; +} -void AddString( char **buf_p, char *string, int width, int prec ) { - int size; - char *buf; +static long round (LDOUBLE value) +{ + long intpart; - buf = *buf_p; + intpart = value; + value = value - intpart; + if (value >= 0.5) + intpart++; - if ( string == NULL ) { - string = "(null)"; - prec = -1; - } + return intpart; +} - if ( prec >= 0 ) { - for( size = 0; size < prec; size++ ) { - if( string[size] == '\0' ) { - break; - } - } - } - else { - size = strlen( string ); - } +static int fmtfp (char *buffer, size_t *currlen, size_t maxlen, + LDOUBLE fvalue, int min, int max, int flags) +{ + int signvalue = 0; + LDOUBLE ufvalue; + char iconvert[20]; + char fconvert[20]; + int iplace = 0; + int fplace = 0; + int padlen = 0; /* amount to pad */ + int zpadlen = 0; + int caps = 0; + int total = 0; + long intpart; + long fracpart; + + /* + * AIX manpage says the default is 0, but Solaris says the default + * is 6, and sprintf on AIX defaults to 6 + */ + if (max < 0) + max = 6; + + ufvalue = abs_val (fvalue); + + if (fvalue < 0) + signvalue = '-'; + else + if (flags & DP_F_PLUS) /* Do a sign (+/i) */ + signvalue = '+'; + else + if (flags & DP_F_SPACE) + signvalue = ' '; - width -= size; +#if 0 + if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ +#endif - while( size-- ) { - *buf++ = *string++; - } + intpart = ufvalue; - while( width-- > 0 ) { - *buf++ = ' '; - } + /* + * Sorry, we only support 9 digits past the decimal because of our + * conversion method + */ + if (max > 9) + max = 9; - *buf_p = buf; -} + /* We "cheat" by converting the fractional part to integer by + * multiplying by a factor of 10 + */ + fracpart = round ((pow10 (max)) * (ufvalue - intpart)); -/* -vsprintf + if (fracpart >= pow10 (max)) + { + intpart++; + fracpart -= pow10 (max); + } -I'm not going to support a bunch of the more arcane stuff in here -just to keep it simpler. For example, the '*' and '$' are not -currently supported. I've tried to make it so that it will just -parse and ignore formats we don't support. -*/ -int vsprintf( char *buffer, const char *fmt, va_list argptr ) { - int *arg; - char *buf_p; - char ch; - int flags; - int width; - int prec; - int n; - char sign; - - buf_p = buffer; - arg = (int *)argptr; - - while( qtrue ) { - // run through the format string until we hit a '%' or '\0' - for ( ch = *fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++ ) { - *buf_p++ = ch; - } - if ( ch == '\0' ) { - goto done; - } +#ifdef DEBUG_SNPRINTF + dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart)); +#endif - // skip over the '%' - fmt++; - - // reset formatting state - flags = 0; - width = 0; - prec = -1; - sign = '\0'; - -rflag: - ch = *fmt++; -reswitch: - switch( ch ) { - case '-': - flags |= LADJUST; - goto rflag; - case '.': - n = 0; - while( is_digit( ( ch = *fmt++ ) ) ) { - n = 10 * n + ( ch - '0' ); - } - prec = n < 0 ? -1 : n; - goto reswitch; - case '0': - flags |= ZEROPAD; - goto rflag; - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - n = 0; - do { - n = 10 * n + ( ch - '0' ); - ch = *fmt++; - } while( is_digit( ch ) ); - width = n; - goto reswitch; - case 'c': - *buf_p++ = (char)*arg; - arg++; - break; - case 'd': - case 'i': - AddInt( &buf_p, *arg, width, flags ); - arg++; - break; - case 'f': - AddFloat( &buf_p, *(double *)arg, width, prec ); - arg += 1; // everything is 32 bit - break; - case 's': - AddString( &buf_p, (char *)*arg, width, prec ); - arg++; - break; - case '%': - *buf_p++ = ch; - break; - default: - *buf_p++ = (char)*arg; - arg++; - break; - } - } + /* Convert integer part */ + do { + iconvert[iplace++] = + (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10]; + intpart = (intpart / 10); + } while(intpart && (iplace < 20)); + if (iplace == 20) iplace--; + iconvert[iplace] = 0; + + /* Convert fractional part */ + do { + fconvert[fplace++] = + (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10]; + fracpart = (fracpart / 10); + } while(fracpart && (fplace < 20)); + if (fplace == 20) fplace--; + fconvert[fplace] = 0; + + /* -1 for decimal point, another -1 if we are printing a sign */ + padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); + zpadlen = max - fplace; + if (zpadlen < 0) + zpadlen = 0; + if (padlen < 0) + padlen = 0; + if (flags & DP_F_MINUS) + padlen = -padlen; /* Left Justifty */ + + if ((flags & DP_F_ZERO) && (padlen > 0)) + { + if (signvalue) + { + total += dopr_outch (buffer, currlen, maxlen, signvalue); + --padlen; + signvalue = 0; + } + while (padlen > 0) + { + total += dopr_outch (buffer, currlen, maxlen, '0'); + --padlen; + } + } + while (padlen > 0) + { + total += dopr_outch (buffer, currlen, maxlen, ' '); + --padlen; + } + if (signvalue) + total += dopr_outch (buffer, currlen, maxlen, signvalue); + + while (iplace > 0) + total += dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]); + + /* + * Decimal point. This should probably use locale to find the correct + * char to print out. + */ + if (max > 0) + { + total += dopr_outch (buffer, currlen, maxlen, '.'); + + while (zpadlen-- > 0) + total += dopr_outch (buffer, currlen, maxlen, '0'); + + while (fplace > 0) + total += dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]); + } + + while (padlen < 0) + { + total += dopr_outch (buffer, currlen, maxlen, ' '); + ++padlen; + } + + return total; +} -done: - *buf_p = 0; - return buf_p - buffer; +static int dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c) +{ + if (*currlen + 1 < maxlen) + buffer[(*currlen)++] = c; + return 1; +} + +int Q_vsnprintf(char *str, size_t length, const char *fmt, va_list args) +{ + if (str != NULL) + str[0] = 0; + return dopr(str, length, fmt, args); +} + +int Q_snprintf(char *str, size_t length, const char *fmt, ...) +{ + va_list ap; + int retval; + + va_start(ap, fmt); + retval = Q_vsnprintf(str, length, fmt, ap); + va_end(ap); + + return retval; } /* this is really crappy */ diff --git a/code/game/bg_lib.h b/code/game/bg_lib.h index 53879c1..54a379b 100644 --- a/code/game/bg_lib.h +++ b/code/game/bg_lib.h @@ -98,7 +98,9 @@ double _atof( const char **stringPtr ); int atoi( const char *string ); int _atoi( const char **stringPtr ); -int vsprintf( char *buffer, const char *fmt, va_list argptr ); +int Q_vsnprintf( char *buffer, size_t length, const char *fmt, va_list argptr ); +int Q_snprintf( char *buffer, size_t length, const char *fmt, ... ) __attribute__ ((format (printf, 3, 4))); + int sscanf( const char *buffer, const char *fmt, ... ) __attribute__ ((format (scanf, 2, 3))); // Memory functions diff --git a/code/game/g_main.c b/code/game/g_main.c index 977f7a5..91cb624 100644 --- a/code/game/g_main.c +++ b/code/game/g_main.c @@ -241,7 +241,7 @@ void QDECL G_Printf( const char *fmt, ... ) { char text[1024]; va_start (argptr, fmt); - vsprintf (text, fmt, argptr); + Q_vsnprintf (text, sizeof(text), fmt, argptr); va_end (argptr); trap_Printf( text ); @@ -252,7 +252,7 @@ void QDECL G_Error( const char *fmt, ... ) { char text[1024]; va_start (argptr, fmt); - vsprintf (text, fmt, argptr); + Q_vsnprintf (text, sizeof(text), fmt, argptr); va_end (argptr); trap_Error( text ); @@ -539,7 +539,7 @@ void QDECL Com_Error ( int level, const char *error, ... ) { char text[1024]; va_start (argptr, error); - vsprintf (text, error, argptr); + Q_vsnprintf (text, sizeof(text), error, argptr); va_end (argptr); G_Error( "%s", text); @@ -550,7 +550,7 @@ void QDECL Com_Printf( const char *msg, ... ) { char text[1024]; va_start (argptr, msg); - vsprintf (text, msg, argptr); + Q_vsnprintf (text, sizeof(text), msg, argptr); va_end (argptr); G_Printf ("%s", text); @@ -1092,7 +1092,7 @@ void QDECL G_LogPrintf( const char *fmt, ... ) { Com_sprintf( string, sizeof(string), "%3i:%i%i ", min, tens, sec ); va_start( argptr, fmt ); - vsprintf( string +7 , fmt,argptr ); + Q_vsnprintf(string + 7, sizeof(string - 7), fmt, argptr); va_end( argptr ); if ( g_dedicated.integer ) { diff --git a/code/game/g_team.c b/code/game/g_team.c index 96dddbf..ca5341d 100644 --- a/code/game/g_team.c +++ b/code/game/g_team.c @@ -108,7 +108,7 @@ void QDECL PrintMsg( gentity_t *ent, const char *fmt, ... ) { char *p; va_start (argptr,fmt); - if (vsprintf (msg, fmt, argptr) > sizeof(msg)) { + if (Q_vsnprintf (msg, sizeof(msg), fmt, argptr) > sizeof(msg)) { G_Error ( "PrintMsg overrun" ); } va_end (argptr); diff --git a/code/q3_ui/ui_atoms.c b/code/q3_ui/ui_atoms.c index e66996d..c798bdd 100644 --- a/code/q3_ui/ui_atoms.c +++ b/code/q3_ui/ui_atoms.c @@ -35,7 +35,7 @@ void QDECL Com_Error( int level, const char *error, ... ) { char text[1024]; va_start (argptr, error); - vsprintf (text, error, argptr); + Q_vsnprintf (text, sizeof(text), error, argptr); va_end (argptr); trap_Error( va("%s", text) ); @@ -46,7 +46,7 @@ void QDECL Com_Printf( const char *msg, ... ) { char text[1024]; va_start (argptr, msg); - vsprintf (text, msg, argptr); + Q_vsnprintf (text, sizeof(text), msg, argptr); va_end (argptr); trap_Print( va("%s", text) ); diff --git a/code/qcommon/common.c b/code/qcommon/common.c index 41cbbc0..9482c04 100644 --- a/code/qcommon/common.c +++ b/code/qcommon/common.c @@ -269,7 +269,7 @@ void QDECL Com_Error( int code, const char *fmt, ... ) { com_errorEntered = qtrue; va_start (argptr,fmt); - vsprintf (com_errorMessage,fmt,argptr); + Q_vsnprintf (com_errorMessage, sizeof(com_errorMessage),fmt,argptr); va_end (argptr); if (code != ERR_DISCONNECT && code != ERR_NEED_CD) diff --git a/code/qcommon/q_shared.c b/code/qcommon/q_shared.c index 81e4e80..5ce6bbf 100644 --- a/code/qcommon/q_shared.c +++ b/code/qcommon/q_shared.c @@ -295,7 +295,7 @@ void COM_ParseError( char *format, ... ) static char string[4096]; va_start (argptr, format); - vsprintf (string, format, argptr); + Q_vsnprintf (string, sizeof(string), format, argptr); va_end (argptr); Com_Printf("ERROR: %s, line %d: %s\n", com_parsename, com_lines, string); @@ -307,7 +307,7 @@ void COM_ParseWarning( char *format, ... ) static char string[4096]; va_start (argptr, format); - vsprintf (string, format, argptr); + Q_vsnprintf (string, sizeof(string), format, argptr); va_end (argptr); Com_Printf("WARNING: %s, line %d: %s\n", com_parsename, com_lines, string); @@ -928,7 +928,7 @@ void QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) { char bigbuffer[32000]; // big, but small enough to fit in PPC stack va_start (argptr,fmt); - len = vsprintf (bigbuffer,fmt,argptr); + len = Q_vsnprintf (bigbuffer, sizeof(bigbuffer), fmt,argptr); va_end (argptr); if ( len >= sizeof( bigbuffer ) ) { Com_Error( ERR_FATAL, "Com_sprintf: overflowed bigbuffer" ); @@ -951,20 +951,19 @@ va does a varargs printf into a temp buffer, so I don't need to have varargs versions of all text functions. -FIXME: make this buffer size safe someday ============ */ char * QDECL va( char *format, ... ) { va_list argptr; - static char string[2][32000]; // in case va is called by nested functions - static int index = 0; - char *buf; + static char string[2][32000]; // in case va is called by nested functions + static int index = 0; + char *buf; buf = string[index & 1]; index++; va_start (argptr, format); - vsprintf (buf, format,argptr); + Q_vsnprintf (buf, sizeof(*string), format, argptr); va_end (argptr); return buf; diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h index 9959f27..8f5dbe4 100644 --- a/code/qcommon/q_shared.h +++ b/code/qcommon/q_shared.h @@ -92,9 +92,13 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA **********************************************************************/ +#ifdef Q3_VM + #include "../game/bg_lib.h" -#ifndef Q3_VM +typedef int intptr_t; + +#else #include #include @@ -106,30 +110,38 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include #include +// vsnprintf is ISO/IEC 9899:1999 +// abstracting this to make it portable +#ifdef _WIN32 + #define Q_vsnprintf _vsnprintf + #define Q_snprintf _snprintf +#else + #define Q_vsnprintf vsnprintf + #define Q_snprintf snprintf +#endif + +#ifdef _MSC_VER + #include + + typedef __int64 int64_t; + typedef __int32 int32_t; + typedef __int16 int16_t; + typedef __int8 int8_t; + typedef unsigned __int64 uint64_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int8 uint8_t; +#else + #include +#endif + #endif + #include "q_platform.h" //============================================================= -#ifdef Q3_VM - typedef int intptr_t; -#else - #ifndef _MSC_VER - #include - #else - #include - typedef __int64 int64_t; - typedef __int32 int32_t; - typedef __int16 int16_t; - typedef __int8 int8_t; - typedef unsigned __int64 uint64_t; - typedef unsigned __int32 uint32_t; - typedef unsigned __int16 uint16_t; - typedef unsigned __int8 uint8_t; - #endif -#endif - typedef unsigned char byte; typedef enum {qfalse, qtrue} qboolean; diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index 817bbab..877b655 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -695,16 +695,6 @@ MISC ============================================================== */ -// vsnprintf is ISO/IEC 9899:1999 -// abstracting this to make it portable -#ifdef _WIN32 -#define Q_vsnprintf _vsnprintf -#define Q_snprintf _snprintf -#else -#define Q_vsnprintf vsnprintf -#define Q_snprintf snprintf -#endif - // centralizing the declarations for cl_cdkey // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=470 extern char cl_cdkey[34]; diff --git a/code/server/sv_bot.c b/code/server/sv_bot.c index 2996561..b0fc1e8 100644 --- a/code/server/sv_bot.c +++ b/code/server/sv_bot.c @@ -139,7 +139,7 @@ void QDECL BotImport_Print(int type, char *fmt, ...) va_list ap; va_start(ap, fmt); - vsprintf(str, fmt, ap); + Q_vsnprintf(str, sizeof(str), fmt, ap); va_end(ap); switch(type) { diff --git a/code/server/sv_rankings.c b/code/server/sv_rankings.c index 844447b..90a90aa 100644 --- a/code/server/sv_rankings.c +++ b/code/server/sv_rankings.c @@ -1523,7 +1523,7 @@ static void SV_RankError( const char* fmt, ... ) char text[1024]; va_start( arg_ptr, fmt ); - vsprintf( text, fmt, arg_ptr ); + Q_vsnprintf(text, sizeof(text), fmt, arg_ptr ); va_end( arg_ptr ); Com_DPrintf( "****************************************\n" ); diff --git a/code/ui/ui_atoms.c b/code/ui/ui_atoms.c index 1a2780f..50c4ed6 100644 --- a/code/ui/ui_atoms.c +++ b/code/ui/ui_atoms.c @@ -34,7 +34,7 @@ void QDECL Com_Error( int level, const char *error, ... ) { char text[1024]; va_start (argptr, error); - vsprintf (text, error, argptr); + Q_vsnprintf (text, sizeof(text), error, argptr); va_end (argptr); trap_Error( va("%s", text) ); @@ -45,7 +45,7 @@ void QDECL Com_Printf( const char *msg, ... ) { char text[1024]; va_start (argptr, msg); - vsprintf (text, msg, argptr); + Q_vsnprintf (text, sizeof(text), msg, argptr); va_end (argptr); trap_Print( va("%s", text) ); diff --git a/code/ui/ui_shared.c b/code/ui/ui_shared.c index d2593fd..3b2ac7d 100644 --- a/code/ui/ui_shared.c +++ b/code/ui/ui_shared.c @@ -258,7 +258,7 @@ void PC_SourceWarning(int handle, char *format, ...) { static char string[4096]; va_start (argptr, format); - vsprintf (string, format, argptr); + Q_vsnprintf (string, sizeof(string), format, argptr); va_end (argptr); filename[0] = '\0'; @@ -280,7 +280,7 @@ void PC_SourceError(int handle, char *format, ...) { static char string[4096]; va_start (argptr, format); - vsprintf (string, format, argptr); + Q_vsnprintf (string, sizeof(string), format, argptr); va_end (argptr); filename[0] = '\0'; -- cgit v1.2.3