fteqw: add memrealloc builtin.

fteqw: make it a bit clearer when there's no tls drivers compiled/loaded.
fteqcc: fix decompiler code to not crash nor misbehave on 64bit cpus.
fteqcc: add -TDP_20241108 to target dp's most recent additions.
fteqcc: add -Fundefwordsize (autoenabled when targetting dp) to tell the compiler to not make any assumptions about runtime pointer types. this skips some optimisations, blocks sizeof(float), casts between pointer and string,  and a few other sizing things, unsafe operations will become errors.
fteqcc: add -FILP32 - changes 'long' datatype to int32_t, which should match common C assumptions around long/size_t/intptr_t
fteqcc: add -Fpointerrelocs (autoenabled with a recent enough fte target). this finally allows pointer globals to be preinitialised with the addresses of other globals.
fteqcc: add -Fomitinternals. this omits the reflection data in the progs roughly equivelent to visibility=hidden om linux. This WILL break saved games, and probably a few other things too, but will greatly reduce stringtable sizes.
fteqcc: improve compat when compiling C code
qclib: fix op_push
This commit is contained in:
Shpoike 2024-11-19 00:37:12 +00:00
parent 7e9d138d5f
commit dc010d6ec8
25 changed files with 2256 additions and 1425 deletions

View file

@ -161,6 +161,7 @@ IF(ZLIB_FOUND)
SET(FTE_LIBS ${FTE_LIBS} ${ZLIB_LIBRARIES})
SET(FTESV_LIBS ${FTESV_LIBS} ${ZLIB_LIBRARIES})
SET(FTEQCC_LIBS ${FTEQCC_LIBS} ${ZLIB_LIBRARIES})
SET(FTEQTV_LIBS ${FTEQTV_LIBS} ${ZLIB_LIBRARIES})
ELSE()
MESSAGE(WARNING "libz library NOT available. compressed pk3, ICE, Q2E, etc etc, yada yada, blah blah will not be available.")
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_ZLIB)
@ -202,16 +203,18 @@ ELSE()
SET(JPEG_LIBRARIES)
ENDIF()
SET(FTE_DEP_DBUS true CACHE BOOL "Link against libdbus.")
IF(FTE_DEP_DBUS)
FIND_PACKAGE(DBus1)
ENDIF()
IF(DBUS1_FOUND)
INCLUDE_DIRECTORIES( ${DBus1_INCLUDE_DIRS} )
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};HAVE_DBUS)
SET(FTE_LIBS ${FTE_LIBS} ${DBus1_LIBRARIES})
ELSE()
MESSAGE(WARNING "libdbus-1 library NOT available. Who cares?")
IF(NOT ${WIN32})
SET(FTE_DEP_DBUS true CACHE BOOL "Link against libdbus.")
IF(FTE_DEP_DBUS)
FIND_PACKAGE(DBus1)
ENDIF()
IF(DBUS1_FOUND)
INCLUDE_DIRECTORIES( ${DBus1_INCLUDE_DIRS} )
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};HAVE_DBUS)
SET(FTE_LIBS ${FTE_LIBS} ${DBus1_LIBRARIES})
ELSE()
MESSAGE(WARNING "libdbus-1 library NOT available. Who cares?")
ENDIF()
ENDIF()
SET(FTE_DEP_PNG true CACHE BOOL "Link against libpng.")
@ -1192,16 +1195,16 @@ ELSE()
fteqtv/libqtvc/glibc_sucks.c
engine/common/sha1.c
)
SET_TARGET_PROPERTIES(qtv PROPERTIES COMPILE_DEFINITIONS "${FTE_REVISON}")
SET_TARGET_PROPERTIES(qtv PROPERTIES COMPILE_DEFINITIONS "${FTE_REVISON};${FTE_LIB_DEFINES}")
IF(WIN32)
TARGET_LINK_LIBRARIES(qtv ws2_32 winmm ${SYS_LIBS} ${ZLIB_LIBRARIES})
TARGET_LINK_LIBRARIES(qtv ws2_32 winmm ${SYS_LIBS} ${FTEQTV_LIBS})
ELSEIF(LINUX)
TARGET_LINK_LIBRARIES(qtv ${SYS_LIBS} ${ZLIB_LIBRARIES})
TARGET_LINK_LIBRARIES(qtv ${SYS_LIBS} ${FTEQTV_LIBS})
# Add Epoll-shim for the Unixes here - Brad
ELSE()
FIND_LIBRARY(epoll-shim REQUIRED)
TARGET_INCLUDE_DIRECTORIES(qtv PUBLIC "${EPOLL_INC_DIR}")
TARGET_LINK_LIBRARIES(qtv epoll-shim ${SYS_LIBS} ${ZLIB_LIBRARIES})
TARGET_LINK_LIBRARIES(qtv epoll-shim ${SYS_LIBS} ${FTEQTV_LIBS})
ENDIF()
SET(INSTALLTARGS ${INSTALLTARGS} qtv)
ENDIF()
@ -1480,6 +1483,7 @@ IF(FTE_PLUG_IRC)
EMBED_PLUGIN_META(irc "IRC Plugin" "Allows you to chat on IRC without tabbing out.")
ENDIF()
IF(ZLIB_FOUND)
#mpq package format plugin (blizzard games)
SET(FTE_PLUG_MPQ false CACHE BOOL "Compile mpq junk.")
IF(FTE_PLUG_MPQ)
@ -1493,6 +1497,7 @@ IF(FTE_PLUG_MPQ)
EMBED_PLUGIN_META(irc "MPQ Archive Plugin" "Adds support for reading .mpq files. Not very useful...")
ENDIF()
ENDIF()
#vpk package format plugin (halflife2)
SET(FTE_PLUG_HL2 true CACHE BOOL "Compile support for hl2 file formats.")

View file

@ -4839,7 +4839,13 @@ static void QCBUILTIN PF_getlightstylergb (pubprogfuncs_t *prinst, struct global
return;
}
if (stnum >= cl_max_lightstyles || !cl_lightstyle[stnum].length)
if (stnum >= cl_max_lightstyles)
{
value = ('m'-'a')*22 * r_lightstylescale.value;
G_VECTOR(OFS_RETURN)[0] = G_VECTOR(OFS_RETURN)[1] = G_VECTOR(OFS_RETURN)[2] = value*(1.0/256);
return;
}
else if (!cl_lightstyle[stnum].length)
value = ('m'-'a')*22 * r_lightstylescale.value;
else if (cl_lightstyle[stnum].map[0] == '=')
value = atof(cl_lightstyle[stnum].map+1)*256*r_lightstylescale.value;
@ -7120,6 +7126,7 @@ static struct {
{"releasecustomskin", PF_cs_releasecustomskin, 379},
{"memalloc", PF_memalloc, 384},
{"memrealloc", PF_memrealloc, 0},
{"memfree", PF_memfree, 385},
{"memcmp", PF_memcmp, 0},
{"memcpy", PF_memcpy, 386},

View file

@ -2662,6 +2662,7 @@ static struct {
{"setcustomskin", PF_m_setcustomskin, 376},
//gap
{"memalloc", PF_memalloc, 384},
{"memrealloc", PF_memrealloc, 0},
{"memfree", PF_memfree, 385},
{"memcmp", PF_memcmp, 0},
{"memcpy", PF_memcpy, 386},

View file

@ -223,10 +223,16 @@ static void NET_TLS_Provider_Changed(struct cvar_s *var, char *oldvalue)
}
if (host_initialized && !var->ival)
{
Con_Printf("%s: \"%s\" not loaded, valid values are:", var->name, var->string);
int found = 0;
for (i = 0; i < cryptolib_count; i++)
if (cryptolib[i])
{
if (!found++)
Con_Printf("%s: \"%s\" not loaded, valid values are:", var->name, var->string);
Con_Printf(" ^[%s\\type\\%s %s^]", cryptolib[i]->drivername, var->name, cryptolib[i]->drivername);
}
if (!found)
Con_Printf("%s: no tls plugins loaded", var->name);
Con_Printf("\n");
}

View file

@ -2040,6 +2040,8 @@ void QCBUILTIN PF_memalloc (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
{
int size = G_INT(OFS_PARM0);
void *ptr;
if (!size)
size = 1; //return something free can free.
if (size <= 0 || size > 0x01000000)
ptr = NULL; //don't let them abuse things too much. values that are too large might overflow.
else
@ -2050,7 +2052,29 @@ void QCBUILTIN PF_memalloc (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
G_INT(OFS_RETURN) = (char*)ptr - prinst->stringtable;
}
else
{
G_INT(OFS_RETURN) = 0;
PR_BIError(prinst, "PF_memalloc: failure (size %i)\n", size);
}
}
void QCBUILTIN PF_memrealloc (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
void *oldcptr = prinst->stringtable + G_INT(OFS_PARM0);
int size = G_INT(OFS_PARM1);
void *ptr;
if (!size)
size = 1; //return something free can free.
if (size <= 0 || size > 0x01000000)
ptr = NULL; //don't let them abuse things too much. values that are too large might overflow.
else
ptr = prinst->AddressableRealloc(prinst, oldcptr, size);
if (ptr)
G_INT(OFS_RETURN) = (char*)ptr - prinst->stringtable;
else
{
G_INT(OFS_RETURN) = 0;
PR_BIError(prinst, "PF_memrealloc: failure (size %i)\n", size);
}
}
void QCBUILTIN PF_memfree (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
@ -3219,17 +3243,17 @@ void QCBUILTIN PF_fseek (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
G_INT(OFS_RETURN) = -1;
if (fnum < 0 || fnum >= MAX_QC_FILES)
{
PF_Warningf(prinst, "PF_fread: File out of range\n");
PF_Warningf(prinst, "PF_fseek: File out of range\n");
return; //out of range
}
if (!pf_fopen_files[fnum].prinst)
{
PF_Warningf(prinst, "PF_fread: File is not open\n");
PF_Warningf(prinst, "PF_fseek: File is not open\n");
return; //not open
}
if (pf_fopen_files[fnum].prinst != prinst)
{
PF_Warningf(prinst, "PF_fread: File is from wrong instance\n");
PF_Warningf(prinst, "PF_fseek: File is from wrong instance\n");
return; //this just isn't ours.
}
@ -3414,7 +3438,7 @@ void QCBUILTIN PF_fexists (pubprogfuncs_t *prinst, struct globalvars_s *pr_globa
void QCBUILTIN PF_rmtree (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *fname = PR_GetStringOfs(prinst, OFS_PARM0);
Con_Printf("rmtree(\"%s\"): rmtree is not implemented at this\n", fname);
Con_Printf("rmtree(\"%s\"): rmtree is not implemented at this time\n", fname);
/*flocation_t loc;
G_FLOAT(OFS_RETURN) = -1; //error

View file

@ -593,6 +593,7 @@ void QCBUILTIN PF_base64encode(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
void QCBUILTIN PF_base64decode(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_memalloc (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_memrealloc(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_memfree (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_memcmp (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_memcpy (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);

View file

@ -102,10 +102,10 @@ qcvm.a: $(QCC_OBJS) $(VM_OBJS) $(COMMON_OBJS)
test.o: test.c
$(DO_CC)
testapp.bin: test.o qcvm.a
$(CC) $(BASE_CFLAGS) $(CFLAGS) -o testapp.bin -O3 $(BASE_LDFLAGS) $^ -lm -lz
qcvm: test.o qcvm.a
$(CC) $(BASE_CFLAGS) $(CFLAGS) -o qcvm -O3 $(BASE_LDFLAGS) $^ -lm -lz -ggdb
tests: testapp.bin
tests: qcvm
@echo Running Tests...
@$(foreach a,$(wildcard tests/*.src), echo TEST: $a; rm progs.dat; ./testapp.bin progs.dat -srcfile $a; echo; echo)
@echo Tests run.

View file

@ -65,6 +65,7 @@ void *qccHunkAlloc(size_t mem)
void qccClearHunk(void)
{
struct qcchunk_s *t;
QCC_PurgeTemps();
while (qcc_hunk)
{
t = qcc_hunk;

File diff suppressed because it is too large Load diff

View file

@ -1602,14 +1602,15 @@ reeval:
return s;
*/ }
break;
case OP_PUSH:
case OP_PUSH: //note: OPA is words, not bytes.
OPC->_int = ENGINEPOINTER(&prinst.localstack[prinst.localstack_used+prinst.spushed]);
prinst.spushed += OPA->_int;
if (prinst.spushed + prinst.localstack_used >= LOCALSTACK_SIZE)
{
i = prinst.spushed;
prinst.spushed = 0;
prinst.pr_xstatement = st-pr_statements;
PR_RunError(&progfuncs->funcs, "Progs pushed too much");
PR_RunError(&progfuncs->funcs, "Progs pushed too much (%i bytes, %i parents, max %i)", i, prinst.localstack_used, LOCALSTACK_SIZE);
}
break;
/* case OP_POP:

View file

@ -445,6 +445,56 @@ static void PDECL PR_memfree (pubprogfuncs_t *ppf, void *memptr)
PR_memvalidate(progfuncs);
}
static void *PDECL PR_memrealloc (pubprogfuncs_t *ppf, void *memptr, unsigned int newsize)
{
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
qcmemusedblock_t *ub;
unsigned int ptr = memptr?((char*)memptr - progfuncs->funcs.stringtable):0;
void *newptr;
unsigned int oldsize;
/*freeing NULL is ignored*/
if (!ptr) //realloc instead of malloc is accepted.
return PR_memalloc(ppf, newsize);
PR_memvalidate(progfuncs);
ptr -= sizeof(qcmemusedblock_t);
if (/*ptr < 0 ||*/ ptr >= prinst.addressableused)
{
ptr += sizeof(qcmemusedblock_t);
if (ptr < prinst.addressableused && !*(char*)memptr)
{
//the empty string is a point of contention. while we can detect it from fteqcc, its best to not give any special favours (other than nicer debugging, where possible)
//we might not actually spot it from other qccs, so warning about it where possible is probably a very good thing.
externs->Printf("PR_memrealloc: unable to free the non-null empty string constant at %x\n", ptr);
}
else
externs->Printf("PR_memrealloc: pointer invalid - out of range (%x >= %x)\n", ptr, (unsigned int)prinst.addressableused);
PR_StackTrace(&progfuncs->funcs, false);
return NULL;
}
//this is the used block that we're trying to free
ub = (qcmemusedblock_t*)(progfuncs->funcs.stringtable + ptr);
if (ub->marker != MARKER_USED || ub->size <= sizeof(*ub) || ptr + ub->size > (unsigned int)prinst.addressableused)
{
externs->Printf("PR_memrealloc: pointer lacks marker - double-freed?\n");
PR_StackTrace(&progfuncs->funcs, false);
return NULL;
}
oldsize = ub->size;
oldsize -= sizeof(qcmemusedblock_t); //ignore the header.
newptr = PR_memalloc(ppf, newsize);
if (oldsize > newsize)
oldsize = newsize; //don't copy it all.
memcpy(newptr, memptr, oldsize);
newsize -= oldsize;
memset((char*)newptr+oldsize, 0, newsize); //clear out any extended part.
PR_memfree(ppf, memptr); //free the old.
return newptr;
}
void PRAddressableFlush(progfuncs_t *progfuncs, size_t totalammount)
{
prinst.addressableused = 0;
@ -1685,6 +1735,7 @@ static pubprogfuncs_t deffuncs = {
ED_NewString,
QC_HunkAlloc,
PR_memalloc,
PR_memrealloc,
PR_memfree,
PR_AllocTempString,
PR_AllocTempStringLen,

View file

@ -1036,6 +1036,20 @@ char *PR_GlobalStringNoContents (progfuncs_t *progfuncs, int ofs)
return line;
}
char *PR_GlobalStringImmediate (progfuncs_t *progfuncs, int ofs)
{
int i;
static char line[128];
sprintf (line,"%i", ofs);
i = strlen(line);
for ( ; i<20 ; i++)
strcat (line," ");
strcat (line," ");
return line;
}
/*
=============
ED_Print
@ -2742,6 +2756,7 @@ pbool PR_ReallyLoadProgs (progfuncs_t *progfuncs, const char *filename, progstat
int reorg = prinst.reorganisefields || prinst.numfields;
int stringadjust;
int pointeradjust;
int *basictypetable;
@ -3027,9 +3042,15 @@ retry:
glob = pr_globals = (float *)s;
if (progfuncs->funcs.stringtable)
{
stringadjust = pr_strings - progfuncs->funcs.stringtable;
pointeradjust = (char*)glob - progfuncs->funcs.stringtable;
}
else
{
stringadjust = 0;
pointeradjust = (char*)glob - pr_strings;
}
if (!pr_linenums)
{
@ -3552,6 +3573,13 @@ retry:
((int *)glob)[gd16[i].ofs] |= progstype << 24;
}
break;
case ev_pointer:
if (((int *)glob)[gd16[i].ofs] & 0x80000000)
{
((int *)glob)[gd16[i].ofs] &= ~0x80000000;
((int *)glob)[gd16[i].ofs] += pointeradjust;
}
break;
}
}
break;
@ -3589,6 +3617,13 @@ retry:
if (((int *)glob)[pr_globaldefs32[i].ofs]) //don't change null funcs
((int *)glob)[pr_globaldefs32[i].ofs] |= progstype << 24;
break;
case ev_pointer:
if (((int *)glob)[pr_globaldefs32[i].ofs] & 0x80000000)
{
((int *)glob)[pr_globaldefs32[i].ofs] &= ~0x80000000;
((int *)glob)[pr_globaldefs32[i].ofs] += pointeradjust;
}
break;
}
}
@ -3628,6 +3663,10 @@ retry:
if (progfuncs->funcs.stringtablesize + progfuncs->funcs.stringtable < pr_strings + pr_progs->numstrings)
progfuncs->funcs.stringtablesize = (pr_strings + pr_progs->numstrings) - progfuncs->funcs.stringtable;
//make sure the localstack is addressable to the qc, so we can OP_PUSH okay.
if (!prinst.localstack)
prinst.localstack = PRAddressableExtend(progfuncs, NULL, 0, sizeof(float)*LOCALSTACK_SIZE);
if (externs->MapNamedBuiltin)
{
for (i=0,fnc2=pr_cp_functions; i<pr_progs->numfunctions; i++, fnc2++)

View file

@ -128,8 +128,8 @@ static void PR_PrintStatement (progfuncs_t *progfuncs, int statementnum)
if ( (unsigned)op < OP_NUMOPS)
{
int i;
externs->Printf ("%s ", pr_opcodes[op].name);
i = strlen(pr_opcodes[op].name);
externs->Printf ("%s ", pr_opcodes[op].opname);
i = strlen(pr_opcodes[op].opname);
for ( ; i<10 ; i++)
externs->Printf (" ");
}
@ -141,16 +141,22 @@ static void PR_PrintStatement (progfuncs_t *progfuncs, int statementnum)
#define TYPEHINT(a) NULL
#endif
if (op == OP_IF_F || op == OP_IFNOT_F)
if (op == OP_IF_F || op == OP_IFNOT_F || op == OP_IF_I || op == OP_IFNOT_I || op == OP_IF_S || op == OP_IFNOT_S)
externs->Printf ("%sbranch %i",PR_GlobalString(progfuncs, arg[0], TYPEHINT(a)),arg[1]);
else if (op == OP_GOTO)
{
externs->Printf ("branch %i",arg[0]);
}
else if (op == OP_BOUNDCHECK)
{
externs->Printf ("%s",PR_GlobalString(progfuncs, arg[0], TYPEHINT(a)));
externs->Printf ("%s",PR_GlobalStringImmediate(progfuncs, arg[1]));
externs->Printf ("%s",PR_GlobalStringImmediate(progfuncs, arg[2]));
}
else if ( (unsigned)(op - OP_STORE_F) < 6)
{
externs->Printf ("%s",PR_GlobalString(progfuncs, arg[0], TYPEHINT(a)));
externs->Printf ("%s", PR_GlobalStringNoContents(progfuncs, arg[1]));
externs->Printf ("%s",PR_GlobalStringNoContents(progfuncs, arg[1]));
}
else
{
@ -159,7 +165,7 @@ static void PR_PrintStatement (progfuncs_t *progfuncs, int statementnum)
if (arg[1])
externs->Printf ("%s",PR_GlobalString(progfuncs, arg[1], TYPEHINT(b)));
if (arg[2])
externs->Printf ("%s", PR_GlobalStringNoContents(progfuncs, arg[2]));
externs->Printf ("%s",PR_GlobalStringNoContents(progfuncs, arg[2]));
}
externs->Printf ("\n");
}
@ -1354,7 +1360,10 @@ static const char *lastfile = NULL;
{
PR_PrintStatement(progfuncs, statement);
if (fatal)
{
progfuncs->funcs.debug_trace = DEBUG_TRACE_ABORTERROR;
progfuncs->funcs.parms->Abort ("%s", fault?fault:"Debugger Abort");
}
return statement;
}

View file

@ -167,12 +167,12 @@ typedef struct prinst_s
#define MAX_STACK_DEPTH 1024 //insanely high value requried for xonotic.
prstack_t pr_stack[MAX_STACK_DEPTH];
int pr_depth;
int spushed;
//locals
#define LOCALSTACK_SIZE 16384
int localstack[LOCALSTACK_SIZE];
#define LOCALSTACK_SIZE 65536 //in words
int *localstack;
int localstack_used;
int spushed; //extra
//step-by-step debug state
int debugstatement;
@ -557,6 +557,7 @@ const char *ASMCALL PR_StringToNative (pubprogfuncs_t *inst, string_t str);
char *PR_GlobalString (progfuncs_t *progfuncs, int ofs, struct QCC_type_s **typehint);
char *PR_GlobalStringNoContents (progfuncs_t *progfuncs, int ofs);
char *PR_GlobalStringImmediate (progfuncs_t *progfuncs, int ofs);
pbool CompileFile(progfuncs_t *progfuncs, const char *filename);

View file

@ -200,6 +200,7 @@ struct pubprogfuncs_s
char *(PDECL *AddString) (pubprogfuncs_t *prinst, const char *val, int minlength, pbool demarkup); //dump a string into the progs memory (for setting globals and whatnot)
void *(PDECL *Tempmem) (pubprogfuncs_t *prinst, int ammount, char *whatfor); //grab some mem for as long as the progs stays loaded
void *(PDECL *AddressableAlloc) (pubprogfuncs_t *progfuncs, unsigned int ammount); /*returns memory within the qc block, use stringtoprogs to get a usable qc pointer/string*/
void *(PDECL *AddressableRealloc) (pubprogfuncs_t *progfuncs, void *oldptr, unsigned int newammount); /*returns memory within the qc block, use stringtoprogs to get a usable qc pointer/string*/
void (PDECL *AddressableFree) (pubprogfuncs_t *progfuncs, void *mem); /*frees a block of addressable memory*/
string_t (PDECL *TempString) (pubprogfuncs_t *prinst, const char *str);
string_t (PDECL *AllocTempString) (pubprogfuncs_t *prinst, char **str, unsigned int len);

View file

@ -42,6 +42,7 @@ typedef unsigned int puint_t;
#define pPRIi64 "I64i"
#define pPRIu64 "I64u"
#define pPRIx64 "I64x"
#define pPRIuSIZE PRIxPTR
#else
#include <inttypes.h>
typedef int64_t pint64_t QC_ALIGN(4);
@ -54,6 +55,7 @@ typedef unsigned int puint_t;
#define pPRIi64 PRIi64
#define pPRIu64 PRIu64
#define pPRIx64 PRIx64
#define pPRIuSIZE PRIxPTR
#endif
#define QCVM_32
#endif

View file

@ -49,6 +49,23 @@ extern progfuncs_t *qccprogfuncs;
#define STRINGIFY(s) STRINGIFY2(s)
#endif
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
#define FTE_DEPRECATED __attribute__((__deprecated__)) //no idea about the actual gcc version
#if defined(_WIN32)
#include <stdio.h>
#ifdef __MINGW_PRINTF_FORMAT
#define LIKEPRINTF(x) __attribute__((format(__MINGW_PRINTF_FORMAT,x,x+1)))
#else
#define LIKEPRINTF(x) __attribute__((format(ms_printf,x,x+1)))
#endif
#else
#define LIKEPRINTF(x) __attribute__((format(printf,x,x+1)))
#endif
#endif
#ifndef LIKEPRINTF
#define LIKEPRINTF(x)
#endif
void *qccHunkAlloc(size_t mem);
void qccClearHunk(void);
@ -429,6 +446,7 @@ typedef struct QCC_def_s
int refcount; //if 0, temp can be reused. tracked on globals too in order to catch bugs that would otherwise be a little too obscure.
int timescalled; //part of the opt_stripfunctions optimisation.
const char *unitn; //for static globals.
const char *filen;
int s_filed;
int s_line;
@ -517,7 +535,8 @@ struct QCC_function_s
int code; // first statement. if -1, is a builtin.
dfunction_t *merged; // this function was merged. this is the index to use to ensure that the parms are sized correctly..
string_t s_filed; // source file with definition
const char *filen;
const char *filen; // full scope, printed for debugging.
const char *unitn; //scope for static variables.
int line;
int line_end;
char *name; //internal name of function
@ -686,9 +705,13 @@ extern pbool flag_allowuninit;
extern pbool flag_cpriority;
extern pbool flag_qcfuncs;
extern pbool flag_embedsrc;
extern pbool flag_noreflection;
extern pbool flag_nopragmafileline;
extern pbool flag_utf8strings;
extern pbool flag_reciprocalmaths;
extern pbool flag_ILP32;
extern pbool flag_undefwordsize;
extern pbool flag_pointerrelocs;
extern pbool opt_overlaptemps;
extern pbool opt_shortenifnots;
@ -771,14 +794,14 @@ void QCC_PR_Expect (const char *string);
pbool QCC_PR_CheckKeyword(int keywordenabled, const char *string);
#endif
pbool QCC_PR_CheckTokenComment(const char *string, char **comment);
NORETURN void VARGS QCC_PR_ParseError (int errortype, const char *error, ...);
pbool VARGS QCC_PR_ParseWarning (int warningtype, const char *error, ...);
pbool VARGS QCC_PR_Warning (int type, const char *file, int line, const char *error, ...);
void VARGS QCC_PR_Note (int type, const char *file, int line, const char *error, ...);
NORETURN void VARGS QCC_PR_ParseError (int errortype, const char *error, ...) LIKEPRINTF(2);
pbool VARGS QCC_PR_ParseWarning (int warningtype, const char *error, ...) LIKEPRINTF(2);
pbool VARGS QCC_PR_Warning (int type, const char *file, int line, const char *error, ...) LIKEPRINTF(4);
void VARGS QCC_PR_Note (int type, const char *file, int line, const char *error, ...) LIKEPRINTF(4);
void QCC_PR_ParsePrintDef (int warningtype, QCC_def_t *def);
void QCC_PR_ParsePrintSRef (int warningtype, QCC_sref_t sref);
NORETURN void VARGS QCC_PR_ParseErrorPrintDef (int errortype, QCC_def_t *def, const char *error, ...);
NORETURN void VARGS QCC_PR_ParseErrorPrintSRef (int errortype, QCC_sref_t sref, const char *error, ...);
NORETURN void VARGS QCC_PR_ParseErrorPrintDef (int errortype, QCC_def_t *def, const char *error, ...) LIKEPRINTF(3);
NORETURN void VARGS QCC_PR_ParseErrorPrintSRef (int errortype, QCC_sref_t sref, const char *error, ...) LIKEPRINTF(3);
QCC_type_t *QCC_PR_MakeThiscall(QCC_type_t *orig, QCC_type_t *thistype);
@ -848,6 +871,7 @@ enum {
WARN_DEPRECACTEDSYNTAX, //triggered when syntax is used that I'm trying to kill
WARN_DEPRECATEDVARIABLE, //triggered from usage of a symbol that someone tried to kill
WARN_MUTEDEPRECATEDVARIABLE, //triggered from usage of a symbol that someone tried to kill (without having been muted).
WARN_OCTAL_IMMEDIATE, // 0400!=400... (not found in
WARN_GMQCC_SPECIFIC, //extension created by gmqcc that conflicts or isn't properly implemented.
WARN_FTE_SPECIFIC, //extension that only FTEQCC will have a clue about.
WARN_EXTENSION_USED, //extension that frikqcc also understands
@ -931,7 +955,6 @@ enum {
ERR_INITIALISEDLOCALFUNCTION,
ERR_NOTDEFINED,
ERR_ARRAYNEEDSSIZE,
ERR_ARRAYNEEDSBRACES,
ERR_TOOMANYINITIALISERS,
ERR_TYPEINVALIDINSTRUCT,
ERR_NOSHAREDLOCALS,
@ -1029,6 +1052,7 @@ extern compiler_flag_t compiler_flag[];
extern unsigned char qccwarningaction[WARN_MAX];
extern jmp_buf pr_parse_abort; // longjump with this on parse error
extern const char *s_unitn; //used to track compilation units, for global statics.
extern const char *s_filen; //name of the file we're currently compiling.
extern QCC_string_t s_filed; //name of the file we're currently compiling, as seen by whoever reads the .dat
extern int pr_source_line;
@ -1046,6 +1070,8 @@ void *QCC_PR_Malloc (int size);
#define OFS_PARM4 16
#define RESERVED_OFS 28
#define VMWORDSIZE 4
extern struct QCC_function_s *pr_scope;
extern int pr_error_count, pr_warning_count;
@ -1272,8 +1298,8 @@ typedef struct qcc_cachedsourcefile_s vfile_t;
void QCC_CloseAllVFiles(void);
vfile_t *QCC_FindVFile(const char *name);
vfile_t *QCC_AddVFile(const char *name, void *data, size_t size);
void QCC_CatVFile(vfile_t *, const char *fmt, ...);
void QCC_InsertVFile(vfile_t *, size_t pos, const char *fmt, ...);
void QCC_CatVFile(vfile_t *, const char *fmt, ...) LIKEPRINTF(2);
void QCC_InsertVFile(vfile_t *, size_t pos, const char *fmt, ...) LIKEPRINTF(3);
char *ReadProgsCopyright(char *buf, size_t bufsize);
//void *QCC_ReadFile(const char *fname, unsigned char *(*buf_get)(void *ctx, size_t len), void *buf_ctx, size_t *out_size, pbool issourcefile);

View file

@ -1270,7 +1270,7 @@ long QCC_LoadFile (char *filename, void **bufferptr)
else if (!mem[check])
{
if (!warned)
QCC_PR_Warning(WARN_UNEXPECTEDPUNCT, filename, line, "file contains null bytes %u/%u", check, len);
QCC_PR_Warning(WARN_UNEXPECTEDPUNCT, filename, line, "file contains null bytes %u/%"pPRIuSIZE, check, len);
warned = true;
//fixme: insert modified-utf-8 nulls instead.
mem[check] = ' ';

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -409,7 +409,7 @@ compiler_flag_t compiler_flag[] = {
{&opt_logicops, FLAG_MIDCOMPILE,"lo", "Logic ops", "This changes the behaviour of your code. It generates additional if operations to early-out in if statements. With this flag, the line if (0 && somefunction()) will never call the function. It can thus be considered an optimisation. However, due to the change of behaviour, it is not considered so by fteqcc. Note that due to inprecisions with floats, this flag can cause runaway loop errors within the player walk and run functions (without iffloat also enabled). This code is advised:\nplayer_stand1:\n if (self.velocity_x || self.velocity_y)\nplayer_run\n if (!(self.velocity_x || self.velocity_y))"},
{&flag_msvcstyle, FLAG_MIDCOMPILE,"msvcstyle", "MSVC-style errors", "Generates warning and error messages in a format that msvc understands, to facilitate ide integration."},
{&flag_debugmacros, FLAG_MIDCOMPILE,"debugmacros", "Verbose Macro Expansion", "Print out the contents of macros that are expanded. This can help look inside macros that are expanded and is especially handy if people are using preprocessor hacks."},
{&flag_filetimes, 0, "filetimes", "Check Filetimes", "Recompiles the progs only if the file times are modified."},
{&flag_filetimes, hideflag, "filetimes", "Check Filetimes", "Recompiles the progs only if the file times are modified."},
{&flag_fasttrackarrays, FLAG_MIDCOMPILE,"fastarrays", "fast arrays where possible", "Generates extra instructions inside array handling functions to detect engine and use extension opcodes only in supporting engines.\nAdds a global which is set by the engine if the engine supports the extra opcodes. Note that this applies to all arrays or none."},
{&flag_assume_integer, FLAG_MIDCOMPILE,"assumeint", "Assume Integers", "Numerical constants are assumed to be integers, instead of floats."},
{&pr_subscopedlocals, FLAG_MIDCOMPILE,"subscope", "Subscoped Locals", "Restrict the scope of locals to the block they are actually defined within, as in C."},
@ -427,9 +427,12 @@ compiler_flag_t compiler_flag[] = {
// {&flag_lno, hidedefaultflag,"lno", "Gen Debugging Info", "Writes debugging info."},
{&flag_utf8strings, FLAG_MIDCOMPILE,"utf8", "Unicode", "String immediates will use utf-8 encoding, instead of quake's encoding."},
{&flag_reciprocalmaths, FLAG_MIDCOMPILE,"reciprocal-math","Reciprocal Maths", "Optimise x/const as x*(1/const)."},
{&flag_ILP32, FLAG_MIDCOMPILE,"ILP32", "ILP32 Data Model", "Restricts the size of `long` to 32bits, consistent with pointers."},
{&flag_undefwordsize, hideflag, "undefwordsize","Undefined Word Size", "Do not make assumptions about pointer types and word sizes. Block functionality that depends upon specific word sizes. Changed as part of target."},
{&flag_pointerrelocs, hideflag, "pointerrelocs","Initialised Pointers", "Allow pointer types to be preinitialised at compile time, both at global scope and optimising local scope a little."},
{&flag_noreflection, FLAG_MIDCOMPILE,"omitinternals","Omit Reflection Info", "Keeps internal symbols private (equivelent to unix's hidden visibility). This has the effect of reducing filesize, thwarting debuggers, and breaking saved games. This allows you to use arrays without massively bloating the size of your progs.\nWARNING: The bit about breaking saved games was NOT a joke, but does not apply to menuqc or csqc. It also interferes with FTE_MULTIPROGS."},
{&flag_embedsrc, FLAG_MIDCOMPILE,"embedsrc", "Embed Sources", "Write the sourcecode into the output file. The resulting .dat can be opened as a standard zip archive (or by fteqccgui).\nGood for GPL compliance!"},
// {&flag_noreflection, FLAG_MIDCOMPILE,"omitinternals","Omit Reflection Info", "Keeps internal symbols private (equivelent to unix's hidden visibility). This has the effect of reducing filesize, thwarting debuggers, and breaking saved games. This allows you to use arrays without massively bloating the size of your progs.\nWARNING: The bit about breaking saved games was NOT a joke, but does not apply to menuqc or csqc. It also interferes with FTE_MULTIPROGS."},
{&flag_dumpfilenames, FLAG_MIDCOMPILE,"dumpfilenames","Write a .lst file", "Writes a .lst file which contains a list of all file names that we can detect from the qc. This file list can then be passed into external compression tools."},
{&flag_dumpfields, FLAG_MIDCOMPILE,"dumpfields", "Write a .fld file", "Writes a .fld file that shows which fields are defined, along with their offsets etc, for weird debugging."},
{&flag_dumpsymbols, FLAG_MIDCOMPILE,"dumpsymbols", "Write a .sym file", "Writes a .sym file alongside the dat which contains a list of all global symbols defined in the code (before stripping)"},
@ -1525,7 +1528,21 @@ static void QCC_FinaliseDef(QCC_def_t *def)
{
def->reloc->used = true;
QCC_FinaliseDef(def->reloc);
qcc_pr_globals[def->ofs]._int += def->reloc->ofs;
if (def->type->type == ev_function/*misordered inits/copies*/ || def->type->type == ev_integer/*dp-style global index*/)
qcc_pr_globals[def->ofs]._int += qcc_pr_globals[def->reloc->ofs]._int;
else if (def->type->type == ev_pointer/*signal to the engine to fix up the offset*/)
{
if (qcc_pr_globals[def->ofs]._int & 0x80000000)
QCC_Error(ERR_INTERNAL, "dupe reloc, type... %s", def->type->name);
else if (flag_undefwordsize)
QCC_PR_ParseWarning(ERR_BADEXTENSION, "pointer relocs are disabled for this target.");
qcc_pr_globals[def->ofs]._int += def->reloc->ofs;
qcc_pr_globals[def->ofs]._int *= VMWORDSIZE;
qcc_pr_globals[def->ofs]._int |= 0x80000000;
}
else
QCC_Error(ERR_INTERNAL, "unknown reloc type... %s", def->type->name);
}
#ifdef DEBUG_DUMP_GLOBALMAP
@ -1777,7 +1794,12 @@ static pbool QCC_WriteData (int crc)
if (i < numstatements)
bigjumps = QCC_FunctionForStatement(i);
QCC_PR_CRCMessages(crc);
if (!def)
{
QCC_PR_Warning(WARN_SYSTEMCRC, NULL, 0, "no end_sys_fields defined. system headers missing.");
}
else
QCC_PR_CRCMessages(crc);
switch (qcc_targetformat)
{
case QCF_HEXEN2:
@ -1865,10 +1887,10 @@ static pbool QCC_WriteData (int crc)
if (compressoutput) progs.blockscompressed |=128; //types
//include a type block?
//types = debugtarget;
if (types && sizeof(char *) != sizeof(string_t))
// if (types && sizeof(char *) != sizeof(string_t))
{
//qcc_typeinfo_t has a char* inside it, which changes size
externs->Printf("AMD64 builds cannot write typeinfo structures\n");
// externs->Printf("64bit builds cannot write typeinfo structures\n");
types = false;
}
@ -2198,7 +2220,11 @@ static pbool QCC_WriteData (int crc)
QCC_GenerateFieldDefs(def, def->name, 0, def->type->aux_type);
continue;
}
else if ((def->scope||def->constant) && (def->type->type != ev_string || (strncmp(def->name, "dotranslate_", 12) && opt_constant_names_strings)))
else if (def->type->type == ev_pointer && (def->symboldata[0]._int & 0x80000000))
def->name = ""; //reloc, can't strip it (engine needs to fix em up), but can clear its name.
else if (def->scope && !def->scope->privatelocals && !def->isstatic)
continue; //def is a local, which got shared and should be 0...
else if ((def->scope||def->constant||flag_noreflection) && (def->type->type != ev_string || (strncmp(def->name, "dotranslate_", 12) && opt_constant_names_strings)))
{
if (opt_constant_names)
{
@ -2209,9 +2235,11 @@ static pbool QCC_WriteData (int crc)
#ifdef DEBUG_DUMP
if (def->scope)
externs->Printf("code: %s:%i: strip local %s %s@%i;\n", def->filen, def->s_line, def->type->name, def->name, def->ofs);
externs->Printf("code: %s:%i: strip local %s %s @%i;\n", def->filen, def->s_line, def->type->name, def->name, def->ofs);
else if (def->constant)
externs->Printf("code: %s:%i: strip const %s %s@%i;\n", def->filen, def->s_line, def->type->name, def->name, def->ofs);
externs->Printf("code: %s:%i: strip const %s %s @%i;\n", def->filen, def->s_line, def->type->name, def->name, def->ofs);
else
externs->Printf("code: %s:%i: strip globl %s %s @%i;\n", def->filen, def->s_line, def->type->name, def->name, def->ofs);
#endif
continue;
}
@ -2334,7 +2362,7 @@ static pbool QCC_WriteData (int crc)
for (i = 0; i < numsounds; i++)
{
if (!precache_sound[i].used)
dupewarncount+=QCC_PR_Warning(WARN_EXTRAPRECACHE, precache_sound[i].filename, precache_sound[i].fileline, (dupewarncount>10&&verbose < VERBOSE_STANDARD)?NULL:"Sound \"%s\" was precached but not directly used", precache_sound[i].name, dupewarncount?"":" (annotate the usage with the used_sound intrinsic to silence this warning)");
dupewarncount+=QCC_PR_Warning(WARN_EXTRAPRECACHE, precache_sound[i].filename, precache_sound[i].fileline, (dupewarncount>10&&verbose < VERBOSE_STANDARD)?NULL:"Sound \"%s\" was precached but not directly used%s", precache_sound[i].name, dupewarncount?"":" (annotate the usage with the used_sound intrinsic to silence this warning)");
else if (!precache_sound[i].block)
dupewarncount+=QCC_PR_Warning(WARN_NOTPRECACHED, precache_sound[i].filename, precache_sound[i].fileline, (dupewarncount>10&&verbose < VERBOSE_STANDARD)?NULL:"Sound \"%s\" was used but not directly precached", precache_sound[i].name);
}
@ -3720,7 +3748,7 @@ static int QCC_PR_FinishCompilation (void)
{
if (!externokay)
{
QCC_PR_Warning(ERR_NOFUNC, d->filen, d->s_line, "extern is not supported with this target format",d->name);
QCC_PR_Warning(ERR_NOFUNC, d->filen, d->s_line, "extern is not supported with this target format");
QCC_PR_ParsePrintDef(ERR_NOFUNC, d);
errors = true;
}
@ -3751,7 +3779,7 @@ static int QCC_PR_FinishCompilation (void)
continue;
}
}
if (d->unused)
if (d->unused && !d->used)
{
d->initialized = 1;
continue;
@ -4647,20 +4675,22 @@ static void QCC_PR_CommandLinePrecompilerOptions (void)
keyword_double = keyword_long = keyword_short = keyword_char = keyword_signed = keyword_unsigned = true;
keyword_thinktime = keyword_until = keyword_loop = false;
flag_ILP32 = true; //C code generally expects intptr_t==size_t==long, we'll get better compat if we don't give it surprises.
opt_logicops = true; //early out like C.
flag_assumevar = true; //const only if explicitly const.
pr_subscopedlocals = true; //locals shadow other locals rather than being the same one.
flag_cpriority = true; //fiddle with operator precedence.
flag_assume_integer = true; //unqualified numeric constants are assumed to be ints, consistent with C.
flag_assume_double = true; //and any immediates with a decimal points are assumed to be doubles, consistent with C.
flag_qcfuncs = false;
flag_macroinstrings = false;
flag_qcfuncs = false; //there's a few parsing quirks where our attempt to parse qc functions will misparse valid C.
flag_macroinstrings = false;//hacky preqcc hack.
qccwarningaction[WARN_UNINITIALIZED] = WA_WARN; //C doesn't like that, might as well warn here too.
qccwarningaction[WARN_TOOMANYPARAMS] = WA_ERROR; //too many args to function is weeeeird.
qccwarningaction[WARN_TOOFEWPARAMS] = WA_ERROR; //missing args should be fatal.
qccwarningaction[WARN_ASSIGNMENTTOCONSTANT] = WA_ERROR; //const is const. at least its not const by default.
qccwarningaction[WARN_SAMENAMEASGLOBAL] = WA_IGNORE; //shadowing of globals.
qccwarningaction[WARN_OCTAL_IMMEDIATE] = WA_IGNORE; //0400!=400 is normal for C code.
if (!stricmp(myargv[i]+5, "c++"))
{
@ -4746,6 +4776,7 @@ static void QCC_PR_CommandLinePrecompilerOptions (void)
flag_boundchecks = false; //gmqcc doesn't support dynamic bound checks, so xonotic is buggy shite. we don't want to generate code that will crash.
flag_macroinstrings = false;
flag_reciprocalmaths = true; //optimise x/y to x*(1/y) in constants.
flag_undefwordsize = true; //assume we're targetting DP and go into lame mode.
opt_logicops = true;
//we have to disable some of these warnings, because xonotic insists on using -Werror. use -Wextra to override.
@ -4758,6 +4789,7 @@ static void QCC_PR_CommandLinePrecompilerOptions (void)
qccwarningaction[WARN_IFSTRING_USED] = WA_IGNORE; //and many people would argue that this was a feature rather than a bug
qccwarningaction[WARN_UNINITIALIZED] = WA_IGNORE; //all locals get 0-initialised anyway, and our checks are not quite up to scratch.
qccwarningaction[WARN_GMQCC_SPECIFIC] = WA_IGNORE; //we shouldn't warn about gmqcc syntax when we're trying to be compatible with it. there's always -Wextra.
qccwarningaction[WARN_OCTAL_IMMEDIATE] = WA_IGNORE; //we shouldn't warn about gmqcc syntax when we're trying to be compatible with it. there's always -Wextra.
qccwarningaction[WARN_SYSTEMCRC] = WA_IGNORE; //lameness
qccwarningaction[WARN_SYSTEMCRC2] = WA_IGNORE; //extra lameness
qccwarningaction[WARN_ARGUMENTCHECK] = WA_IGNORE; //gmqcc is often used on DP mods, and DP is just too horrible to fix its problems. Also there's a good chance its using some undocumented/new thing.
@ -5321,7 +5353,7 @@ pbool QCC_main (int argc, const char **argv) //as part of the quake engine
pHash_Add = &Hash_Add;
pHash_RemoveData = &Hash_RemoveData;
MAX_REGS = 1<<17;
MAX_REGS = 1<<19;
MAX_STRINGS = 1<<21;
MAX_GLOBALS = 1<<17;
MAX_FIELDS = 1<<13;
@ -5803,7 +5835,7 @@ void QCC_ContinueCompile(void)
if(setjmp(pr_parse_abort))
{
if (++pr_error_count > MAX_ERRORS)
QCC_Error (ERR_PARSEERRORS, "Errors have occured\n");
QCC_Error (ERR_PARSEERRORS, "%i errors have occured\n", pr_error_count);
return; //just try move onto the next file, gather errors.
}
else
@ -5849,7 +5881,7 @@ void QCC_ContinueCompile(void)
QCC_LoadFile (qccmfilename, (void *)&qccmsrc2);
if (!QCC_PR_CompileFile (qccmsrc2, qccmfilename) )
QCC_Error (ERR_PARSEERRORS, "Errors have occured\n");
QCC_Error (ERR_PARSEERRORS, "%i errors have occured\n", pr_error_count);
*/
}
void QCC_FinishCompile(void)
@ -6026,7 +6058,7 @@ void new_QCC_ContinueCompile(void)
{
// if (pr_error_count != 0)
{
QCC_Error (ERR_PARSEERRORS, "Errors have occured");
QCC_Error (ERR_PARSEERRORS, "%i errors have occured\n", pr_error_count);
return;
}
QCC_PR_SkipToSemicolon ();
@ -6037,7 +6069,7 @@ void new_QCC_ContinueCompile(void)
if (pr_token_type == tt_eof)
{
if (pr_error_count)
QCC_Error (ERR_PARSEERRORS, "Errors have occured");
QCC_Error (ERR_PARSEERRORS, "%i errors have occured\n", pr_error_count);
if (autoprototype && !parseonly)
{

View file

@ -13,6 +13,7 @@
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <math.h>
enum{false,true};
@ -25,6 +26,93 @@ void PF_puts (pubprogfuncs_t *prinst, struct globalvars_s *gvars)
printf("%s", s);
}
void PF_strcat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
G_INT(OFS_RETURN) = prinst->TempString(prinst, prinst->VarString(prinst, 0));
}
void PF_ftos (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
char temp[64];
sprintf(temp, "%g", G_FLOAT(OFS_PARM0));
G_INT(OFS_RETURN) = prinst->TempString(prinst, temp);
}
void PF_vtos (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
char temp[64];
sprintf(temp, "'%g %g %g'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
G_INT(OFS_RETURN) = prinst->TempString(prinst, temp);
}
void PF_etos (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
char temp[64];
sprintf(temp, "%i", G_INT(OFS_PARM0));
G_INT(OFS_RETURN) = prinst->TempString(prinst, temp);
}
void PF_itos (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
char temp[64];
sprintf(temp, "%x", G_INT(OFS_PARM0));
G_INT(OFS_RETURN) = prinst->TempString(prinst, temp);
}
void PF_ltos (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
char temp[64];
sprintf(temp, "%"PRIx64, G_INT64(OFS_PARM0));
G_INT(OFS_RETURN) = prinst->TempString(prinst, temp);
}
void PF_dtos (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
char temp[64];
sprintf(temp, "%g", G_DOUBLE(OFS_PARM0));
G_INT(OFS_RETURN) = prinst->TempString(prinst, temp);
}
void PF_stof (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
G_FLOAT(OFS_RETURN) = strtod(PR_GetStringOfs(prinst, OFS_PARM0), NULL);
}
void PF_stov (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
sscanf(PR_GetStringOfs(prinst, OFS_PARM0), " ' %f %f %f ' ",
&G_FLOAT(OFS_RETURN+0),
&G_FLOAT(OFS_RETURN+1),
&G_FLOAT(OFS_RETURN+2));
}
void PF_strcmp (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
if (prinst->callargc >= 3)
G_FLOAT(OFS_RETURN) = strncmp(PR_GetStringOfs(prinst, OFS_PARM0), PR_GetStringOfs(prinst, OFS_PARM1), G_FLOAT(OFS_PARM2));
else
G_FLOAT(OFS_RETURN) = strcmp(PR_GetStringOfs(prinst, OFS_PARM0), PR_GetStringOfs(prinst, OFS_PARM1));
}
void PF_vlen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
float *v = G_VECTOR(OFS_PARM0);
G_FLOAT(OFS_RETURN) = sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
}
void PF_normalize (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
float *v = G_VECTOR(OFS_PARM0);
double l = sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
if (l)
l = 1./l;
else
l = 0;
G_VECTOR(OFS_RETURN)[0] = v[0] * l;
G_VECTOR(OFS_RETURN)[1] = v[1] * l;
G_VECTOR(OFS_RETURN)[2] = v[2] * l;
}
void PF_floor (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
}
void PF_pow (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
}
void PF_sqrt (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
}
void PF_putv (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
@ -391,6 +479,15 @@ void PF_printf (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
printf("%s", outbuf);
}
struct edict_s
{
enum ereftype_e ereftype;
float freetime; // realtime when the object was freed
unsigned int entnum;
unsigned int fieldsize;
pbool readonly; //causes error when QC tries writing to it. (quake's world entity)
void *fields;
};
void PF_spawn (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
struct edict_s *ed;
@ -398,6 +495,22 @@ void PF_spawn (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
pr_globals = PR_globals(prinst, PR_CURRENT);
RETURN_EDICT(prinst, ed);
}
void PF_remove (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
struct edict_s *ed = (void*)G_EDICT(prinst, OFS_PARM0);
if (ed->ereftype == ER_FREE)
{
printf("Tried removing free entity\n");
PR_StackTrace(prinst, false);
return;
}
ED_Free (prinst, (void*)ed);
}
void PF_error(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
PF_puts(prinst, pr_globals);
}
void PF_bad (pubprogfuncs_t *prinst, struct globalvars_s *gvars)
{
@ -407,10 +520,28 @@ void PF_bad (pubprogfuncs_t *prinst, struct globalvars_s *gvars)
builtin_t builtins[] = {
PF_bad,
PF_puts,
PF_ftos,
PF_spawn,
PF_remove,
PF_vtos,
PF_error,
PF_vlen,
PF_etos,
PF_stof,
PF_strcat,
PF_strcmp,
PF_normalize,
PF_sqrt,
PF_floor,
PF_pow,
PF_stov,
PF_itos,
PF_ltos,
PF_dtos,
PF_puts,
PF_putv,
PF_putf,
PF_printf,
PF_spawn
};
@ -483,7 +614,120 @@ pbool Sys_WriteFile (const char *fname, void *data, int len)
return 1;
}
void runtest(const char *progsname)
void ASMCALL StateOp(pubprogfuncs_t *prinst, float var, func_t func)
{ //note: inefficient. stupid globals abuse and not making assumptions about fields
int *selfg = (int*)PR_FindGlobal(prinst, "self", 0, NULL);
struct edict_s *ed = PROG_TO_EDICT(prinst, selfg?*selfg:0);
float *time = (float*)PR_FindGlobal(prinst, "time", 0, NULL);
eval_t *think = prinst->GetEdictFieldValue(prinst, ed, "think", ev_function, NULL);
eval_t *nextthink = prinst->GetEdictFieldValue(prinst, ed, "nextthink", ev_float, NULL);
eval_t *frame = prinst->GetEdictFieldValue(prinst, ed, "frame", ev_float, NULL);
if (time && nextthink)
nextthink->_float = *time+0.1;
if (think)
think->function = func;
if (frame)
frame->_float = var;
}
void ASMCALL CStateOp(pubprogfuncs_t *progs, float first, float last, func_t currentfunc)
{
/*
float min, max;
float step;
float *vars = PROG_TO_WEDICT(progs, *w->g.self)->fields;
float frame = e->v->frame;
// if (progstype == PROG_H2)
// e->v->nextthink = *w->g.time+0.05;
// else
e->v->nextthink = *w->g.time+0.1;
e->v->think = currentfunc;
if (csqcg.cycle_wrapped)
*csqcg.cycle_wrapped = false;
if (first > last)
{ //going backwards
min = last;
max = first;
step = -1.0;
}
else
{ //forwards
min = first;
max = last;
step = 1.0;
}
if (frame < min || frame > max)
frame = first; //started out of range, must have been a different animation
else
{
frame += step;
if (frame < min || frame > max)
{ //became out of range, must have wrapped
if (csqcg.cycle_wrapped)
*csqcg.cycle_wrapped = true;
frame = first;
}
}
e->v->frame = frame;
*/
}
static void ASMCALL CWStateOp (pubprogfuncs_t *prinst, float first, float last, func_t currentfunc)
{
/*
float min, max;
float step;
world_t *w = prinst->parms->user;
wedict_t *e = PROG_TO_WEDICT(prinst, *w->g.self);
float frame = e->v->weaponframe;
e->v->nextthink = *w->g.time+0.1;
e->v->think = currentfunc;
if (csqcg.cycle_wrapped)
*csqcg.cycle_wrapped = false;
if (first > last)
{ //going backwards
min = last;
max = first;
step = -1.0;
}
else
{ //forwards
min = first;
max = last;
step = 1.0;
}
if (frame < min || frame > max)
frame = first; //started out of range, must have been a different animation
else
{
frame += step;
if (frame < min || frame > max)
{ //became out of range, must have wrapped
if (csqcg.cycle_wrapped)
*csqcg.cycle_wrapped = true;
frame = first;
}
}
e->v->weaponframe = frame;
*/
}
void ASMCALL ThinkTimeOp(pubprogfuncs_t *prinst, struct edict_s *ed, float var)
{
float *self = (float*)PR_FindGlobal(prinst, "self", 0, NULL);
float *time = (float*)PR_FindGlobal(prinst, "time", 0, NULL);
int *nextthink = (int*)PR_FindGlobal(prinst, "nextthink", 0, NULL);
float *vars = PROG_TO_EDICT(prinst, self?*self:0)->fields;
if (time && nextthink)
vars[*nextthink] = *time+0.1;
}
void runtest(const char *progsname, const char **args)
{
pubprogfuncs_t *pf;
func_t func;
@ -497,6 +741,10 @@ void runtest(const char *progsname)
ext.FileSize= Sys_FileSize;
ext.Abort = Sys_Abort;
ext.Printf = printf;
ext.stateop = StateOp;
ext.cstateop = CStateOp;
ext.cwstateop = CWStateOp;
ext.thinktimeop = ThinkTimeOp;
ext.numglobalbuiltins = sizeof(builtins)/sizeof(builtins[0]);
ext.globalbuiltins = builtins;
@ -520,15 +768,34 @@ void runtest(const char *progsname)
if (!func)
printf("Couldn't find function\n");
else
{ //feed it some complex args.
void *pr_globals = PR_globals(pf, PR_CURRENT);
int i;
const char *atypes = *args++;
for (i = 0; atypes[i]; i++) switch(atypes[i])
{
case 'f':
G_FLOAT(OFS_PARM0+i*3) = atof(*args++);
break;
case 'v':
sscanf(*args++, " %f %f %f ", &G_VECTOR(OFS_PARM0+i*3)[0], &G_VECTOR(OFS_PARM0+i*3)[1], &G_VECTOR(OFS_PARM0+i*3)[2]);
break;
case 's':
G_INT(OFS_PARM0+i*3) = pf->TempString(pf, *args++);
break;
}
pf->ExecuteProgram(pf, func); //call the function
}
}
pf->Shutdown(pf);
}
//Run a compiler and nothing else.
//Note that this could be done with an autocompile of PR_COMPILEALWAYS.
void compile(int argc, const char **argv)
pbool compile(int argc, const char **argv)
{
pbool success = false;
pubprogfuncs_t *pf;
progparms_t ext;
@ -565,25 +832,44 @@ void compile(int argc, const char **argv)
{
while(pf->ContinueCompile(pf) == 1)
;
success = true;
}
else
printf("compilation failed to start\n");
}
else
printf("no compiler in this qcvm build\n");
pf->Shutdown(pf);
return success;
}
int main(int argc, const char **argv)
{
int i, a=0;
char atypes[9];
const char *args[9] = {atypes};
const char *dat = NULL;
if (argc < 2)
{
printf("Invalid arguments!\nPlease run as, for example:\n%s testprogs.dat -srcfile progs.src\nThe first argument is the name of the progs.dat to run, the remaining arguments are the qcc args to use", argv[0]);
return 0;
}
compile(argc-1, argv+1);
runtest(argv[1]);
for (i = 1; i < argc; i++)
{
if (!strcmp(argv[i], "-float")) {atypes[a] = 'f'; args[++a] = argv[++i];}
else if (!strcmp(argv[i], "-vector")) {atypes[a] = 'v'; args[++a] = argv[++i];}
else if (!strcmp(argv[i], "-string")) {atypes[a] = 's'; args[++a] = argv[++i];}
else if (!strcmp(argv[i], "-srcfile")) {if (!compile(argc-i, argv+i))return EXIT_FAILURE; break;} //compile it, woo. consume the rest of the args, too
else if (!dat && argv[i][0] != '-') {dat = argv[i];}
else {printf("unknown arg %s\n", argv[i]); return EXIT_FAILURE;}
}
atypes[a] = 0;
if (dat)
runtest(dat, args);
else
printf("Nothing to run\n");
return 0;
return EXIT_SUCCESS;
}

View file

@ -12031,6 +12031,7 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
//END EXT_CSQC
{"memalloc", PF_memalloc, 0, 0, 0, 384, D("__variant*(int size)", "Allocate an arbitary block of memory")},
{"memrealloc", PF_memrealloc, 0, 0, 0, 0, D("__variant*(void *oldptr, int newsize)", "Allocate a new block of memory to replace an old one.")},
{"memfree", PF_memfree, 0, 0, 0, 385, D("void(__variant *ptr)", "Frees a block of memory that was allocated with memfree")},
{"memcmp", PF_memcmp, 0, 0, 0, 0, D("int(__variant *dst, __variant *src, int size, optional int dstoffset, int srcoffset)", "Compares two blocks of memory. Returns 0 if equal.")},
{"memcpy", PF_memcpy, 0, 0, 0, 386, D("void(__variant *dst, __variant *src, int size, optional int dstoffset, int srcoffset)", "Copys memory from one location to another")},

View file

@ -1665,8 +1665,9 @@ qboolean SVC_GetChallenge (qboolean respond_dp)
if (!protocols)
{
COM_ParseOut(Cmd_Argv(2), tprot,sizeof(tprot));
COM_ParseOut(com_protocolname.string, oprot,sizeof(oprot));
pname = va("print\nGame mismatch: This is a %s server\n", oprot);
pname = va("print\nGame mismatch: This is a %s server but you are using %s\n", oprot, tprot);
Netchan_OutOfBand(NCF_SERVER, &net_from, strlen(pname), pname);
return false;
}

View file

@ -57,6 +57,7 @@ var Module = {
"showpic touch_weapons.tga weap 80 -80 bm 32 32 +weaponwheel 5\n"
"showpic touch_menu.tga menu -32 0 tr 32 32 togglemenu 10\n"),
*/ },
// autostart: true, //uncomment to start up straight away without asking about files or not. hope your files are okay.
// quiturl: "/", //url to jump to when 'quitting' (otherwise uses history.back).
// arguments:["+alias","f_startup","connect","wss://theservertojoin", "-manifest","default.fmf"], //beware the scheme registration stuff (pwa+js methods).
// manifest: "index.html.fmf", // '-manifest' arg if args are not explicit. also inhibits the #foo.fmf thing.