Fix up an __int64 networking issue. allow qc's sprintf builtin to print them ('q' modifier, also works for doubles when paired with the 'float' modifier as appropriate).

This commit is contained in:
Shpoike 2023-08-01 12:22:38 +01:00
parent e48e9c67ad
commit 75166b0815
3 changed files with 110 additions and 36 deletions

View file

@ -2264,9 +2264,9 @@ quint64_t MSG_ReadUInt64 (void)
v-=l;
b++;
}
r = v<<(b*8);
r = (quint64_t)v<<(b*8);
while(b --> 0)
r |= MSG_ReadByte()<<(b*8);
r |= (quint64_t)MSG_ReadByte()<<(b*8);
return r;
}
qint64_t MSG_ReadInt64 (void)

View file

@ -7011,7 +7011,7 @@ void QCBUILTIN PF_sprintf_internal (pubprogfuncs_t *prinst, struct globalvars_s
char formatbuf[16];
char *f;
int argpos = firstarg;
int isfloat;
int isfloat, is64bit;
static int dummyivec[3] = {0, 0, 0};
static float dummyvec[3] = {0, 0, 0};
@ -7024,11 +7024,18 @@ void QCBUILTIN PF_sprintf_internal (pubprogfuncs_t *prinst, struct globalvars_s
formatbuf[0] = '%';
#define GETARG_FLOAT(a) (((a)>=firstarg && (a)<prinst->callargc) ? (G_FLOAT(OFS_PARM0 + 3 * (a))) : 0)
#define GETARG_DOUBLE(a) (((a)>=firstarg && (a)<prinst->callargc) ? (G_FLOAT(OFS_PARM0 + 3 * (a))) : 0)
#define GETARG_VECTOR(a) (((a)>=firstarg && (a)<prinst->callargc) ? (G_VECTOR(OFS_PARM0 + 3 * (a))) : dummyvec)
#define GETARG_INT(a) (((a)>=firstarg && (a)<prinst->callargc) ? (G_INT(OFS_PARM0 + 3 * (a))) : 0)
#define GETARG_INT64(a) (((a)>=firstarg && (a)<prinst->callargc) ? (G_INT64(OFS_PARM0 + 3 * (a))) : 0)
#define GETARG_UINT(a) (((a)>=firstarg && (a)<prinst->callargc) ? (G_UINT(OFS_PARM0 + 3 * (a))) : 0)
#define GETARG_UINT64(a) (((a)>=firstarg && (a)<prinst->callargc) ? (G_UINT64(OFS_PARM0 + 3 * (a))) : 0)
#define GETARG_INTVECTOR(a) (((a)>=firstarg && (a)<prinst->callargc) ? ((int*) G_VECTOR(OFS_PARM0 + 3 * (a))) : dummyivec)
#define GETARG_STRING(a) (((a)>=firstarg && (a)<prinst->callargc) ? (PR_GetStringOfs(prinst, OFS_PARM0 + 3 * (a))) : "")
#define GETARG_SNUMERIC(t, a) (is64bit?(isfloat ? (t) GETARG_DOUBLE(a) : (t) GETARG_INT64 (a)):(isfloat ? (t) GETARG_FLOAT(a) : (t) GETARG_INT (a)))
#define GETARG_UNUMERIC(t, a) (is64bit?(isfloat ? (t) GETARG_DOUBLE(a) : (t) GETARG_UINT64(a)):(isfloat ? (t) GETARG_FLOAT(a) : (t) GETARG_UINT(a)))
for(;;)
{
s0 = s;
@ -7050,6 +7057,7 @@ void QCBUILTIN PF_sprintf_internal (pubprogfuncs_t *prinst, struct globalvars_s
thisarg = -1;
flags = 0;
isfloat = -1;
is64bit = 0;
// is number following?
if(*s >= '0' && *s <= '9')
@ -7176,10 +7184,18 @@ noflags:
{
switch(*s)
{
/* note: this is technically a dp extension, so for our inputs:
dp defined %lx for entity numbers (it not having actual ints)
it later defined %llx for Actual ints, not that it makes a difference in DP.
This leaves us unable to use C's 'l' for our int64 type (aka long), nor 'll' either.
So lean on BSD's 'q'.
for our outputs, %llx is standard for int64 with MS violating c99 and requiring %I64x instead.
*/
case 'h': isfloat = 1; break; //short in C, interpreted as float here. doubled for char.
case 'l': isfloat = 0; break; //long, twice for long long... we interpret as int32.
case 'L': isfloat = 0; break; //'long double'
//case 'q': isfloat = 0; break; //synonym for long long.
case 'q': is64bit = 1; break; //BSD synonym for long long. or more specifically int64 and NOT int128.
case 'j': break; //intmax_t
//case 'Z': //synonym for 'z'. do not use
case 'z': break; //size_t
@ -7229,6 +7245,24 @@ nolength:
*f++ = '.';
*f++ = '*';
}
switch(*s)
{
case 'd': case 'i': case 'I':
case 'o': case 'u': case 'x': case 'X': case 'p': case 'P':
#ifdef _WIN32 //not c99
*f++ = 'I';
*f++ = '6';
*f++ = '4';
#else //c99
*f++ = 'l';
if (sizeof(long) == 4)
*f++ = 'l'; //go for long long instead
#endif
break;
}
if (*s == 'p')
*f++ = 'x';
else if (*s == 'P')
@ -7246,23 +7280,23 @@ nolength:
{
case 'd': case 'i': case 'I':
if(precision < 0) // not set
Q_snprintfz(o, end - o, formatbuf, width, (isfloat ? (int) GETARG_FLOAT(thisarg) : (int) GETARG_INT(thisarg)));
Q_snprintfz(o, end - o, formatbuf, width, GETARG_SNUMERIC(qint64_t, thisarg));
else
Q_snprintfz(o, end - o, formatbuf, width, precision, (isfloat ? (int) GETARG_FLOAT(thisarg) : (int) GETARG_INT(thisarg)));
Q_snprintfz(o, end - o, formatbuf, width, precision, GETARG_SNUMERIC(qint64_t, thisarg));
o += strlen(o);
break;
case 'o': case 'u': case 'x': case 'X': case 'p': case 'P':
if(precision < 0) // not set
Q_snprintfz(o, end - o, formatbuf, width, (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg)));
Q_snprintfz(o, end - o, formatbuf, width, GETARG_UNUMERIC(quint64_t, thisarg));
else
Q_snprintfz(o, end - o, formatbuf, width, precision, (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg)));
Q_snprintfz(o, end - o, formatbuf, width, precision, GETARG_UNUMERIC(quint64_t, thisarg));
o += strlen(o);
break;
case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
if(precision < 0) // not set
Q_snprintfz(o, end - o, formatbuf, width, (isfloat ? (double) GETARG_FLOAT(thisarg) : (double) GETARG_INT(thisarg)));
Q_snprintfz(o, end - o, formatbuf, width, GETARG_SNUMERIC(double, thisarg));
else
Q_snprintfz(o, end - o, formatbuf, width, precision, (isfloat ? (double) GETARG_FLOAT(thisarg) : (double) GETARG_INT(thisarg)));
Q_snprintfz(o, end - o, formatbuf, width, precision, GETARG_SNUMERIC(double, thisarg));
o += strlen(o);
break;
case 'v': case 'V':

View file

@ -5919,7 +5919,7 @@ static void QCC_VerifyFormatString (const char *funcname, QCC_ref_t **arglist, u
char formatbuf[16];
char temp[256];
int argpos = firstarg, argn_last = firstarg;
int isfloat;
int isfloat, is64bit;
const QCC_eval_t *formatstring = QCC_SRef_EvalConst(arglist[0]->base);
if (!formatstring) //can't check variables.
return;
@ -5952,6 +5952,7 @@ static void QCC_VerifyFormatString (const char *funcname, QCC_ref_t **arglist, u
width = -1;
thisarg = -1;
isfloat = -1;
is64bit = 0;
// is number following?
if(*s >= '0' && *s <= '9')
@ -6078,7 +6079,7 @@ noflags:
//case 'll': //long long
case 'l': isfloat = 0; break; //long
case 'L': isfloat = 0; break; //long double
//case 'q': break; //long long in c
case 'q': is64bit = 1; break; //BSD's int64
case 'j': //[u]intmax_t
case 'z': //size_t
case 't': //ptrdiff_t
@ -6125,21 +6126,38 @@ nolength:
case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
if (isfloat)
{
switch(ARGTYPE(thisarg))
if (is64bit)
{
case ev_float:
case ev_variant:
break;
default:
reqtype = "float";
break;
switch(ARGTYPE(thisarg))
{
case ev_double:
case ev_variant:
break;
default:
reqtype = "double";
break;
}
}
else
{
switch(ARGTYPE(thisarg))
{
case ev_float:
case ev_variant:
break;
default:
reqtype = "float";
break;
}
}
}
else
{
if (*s == 'p' || *s == 'P')
{
switch(ARGTYPE(thisarg))
if (is64bit)
reqtype = "some kind of double-size pointer! oh noes!";
else switch(ARGTYPE(thisarg))
{
case ev_pointer:
case ev_variant:
@ -6151,20 +6169,37 @@ nolength:
}
else
{
switch(ARGTYPE(thisarg))
if (is64bit)
{
case ev_integer:
case ev_uint:
case ev_variant:
break;
case ev_entity: //accept ents ONLY for %i
if (*s == 'i')
switch(ARGTYPE(thisarg))
{
case ev_int64:
case ev_uint64:
case ev_variant:
break;
//fallthrough
default:
reqtype = "int";
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s%s%s requires int at arg %i (got %s%s%s)", funcname, col_name, formatbuf, col_none, thisarg+1, col_type, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)), col_none);
break;
default:
reqtype = "__int64";
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s%s%s requires __int64 at arg %i (got %s%s%s)", funcname, col_name, formatbuf, col_none, thisarg+1, col_type, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)), col_none);
break;
}
}
else
{
switch(ARGTYPE(thisarg))
{
case ev_integer:
case ev_uint:
case ev_variant:
break;
case ev_entity: //accept ents ONLY for %i
if (*s == 'i')
break;
//fallthrough
default:
reqtype = "int";
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s%s%s requires int at arg %i (got %s%s%s)", funcname, col_name, formatbuf, col_none, thisarg+1, col_type, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)), col_none);
break;
}
}
}
}
@ -6228,14 +6263,19 @@ nolength:
case ev_uint:
QCC_PR_Note(WARN_FORMATSTRING, s_filen, pr_source_line, "%s", "use %lu or or %lx for 32bit ints");
break;
case ev_int64:
QCC_PR_Note(WARN_FORMATSTRING, s_filen, pr_source_line, "%s", "use %qi or %lqx for 64bit ints");
break;
case ev_uint64:
QCC_PR_Note(WARN_FORMATSTRING, s_filen, pr_source_line, "%s", "use %lqu or or %lqx for 64bit ints");
break;
case ev_double:
QCC_PR_Note(WARN_FORMATSTRING, s_filen, pr_source_line, "%s", "use %qg or %qf or %hqx for doubles");
break;
case ev_void: //coder's problem
case ev_field: //cast to int
case ev_function: //cast to int
case ev_variant: //should be accepted by anything...
case ev_int64: //specification problem
case ev_uint64: //specification problem
case ev_double: //specification problem
case ev_struct: //coder's problem
case ev_union: //coder's problem
case ev_accessor: //should be unreachable