From d010b5177ed500178d3a40b49788c8093127ecf4 Mon Sep 17 00:00:00 2001 From: havoc Date: Fri, 13 May 2005 19:41:09 +0000 Subject: [PATCH] upgraded both QuakeC VMs to use a table of negative string indices for all dynamic strings, this should make everything work on 64bit systems git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@5278 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_screen.c | 4 +- cl_screen.h | 6 +- cl_video.c | 6 +- cl_video.h | 10 +-- common.c | 2 +- common.h | 2 +- draw.h | 6 +- gl_draw.c | 6 +- host.c | 2 +- host_cmd.c | 11 ++- menu.c | 2 +- pr_cmds.c | 84 ++++++++++---------- pr_edict.c | 195 ++++++++++++++++++++++++++++++++++++----------- progs.h | 15 ++-- progsvm.h | 22 ++++-- prvm_cmds.c | 180 +++++++++++++++++++------------------------ prvm_edict.c | 211 +++++++++++++++++++++++++++++++++++++++------------ server.h | 8 +- sv_main.c | 22 +++--- sv_user.c | 2 +- wad.c | 4 +- wad.h | 2 +- 22 files changed, 505 insertions(+), 297 deletions(-) diff --git a/cl_screen.c b/cl_screen.c index 02632b2c..505366fe 100644 --- a/cl_screen.c +++ b/cl_screen.c @@ -489,7 +489,7 @@ void DrawQ_Clear(void) } static int picelements[6] = {0, 1, 2, 0, 2, 3}; -void DrawQ_Pic(float x, float y, char *picname, float width, float height, float red, float green, float blue, float alpha, int flags) +void DrawQ_Pic(float x, float y, const char *picname, float width, float height, float red, float green, float blue, float alpha, int flags) { DrawQ_SuperPic(x,y,picname,width,height,0,0,red,green,blue,alpha,1,0,red,green,blue,alpha,0,1,red,green,blue,alpha,1,1,red,green,blue,alpha,flags); } @@ -546,7 +546,7 @@ void DrawQ_Fill (float x, float y, float w, float h, float red, float green, flo DrawQ_SuperPic(x,y,NULL,w,h,0,0,red,green,blue,alpha,1,0,red,green,blue,alpha,0,1,red,green,blue,alpha,1,1,red,green,blue,alpha,flags); } -void DrawQ_SuperPic(float x, float y, char *picname, float width, float height, float s1, float t1, float r1, float g1, float b1, float a1, float s2, float t2, float r2, float g2, float b2, float a2, float s3, float t3, float r3, float g3, float b3, float a3, float s4, float t4, float r4, float g4, float b4, float a4, int flags) +void DrawQ_SuperPic(float x, float y, const char *picname, float width, float height, float s1, float t1, float r1, float g1, float b1, float a1, float s2, float t2, float r2, float g2, float b2, float a2, float s3, float t3, float r3, float g3, float b3, float a3, float s4, float t4, float r4, float g4, float b4, float a4, int flags) { float floats[36]; cachepic_t *pic; diff --git a/cl_screen.h b/cl_screen.h index 7f705b6f..d914bfaa 100644 --- a/cl_screen.h +++ b/cl_screen.h @@ -33,7 +33,7 @@ typedef struct drawqueuemesh_s } drawqueuemesh_t; -enum drawqueue_drawflag_e { +enum drawqueue_drawflag_e { DRAWFLAG_NORMAL, DRAWFLAG_ADDITIVE, DRAWFLAG_MODULATE, @@ -44,13 +44,13 @@ DRAWFLAG_NUMFLAGS // clear the draw queue void DrawQ_Clear(void); // draw an image -void DrawQ_Pic(float x, float y, char *picname, float width, float height, float red, float green, float blue, float alpha, int flags); +void DrawQ_Pic(float x, float y, const char *picname, float width, float height, float red, float green, float blue, float alpha, int flags); // draw a text string void DrawQ_String(float x, float y, const char *string, int maxlen, float scalex, float scaley, float red, float green, float blue, float alpha, int flags); // draw a filled rectangle void DrawQ_Fill(float x, float y, float w, float h, float red, float green, float blue, float alpha, int flags); // draw a very fancy pic (per corner texcoord/color control), the order is tl, tr, bl, br -void DrawQ_SuperPic(float x, float y, char *picname, float width, float height, float s1, float t1, float r1, float g1, float b1, float a1, float s2, float t2, float r2, float g2, float b2, float a2, float s3, float t3, float r3, float g3, float b3, float a3, float s4, float t4, float r4, float g4, float b4, float a4, int flags); +void DrawQ_SuperPic(float x, float y, const char *picname, float width, float height, float s1, float t1, float r1, float g1, float b1, float a1, float s2, float t2, float r2, float g2, float b2, float a2, float s3, float t3, float r3, float g3, float b3, float a3, float s4, float t4, float r4, float g4, float b4, float a4, int flags); // draw a triangle mesh void DrawQ_Mesh(drawqueuemesh_t *mesh, int flags); // set the clipping area diff --git a/cl_video.c b/cl_video.c index cac5af69..e7858ac3 100644 --- a/cl_video.c +++ b/cl_video.c @@ -69,7 +69,7 @@ static qboolean WakeVideo( clvideo_t * video ) return true; } -static clvideo_t* OpenVideo( clvideo_t *video, char *filename, char *name, int owner ) +static clvideo_t* OpenVideo( clvideo_t *video, const char *filename, const char *name, int owner ) { strncpy( video->filename, filename, MAX_QPATH ); video->ownertag = owner; @@ -95,7 +95,7 @@ static clvideo_t* OpenVideo( clvideo_t *video, char *filename, char *name, int o return video; } -clvideo_t* CL_OpenVideo( char *filename, char *name, int owner ) +clvideo_t* CL_OpenVideo( const char *filename, const char *name, int owner ) { clvideo_t *video; @@ -107,7 +107,7 @@ clvideo_t* CL_OpenVideo( char *filename, char *name, int owner ) return OpenVideo( video, filename, name, owner ); } -clvideo_t* CL_GetVideo( char *name ) +clvideo_t* CL_GetVideo( const char *name ) { int i; clvideo_t *video; diff --git a/cl_video.h b/cl_video.h index bd706bc5..8439e92c 100644 --- a/cl_video.h +++ b/cl_video.h @@ -36,17 +36,17 @@ typedef struct clvideo_s cachepic_t cpif; // if a video is suspended, it is automatically paused (else we'd still have to process the frames) - + // used to determine whether the video's resources should be freed or not - double lasttime; + double lasttime; // when lasttime - realtime > THRESHOLD, all but the stream is freed - qboolean suspended; + qboolean suspended; char filename[MAX_QPATH]; } clvideo_t; -clvideo_t* CL_OpenVideo( char *filename, char *name, int owner ); -clvideo_t* CL_GetVideo( char *name ); +clvideo_t* CL_OpenVideo( const char *filename, const char *name, int owner ); +clvideo_t* CL_GetVideo( const char *name ); void CL_SetVideoState( clvideo_t *video, clvideostate_t state ); void CL_RestartVideo( clvideo_t *video ); diff --git a/common.c b/common.c index f568a828..0c8dc3fc 100644 --- a/common.c +++ b/common.c @@ -171,7 +171,7 @@ static unsigned short crctable[256] = 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 }; -unsigned short CRC_Block(qbyte *data, int size) +unsigned short CRC_Block(const qbyte *data, int size) { unsigned short crc = CRC_INIT_VALUE; while (size--) diff --git a/common.h b/common.h index 3a73d7ca..8994079a 100644 --- a/common.h +++ b/common.h @@ -53,7 +53,7 @@ void SZ_HexDumpToConsole(const sizebuf_t *buf); void Com_HexDumpToConsole(const qbyte *data, int size); -unsigned short CRC_Block(qbyte *data, int size); +unsigned short CRC_Block(const qbyte *data, int size); //============================================================================ diff --git a/draw.h b/draw.h index 4c507883..61d50af9 100644 --- a/draw.h +++ b/draw.h @@ -39,11 +39,11 @@ typedef struct cachepic_s cachepic_t; void Draw_Init (void); -cachepic_t *Draw_CachePic (char *path, qboolean persistent); +cachepic_t *Draw_CachePic (const char *path, qboolean persistent); // create or update a pic's image -cachepic_t *Draw_NewPic(char *picname, int width, int height, int alpha, qbyte *pixels); +cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, qbyte *pixels); // free the texture memory used by a pic -void Draw_FreePic(char *picname); +void Draw_FreePic(const char *picname); void R_DrawQueue(void); diff --git a/gl_draw.c b/gl_draw.c index f0b1d405..7ae87007 100644 --- a/gl_draw.c +++ b/gl_draw.c @@ -262,7 +262,7 @@ Draw_CachePic ================ */ // FIXME: move this to client somehow -cachepic_t *Draw_CachePic (char *path, qboolean persistent) +cachepic_t *Draw_CachePic (const char *path, qboolean persistent) { int i, crc, hashkey; cachepic_t *pic; @@ -350,7 +350,7 @@ cachepic_t *Draw_CachePic (char *path, qboolean persistent) return pic; } -cachepic_t *Draw_NewPic(char *picname, int width, int height, int alpha, qbyte *pixels) +cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, qbyte *pixels) { int crc, hashkey; cachepic_t *pic; @@ -391,7 +391,7 @@ cachepic_t *Draw_NewPic(char *picname, int width, int height, int alpha, qbyte * return pic; } -void Draw_FreePic(char *picname) +void Draw_FreePic(const char *picname) { int crc; int hashkey; diff --git a/host.c b/host.c index 108db335..b81831af 100644 --- a/host.c +++ b/host.c @@ -424,7 +424,7 @@ void SV_DropClient(qboolean crash) } // remove leaving player from scoreboard - //host_client->edict->v->netname = PR_SetString(host_client->name); + //host_client->edict->v->netname = PR_SetEngineString(host_client->name); //if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors))) // val->_float = 0; //host_client->edict->v->frags = 0; diff --git a/host_cmd.c b/host_cmd.c index 21ad53e6..702d1496 100644 --- a/host_cmd.c +++ b/host_cmd.c @@ -519,7 +519,7 @@ void Host_Savegame_f (void) // write the light styles for (i=0 ; iname to keep it safe strlcpy (host_client->name, newName, sizeof (host_client->name)); - host_client->edict->v->netname = PR_SetString(host_client->name); + host_client->edict->v->netname = PR_SetEngineString(host_client->name); if (strcmp(host_client->old_name, host_client->name)) { if (host_client->spawned) @@ -799,7 +798,7 @@ void Host_Playermodel_f (void) // point the string back at updateclient->name to keep it safe strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel)); if( eval_playermodel ) - GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PR_SetString(host_client->playermodel); + GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PR_SetEngineString(host_client->playermodel); if (strcmp(host_client->old_model, host_client->playermodel)) { if (host_client->spawned) @@ -860,7 +859,7 @@ void Host_Playerskin_f (void) // point the string back at updateclient->name to keep it safe strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin)); if( eval_playerskin ) - GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PR_SetString(host_client->playerskin); + GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PR_SetEngineString(host_client->playerskin); if (strcmp(host_client->old_skin, host_client->playerskin)) { if (host_client->spawned) diff --git a/menu.c b/menu.c index c09d888d..a83f1a1f 100644 --- a/menu.c +++ b/menu.c @@ -2506,7 +2506,7 @@ void M_Menu_Keys_f (void) #define NUMKEYS 5 -void M_FindKeysForCommand (char *command, int *keys) +void M_FindKeysForCommand (const char *command, int *keys) { int count; int j; diff --git a/pr_cmds.c b/pr_cmds.c index 19643ea0..52555c95 100644 --- a/pr_cmds.c +++ b/pr_cmds.c @@ -175,7 +175,7 @@ char *ENGINE_EXTENSIONS = "NEXUIZ_PLAYERSKIN " ; -qboolean checkextension(char *name) +qboolean checkextension(const char *name) { int len; char *e, *start; @@ -370,7 +370,7 @@ void PF_setmodel (void) if (e->e->free) PF_WARNING("setmodel: can not modify free entity\n"); i = SV_ModelIndex(G_STRING(OFS_PARM1), 1); - e->v->model = PR_SetString(sv.model_precache[i]); + e->v->model = PR_SetEngineString(sv.model_precache[i]); e->v->modelindex = i; mod = sv.models[i]; @@ -627,7 +627,7 @@ PF_ambientsound */ void PF_ambientsound (void) { - char *samp; + const char *samp; float *pos; float vol, attenuation; int soundnum, large; @@ -682,7 +682,7 @@ Larger attenuations will drop off. */ void PF_sound (void) { - char *sample; + const char *sample; int channel; edict_t *entity; int volume; @@ -960,7 +960,7 @@ stuffcmd (clientent, value) void PF_stuffcmd (void) { int entnum; - char *str; + const char *str; client_t *old; entnum = G_EDICTNUM(OFS_PARM0); @@ -1109,7 +1109,7 @@ void PF_ftos (void) sprintf(s, "%i", (int)v); else sprintf(s, "%f", v); - G_INT(OFS_RETURN) = PR_SetString(s); + G_INT(OFS_RETURN) = PR_SetEngineString(s); } void PF_fabs (void) @@ -1124,7 +1124,7 @@ void PF_vtos (void) char *s; s = PR_GetTempString(); sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]); - G_INT(OFS_RETURN) = PR_SetString(s); + G_INT(OFS_RETURN) = PR_SetEngineString(s); } void PF_etos (void) @@ -1132,7 +1132,7 @@ void PF_etos (void) char *s; s = PR_GetTempString(); sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0)); - G_INT(OFS_RETURN) = PR_SetString(s); + G_INT(OFS_RETURN) = PR_SetEngineString(s); } void PF_Spawn (void) @@ -1165,7 +1165,7 @@ void PF_Find (void) { int e; int f; - char *s, *t; + const char *s, *t; edict_t *ed; e = G_EDICTNUM(OFS_PARM0); @@ -1230,7 +1230,7 @@ void PF_findchain (void) { int i; int f; - char *s, *t; + const char *s, *t; edict_t *ent, *chain; chain = (edict_t *)sv.edicts; @@ -1349,12 +1349,6 @@ void PF_findchainflags (void) RETURN_EDICT(chain); } -void PR_CheckEmptyString (char *s) -{ - if (s[0] <= ' ') - PF_ERROR("Bad string"); -} - void PF_precache_file (void) { // precache_file is only used to copy files with qcc, it does nothing G_INT(OFS_RETURN) = G_INT(OFS_PARM0); @@ -1490,7 +1484,7 @@ void(float style, string value) lightstyle void PF_lightstyle (void) { int style; - char *val; + const char *val; client_t *client; int j; @@ -1498,7 +1492,7 @@ void PF_lightstyle (void) val = G_STRING(OFS_PARM1); // change the string in sv - sv.lightstyles[style] = val; + strlcpy(sv.lightstyles[style], val, sizeof(sv.lightstyles[style])); // send message to all clients on this server if (sv.state != ss_active) @@ -1946,7 +1940,7 @@ PF_changelevel */ void PF_changelevel (void) { - char *s; + const char *s; // make sure we don't issue two changelevels if (svs.changelevel_issued) @@ -2021,7 +2015,7 @@ void PF_GetLight (void) void PF_registercvar (void) { - char *name, *value; + const char *name, *value; name = G_STRING(OFS_PARM0); value = G_STRING(OFS_PARM1); G_FLOAT(OFS_RETURN) = 0; @@ -2207,7 +2201,7 @@ effect(origin, modelname, startframe, framecount, framerate) void PF_effect (void) { int i; - char *s; + const char *s; s = G_STRING(OFS_PARM1); if (!s || !s[0]) PF_WARNING("effect: no model specified\n"); @@ -2718,7 +2712,7 @@ void PF_getsurfacetexture(void) G_INT(OFS_RETURN) = 0; if (!(surface = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1)))) return; - G_INT(OFS_RETURN) = PR_SetString(surface->texture->name); + G_INT(OFS_RETURN) = PR_SetEngineString(surface->texture->name); } //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438; void PF_getsurfacenearpoint(void) @@ -2822,7 +2816,7 @@ void PF_stof(void) void PF_fopen(void) { int filenum, mode; - char *modestring, *filename; + const char *modestring, *filename; for (filenum = 0;filenum < MAX_PRFILES;filenum++) if (pr_files[filenum] == NULL) break; @@ -2916,7 +2910,7 @@ void PF_fgets(void) if (developer.integer) Con_Printf("fgets: %s\n", string); if (c >= 0 || end) - G_INT(OFS_RETURN) = PR_SetString(string); + G_INT(OFS_RETURN) = PR_SetEngineString(string); else G_INT(OFS_RETURN) = 0; } @@ -2947,7 +2941,7 @@ void PF_fputs(void) //float(string s) strlen = #114; // returns how many characters are in a string void PF_strlen(void) { - char *s; + const char *s; s = G_STRING(OFS_PARM0); if (s) G_FLOAT(OFS_RETURN) = strlen(s); @@ -2960,14 +2954,15 @@ void PF_strcat(void) { char *s = PR_GetTempString(); PF_VarString(0, s, STRINGTEMP_LENGTH); - G_INT(OFS_RETURN) = PR_SetString(s); + G_INT(OFS_RETURN) = PR_SetEngineString(s); } //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring void PF_substring(void) { int i, start, length; - char *s, *string = PR_GetTempString(); + const char *s; + char *string = PR_GetTempString(); s = G_STRING(OFS_PARM0); start = G_FLOAT(OFS_PARM1); length = G_FLOAT(OFS_PARM2); @@ -2977,7 +2972,7 @@ void PF_substring(void) for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++) string[i] = *s; string[i] = 0; - G_INT(OFS_RETURN) = PR_SetString(string); + G_INT(OFS_RETURN) = PR_SetEngineString(string); } //vector(string s) stov = #117; // returns vector value from a string @@ -2991,17 +2986,18 @@ void PF_stov(void) //string(string s) strzone = #118; // makes a copy of a string into the string zone and returns it, this is often used to keep around a tempstring for longer periods of time (tempstrings are replaced often) void PF_strzone(void) { - char *in, *out; + const char *in; + char *out; in = G_STRING(OFS_PARM0); - out = PR_Alloc(strlen(in) + 1); + out = PR_AllocString(strlen(in) + 1); strcpy(out, in); - G_INT(OFS_RETURN) = PR_SetString(out); + G_INT(OFS_RETURN) = PR_SetQCString(out); } //void(string s) strunzone = #119; // removes a copy of a string from the string zone (you can not use that string again or it may crash!!!) void PF_strunzone(void) { - PR_Free(G_STRING(OFS_PARM0)); + PR_FreeString((char *)G_STRING(OFS_PARM0)); } //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client @@ -3058,9 +3054,9 @@ void PF_argv (void) { int token_num = G_FLOAT(OFS_PARM0); if (token_num >= 0 && token_num < num_tokens) - G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]); + G_INT(OFS_RETURN) = PR_SetEngineString(tokens[token_num]); else - G_INT(OFS_RETURN) = PR_SetString(""); + G_INT(OFS_RETURN) = PR_SetEngineString(NULL); } //void(entity e, entity tagentity, string tagname) setattachment = #443; // attachs e to a tag on tagentity (note: use "" to attach to entity origin/angles instead of a tag) @@ -3068,7 +3064,7 @@ void PF_setattachment (void) { edict_t *e = G_EDICT(OFS_PARM0); edict_t *tagentity = G_EDICT(OFS_PARM1); - char *tagname = G_STRING(OFS_PARM2); + const char *tagname = G_STRING(OFS_PARM2); eval_t *v; int modelindex; model_t *model; @@ -3105,7 +3101,7 @@ void PF_setattachment (void) ///////////////////////////////////////// // DP_MD3_TAGINFO extension coded by VorteX -int SV_GetTagIndex (edict_t *e, char *tagname) +int SV_GetTagIndex (edict_t *e, const char *tagname) { int i; model_t *model; @@ -3259,7 +3255,7 @@ int SV_GetTagMatrix (matrix4x4_t *out, edict_t *ent, int tagindex) void PF_gettagindex (void) { edict_t *ent = G_EDICT(OFS_PARM0); - char *tag_name = G_STRING(OFS_PARM1); + const char *tag_name = G_STRING(OFS_PARM1); int modelindex, tag_index; if (ent == sv.edicts) @@ -3345,12 +3341,12 @@ float search_begin(string pattern, float caseinsensitive, float quiet) void PF_search_begin(void) { int handle; - char *pattern; + const char *pattern; int caseinsens, quiet; pattern = G_STRING(OFS_PARM0); - - PR_CheckEmptyString(pattern); + if (!pattern || pattern[0] <= ' ') + PF_ERROR("PF_search_begin: Bad string"); caseinsens = G_FLOAT(OFS_PARM1); quiet = G_FLOAT(OFS_PARM2); @@ -3461,12 +3457,12 @@ void PF_search_getfilename(void) tmp = PR_GetTempString(); strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]); - G_INT(OFS_RETURN) = PR_SetString(tmp); + G_INT(OFS_RETURN) = PR_SetEngineString(tmp); } void PF_cvar_string (void) { - char *str; + const char *str; cvar_t *var; char *tmp; @@ -3478,8 +3474,8 @@ void PF_cvar_string (void) strcpy(tmp, var->string); } else - tmp = ""; - G_INT(OFS_RETURN) = PR_SetString(tmp); + tmp = NULL; + G_INT(OFS_RETURN) = PR_SetEngineString(tmp); } //void(entity clent) dropclient (DP_SV_DROPCLIENT) diff --git a/pr_edict.c b/pr_edict.c index 985fc4db..8b1ef350 100644 --- a/pr_edict.c +++ b/pr_edict.c @@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. dprograms_t *progs; mfunction_t *pr_functions; char *pr_strings; +int pr_stringssize; ddef_t *pr_fielddefs; ddef_t *pr_globaldefs; dstatement_t *pr_statements; @@ -32,6 +33,10 @@ float *pr_globals; // same as pr_global_struct int pr_edict_size; // in bytes int pr_edictareasize; // LordHavoc: in bytes +int pr_maxknownstrings; +int pr_numknownstrings; +const char **pr_knownstrings; + unsigned short pr_crc; mempool_t *serverprogs_mempool; @@ -235,14 +240,14 @@ void ED_ClearEdict (edict_t *e) // set netname/clientcolors back to client values so that // DP_SV_CLIENTNAME and DPV_SV_CLIENTCOLORS will not immediately // reset them - e->v->netname = PR_SetString(svs.clients[num].name); + e->v->netname = PR_SetEngineString(svs.clients[num].name); if ((val = GETEDICTFIELDVALUE(e, eval_clientcolors))) val->_float = svs.clients[num].colors; // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN if( eval_playermodel ) - GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PR_SetString(svs.clients[num].playermodel); + GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PR_SetEngineString(svs.clients[num].playermodel); if( eval_playerskin ) - GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PR_SetString(svs.clients[num].playerskin); + GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PR_SetEngineString(svs.clients[num].playerskin); } } @@ -484,7 +489,7 @@ char *PR_UglyValueString (etype_t type, eval_t *val) { static char line[4096]; int i; - char *s; + const char *s; ddef_t *def; mfunction_t *f; @@ -613,7 +618,7 @@ void ED_Print(edict_t *ed) ddef_t *d; int *v; int i, j; - char *name; + const char *name; int type; char tempstring[8192], tempstring2[260]; // temporary string buffers @@ -687,7 +692,7 @@ void ED_Write (qfile_t *f, edict_t *ed) ddef_t *d; int *v; int i, j; - char *name; + const char *name; int type; FS_Print(f, "{\n"); @@ -817,7 +822,7 @@ void ED_WriteGlobals (qfile_t *f) { ddef_t *def; int i; - char *name; + const char *name; int type; FS_Print(f,"{\n"); @@ -909,40 +914,6 @@ void ED_ParseGlobals (const char *data) //============================================================================ -/* -============= -ED_NewString -============= -*/ -char *ED_NewString (const char *string) -{ - char *new, *new_p; - int i,l; - - l = strlen(string) + 1; - new = PR_Alloc(l); - new_p = new; - - for (i=0 ; i< l ; i++) - { - if (string[i] == '\\' && i < l-1) - { - i++; - if (string[i] == 'n') - *new_p++ = '\n'; - else if (string[i] == 'r') - *new_p++ = '\r'; - else - *new_p++ = '\\'; - } - else - *new_p++ = string[i]; - } - - return new; -} - - /* ============= ED_ParseEval @@ -953,7 +924,8 @@ returns false if error */ qboolean ED_ParseEpair(edict_t *ent, ddef_t *key, const char *s) { - int i; + int i, l; + char *new_p; ddef_t *def; eval_t *val; mfunction_t *func; @@ -965,7 +937,24 @@ qboolean ED_ParseEpair(edict_t *ent, ddef_t *key, const char *s) switch (key->type & ~DEF_SAVEGLOBAL) { case ev_string: - val->string = PR_SetString(ED_NewString(s)); + l = strlen(s) + 1; + new_p = PR_AllocString(l); + val->string = PR_SetQCString(new_p); + for (i = 0;i < l;i++) + { + if (s[i] == '\\' && i < l-1) + { + i++; + if (s[i] == 'n') + *new_p++ = '\n'; + else if (s[i] == 'r') + *new_p++ = '\r'; + else + *new_p++ = s[i]; + } + else + *new_p++ = s[i]; + } break; case ev_float: @@ -1327,7 +1316,19 @@ void PR_LoadProgs (const char *progsname) //pr_functions = (dfunction_t *)((qbyte *)progs + progs->ofs_functions); dfunctions = (dfunction_t *)((qbyte *)progs + progs->ofs_functions); + pr_strings = (char *)progs + progs->ofs_strings; + pr_stringssize = 0; + for (i = 0;i < progs->numstrings;i++) + { + if (progs->ofs_strings + pr_stringssize >= fs_filesize) + Host_Error ("progs.dat strings go past end of file\n"); + pr_stringssize += strlen (pr_strings + pr_stringssize) + 1; + } + pr_numknownstrings = 0; + pr_maxknownstrings = 0; + pr_knownstrings = NULL; + pr_globaldefs = (ddef_t *)((qbyte *)progs + progs->ofs_globaldefs); // we need to expand the fielddefs list to include all the engine fields, @@ -1385,7 +1386,7 @@ void PR_LoadProgs (const char *progsname) { pr_fielddefs[progs->numfielddefs].type = dpfields[i].type; pr_fielddefs[progs->numfielddefs].ofs = progs->entityfields; - pr_fielddefs[progs->numfielddefs].s_name = PR_SetString(dpfields[i].string); + pr_fielddefs[progs->numfielddefs].s_name = PR_SetEngineString(dpfields[i].string); if (pr_fielddefs[progs->numfielddefs].type == ev_vector) progs->entityfields += 3; else @@ -1510,7 +1511,8 @@ void PR_Fields_f (void) { int i, j, ednum, used, usedamount; int *counts; - char tempstring[5000], tempstring2[260], *name; + const char *name; + char tempstring[5000], tempstring2[260]; edict_t *ed; ddef_t *d; int *v; @@ -1756,3 +1758,106 @@ edict_t *PROG_TO_EDICT(int n) } */ +const char *PR_GetString(int num) +{ + if (num >= 0 && num < pr_stringssize) + return pr_strings + num; + else if (num < 0 && num >= -pr_numknownstrings) + { + num = -1 - num; + if (!pr_knownstrings[num]) + Host_Error("PR_GetString: attempt to get string that is already freed\n"); + return pr_knownstrings[num]; + } + else + { + Host_Error("PR_GetString: invalid string offset %i\n", num); + return ""; + } +} + +int PR_SetQCString(const char *s) +{ + int i; + if (!s) + return 0; + if (s >= pr_strings && s <= pr_strings + pr_stringssize) + return s - pr_strings; + for (i = 0;i < pr_numknownstrings;i++) + if (pr_knownstrings[i] == s) + return -1 - i; + Host_Error("PR_SetQCString: unknown string\n"); + return -1 - i; +} + +int PR_SetEngineString(const char *s) +{ + int i; + if (!s) + return 0; + if (s >= pr_strings && s <= pr_strings + pr_stringssize) + Host_Error("PR_SetEngineString: s in pr_strings area\n"); + for (i = 0;i < pr_numknownstrings;i++) + if (pr_knownstrings[i] == s) + return -1 - i; + // new unknown engine string + if (developer.integer >= 3) + Con_Printf("new engine string %p\n", s); + for (i = 0;i < pr_numknownstrings;i++) + if (!pr_knownstrings[i]) + break; + if (i >= pr_numknownstrings) + { + if (i >= pr_maxknownstrings) + { + const char **oldstrings = pr_knownstrings; + pr_maxknownstrings += 128; + pr_knownstrings = PR_Alloc(pr_maxknownstrings * sizeof(char *)); + if (pr_numknownstrings) + memcpy(pr_knownstrings, oldstrings, pr_numknownstrings * sizeof(char *)); + } + pr_numknownstrings++; + } + pr_knownstrings[i] = s; + return -1 - i; +} + +char *PR_AllocString(int bufferlength) +{ + int i; + if (!bufferlength) + return 0; + for (i = 0;i < pr_numknownstrings;i++) + if (!pr_knownstrings[i]) + break; + if (i >= pr_numknownstrings) + { + if (i >= pr_maxknownstrings) + { + const char **oldstrings = pr_knownstrings; + pr_maxknownstrings += 128; + pr_knownstrings = PR_Alloc(pr_maxknownstrings * sizeof(char *)); + if (pr_numknownstrings) + memcpy(pr_knownstrings, oldstrings, pr_numknownstrings * sizeof(char *)); + } + pr_numknownstrings++; + } + return (char *)(pr_knownstrings[i] = PR_Alloc(bufferlength)); +} + +void PR_FreeString(char *s) +{ + int i; + if (!s) + Host_Error("PR_FreeString: attempt to free a NULL string\n"); + if (s >= pr_strings && s <= pr_strings + pr_stringssize) + Host_Error("PR_FreeString: attempt to free a constant string\n"); + for (i = 0;i < pr_numknownstrings;i++) + if (pr_knownstrings[i] == s) + break; + if (i == pr_numknownstrings) + Host_Error("PR_FreeString: attempt to free a non-existent or already freed string\n"); + PR_Free((char *)pr_knownstrings[i]); + pr_knownstrings[i] = NULL; +} + diff --git a/progs.h b/progs.h index b39f355e..e4ea1410 100644 --- a/progs.h +++ b/progs.h @@ -147,6 +147,7 @@ extern mfunction_t *SV_ParseClientCommandQC; extern dprograms_t *progs; extern mfunction_t *pr_functions; extern char *pr_strings; +extern int pr_stringssize; extern ddef_t *pr_globaldefs; extern ddef_t *pr_fielddefs; extern dstatement_t *pr_statements; @@ -156,6 +157,10 @@ extern float *pr_globals; // same as pr_global_struct extern int pr_edict_size; // in bytes extern int pr_edictareasize; // LordHavoc: for bounds checking +extern int pr_maxknownstrings; +extern int pr_numknownstrings; +extern const char **pr_knownstrings; + //============================================================================ void PR_Init (void); @@ -182,9 +187,6 @@ edict_t *ED_Alloc (void); void ED_Free (edict_t *ed); void ED_ClearEdict (edict_t *e); -char *ED_NewString (const char *string); -// returns a copy of the string allocated from the server's string heap - void ED_Print(edict_t *ed); void ED_Write (qfile_t *f, edict_t *ed); const char *ED_ParseEdict (const char *data, edict_t *ent); @@ -244,8 +246,11 @@ void PR_Execute_ProgsLoaded(void); void ED_PrintEdicts (void); void ED_PrintNum (int ent); -#define PR_GetString(num) (pr_strings + num) -#define PR_SetString(s) ((s) != NULL ? (int) (s - pr_strings) : 0) +const char *PR_GetString(int num); +int PR_SetQCString(const char *s); +int PR_SetEngineString(const char *s); +char *PR_AllocString(int bufferlength); +void PR_FreeString(char *s); #endif diff --git a/progsvm.h b/progsvm.h index 744c8f57..0ea2072d 100644 --- a/progsvm.h +++ b/progsvm.h @@ -242,6 +242,7 @@ typedef struct vm_prog_s dprograms_t *progs; mfunction_t *functions; char *strings; + int stringssize; ddef_t *fielddefs; ddef_t *globaldefs; dstatement_t *statements; @@ -250,6 +251,10 @@ typedef struct vm_prog_s int edict_size; // in bytes int edictareasize; // LordHavoc: in bytes (for bound checking) + int maxknownstrings; + int numknownstrings; + const char **knownstrings; + // all memory allocations related to this vm_prog (code, edicts, strings) mempool_t *progs_mempool; @@ -379,6 +384,13 @@ void PRVM_Init (void); void PRVM_ExecuteProgram (func_t fnum, const char *errormessage); void PRVM_LoadProgs (const char *filename, int numrequiredfunc, char **required_func); +#define PRVM_Alloc(buffersize) _PRVM_Alloc(buffersize, __FILE__, __LINE__) +#define PRVM_Free(buffer) _PRVM_Free(buffer, __FILE__, __LINE__) +#define PRVM_FreeAll() _PRVM_FreeAll(__FILE__, __LINE__) +void *_PRVM_Alloc (size_t buffersize, const char *filename, int fileline); +void _PRVM_Free (void *buffer, const char *filename, int fileline); +void _PRVM_FreeAll (const char *filename, int fileline); + void PRVM_Profile_f (void); void PRVM_PrintState(void); @@ -389,9 +401,6 @@ prvm_edict_t *PRVM_ED_Alloc (void); void PRVM_ED_Free (prvm_edict_t *ed); void PRVM_ED_ClearEdict (prvm_edict_t *e); -char *PRVM_ED_NewString (const char *string); -// returns a copy of the string allocated from the server's string heap - void PRVM_ED_Print(prvm_edict_t *ed); void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed); const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent); @@ -439,8 +448,11 @@ void PRVM_Init_Exec(void); void PRVM_ED_PrintEdicts_f (void); void PRVM_ED_PrintNum (int ent); -#define PRVM_GetString(num) (prog->strings + num) -#define PRVM_SetString(s) ((s) != NULL ? (int) (s - prog->strings) : 0) +const char *PRVM_GetString(int num); +int PRVM_SetQCString(const char *s); +int PRVM_SetEngineString(const char *s); +char *PRVM_AllocString(int bufferlength); +void PRVM_FreeString(char *s); //============================================================================ diff --git a/prvm_cmds.c b/prvm_cmds.c index 4ebdc3b3..b09b92a2 100644 --- a/prvm_cmds.c +++ b/prvm_cmds.c @@ -190,8 +190,6 @@ float getserverlistindexforkey(string key) #define VM_RETURN_EDICT(e) (((int *)prog->globals)[OFS_RETURN] = PRVM_EDICT_TO_PROG(e)) -#define VM_STRINGS_MEMPOOL vm_strings_mempool[PRVM_GetProgNr()] - #define e10 0,0,0,0,0,0,0,0,0,0 #define e100 e10,e10,e10,e10,e10,e10,e10,e10,e10,e10 #define e1000 e100,e100,e100,e100,e100,e100,e100,e100,e100,e100 @@ -199,9 +197,6 @@ float getserverlistindexforkey(string key) //============================================================================ // Common -// string zone mempool -mempool_t *vm_strings_mempool[PRVM_MAXPROGS]; - // temp string handling // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print #define VM_STRINGTEMP_BUFFERS 16 @@ -231,7 +226,7 @@ static char *VM_GetTempString(void) return s; } -void VM_CheckEmptyString (char *s) +void VM_CheckEmptyString (const char *s) { if (s[0] <= ' ') PRVM_ERROR ("%s: Bad string", PRVM_NAME); @@ -267,7 +262,7 @@ checkextension(extensionname) */ // kind of helper function -static qboolean checkextension(char *name) +static qboolean checkextension(const char *name) { int len; char *e, *start; @@ -641,7 +636,7 @@ localsound(string sample) */ void VM_localsound(void) { - char *s; + const char *s; VM_SAFEPARMCOUNT(1,VM_localsound); @@ -711,7 +706,8 @@ const string str_cvar (string) */ void VM_str_cvar(void) { - char *out, *name; + char *out; + const char *name; const char *cvar_string; VM_SAFEPARMCOUNT(1,VM_str_cvar); @@ -728,7 +724,7 @@ void VM_str_cvar(void) strcpy(out, cvar_string); - PRVM_G_INT(OFS_RETURN) = PRVM_SetString(out); + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(out); } /* @@ -784,7 +780,7 @@ void VM_ftos (void) sprintf(s, "%i", (int)v); else sprintf(s, "%f", v); - PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s); + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(s); } /* @@ -821,7 +817,7 @@ void VM_vtos (void) s = VM_GetTempString(); sprintf (s, "'%5.1f %5.1f %5.1f'", PRVM_G_VECTOR(OFS_PARM0)[0], PRVM_G_VECTOR(OFS_PARM0)[1], PRVM_G_VECTOR(OFS_PARM0)[2]); - PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s); + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(s); } /* @@ -840,7 +836,7 @@ void VM_etos (void) s = VM_GetTempString(); sprintf (s, "entity %i", PRVM_G_EDICTNUM(OFS_PARM0)); - PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s); + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(s); } /* @@ -940,7 +936,7 @@ void VM_find (void) { int e; int f; - char *s, *t; + const char *s, *t; prvm_edict_t *ed; VM_SAFEPARMCOUNT(3,VM_find); @@ -1028,7 +1024,7 @@ void VM_findchain (void) int i; int f; int chain_of; - char *s, *t; + const char *s, *t; prvm_edict_t *ent, *chain; VM_SAFEPARMCOUNT(2,VM_findchain); @@ -1150,7 +1146,7 @@ string precache_sound (string sample) */ void VM_precache_sound (void) { - char *s; + const char *s; VM_SAFEPARMCOUNT(1, VM_precache_sound); @@ -1434,7 +1430,7 @@ changelevel(string map) */ void VM_changelevel (void) { - char *s; + const char *s; VM_SAFEPARMCOUNT(1, VM_changelevel); @@ -1449,7 +1445,7 @@ void VM_changelevel (void) return; svs.changelevel_issued = true; - s = G_STRING(OFS_PARM0); + s = PRVM_G_STRING(OFS_PARM0); Cbuf_AddText (va("changelevel %s\n",s)); } @@ -1538,7 +1534,7 @@ float registercvar (string name, string value, float flags) */ void VM_registercvar (void) { - char *name, *value; + const char *name, *value; int flags; VM_SAFEPARMCOUNT(3,VM_registercvar); @@ -1735,7 +1731,7 @@ float fopen(string filename, float mode) void VM_fopen(void) { int filenum, mode; - char *modestring, *filename; + const char *modestring, *filename; VM_SAFEPARMCOUNT(2,VM_fopen); @@ -1862,7 +1858,7 @@ void VM_fgets(void) if (developer.integer >= 3) Con_Printf("fgets: %s: %s\n", PRVM_NAME, string); if (c >= 0 || end) - PRVM_G_INT(OFS_RETURN) = PRVM_SetString(string); + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(string); else PRVM_G_INT(OFS_RETURN) = 0; } @@ -1911,7 +1907,7 @@ float strlen(string s) //float(string s) strlen = #114; // returns how many characters are in a string void VM_strlen(void) { - char *s; + const char *s; VM_SAFEPARMCOUNT(1,VM_strlen); @@ -1941,7 +1937,7 @@ void VM_strcat(void) s = VM_GetTempString(); VM_VarString(0, s, VM_STRINGTEMP_LENGTH); - PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s); + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(s); } /* @@ -1956,7 +1952,8 @@ string substring(string s, float start, float length) void VM_substring(void) { int i, start, length; - char *s, *string; + const char *s; + char *string; VM_SAFEPARMCOUNT(3,VM_substring); @@ -1970,7 +1967,7 @@ void VM_substring(void) for (i = 0;i < VM_STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++) string[i] = *s; string[i] = 0; - PRVM_G_INT(OFS_RETURN) = PRVM_SetString(string); + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(string); } /* @@ -2001,14 +1998,15 @@ string strzone(string s) //string(string s) strzone = #118; // makes a copy of a string into the string zone and returns it, this is often used to keep around a tempstring for longer periods of time (tempstrings are replaced often) void VM_strzone(void) { - char *in, *out; + const char *in; + char *out; VM_SAFEPARMCOUNT(1,VM_strzone); in = PRVM_G_STRING(OFS_PARM0); - out = Mem_Alloc(VM_STRINGS_MEMPOOL, strlen(in) + 1); + out = PRVM_AllocString(strlen(in) + 1); strcpy(out, in); - PRVM_G_INT(OFS_RETURN) = PRVM_SetString(out); + PRVM_G_INT(OFS_RETURN) = PRVM_SetQCString(out); } /* @@ -2021,16 +2019,8 @@ strunzone(string s) //void(string s) strunzone = #119; // removes a copy of a string from the string zone (you can not use that string again or it may crash!!!) void VM_strunzone(void) { - char *str; VM_SAFEPARMCOUNT(1,VM_strunzone); - - str = PRVM_G_STRING(OFS_PARM0); - if( !str ) - PRVM_ERROR( "VM_strunzone: s%: Null string passed!", PRVM_NAME ); - if( developer.integer && !Mem_IsAllocated( VM_STRINGS_MEMPOOL, str ) ) - PRVM_ERROR( "VM_strunzone: Zone string already freed in %s!", PRVM_NAME ); - else - Mem_Free( str ); + PRVM_FreeString((char *)PRVM_G_STRING(OFS_PARM0)); } /* @@ -2077,8 +2067,7 @@ static char **tokens = NULL; static int max_tokens, num_tokens = 0; void VM_tokenize (void) { - const char *p; - char *str; + const char *p, *str; VM_SAFEPARMCOUNT(1,VM_tokenize); @@ -2123,9 +2112,9 @@ void VM_argv (void) token_num = PRVM_G_FLOAT(OFS_PARM0); if (token_num >= 0 && token_num < num_tokens) - PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tokens[token_num]); + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(tokens[token_num]); else - PRVM_G_INT(OFS_RETURN) = PRVM_SetString(""); + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(NULL); } /* @@ -2322,7 +2311,7 @@ loadfromfile(string file) */ void VM_loadfromfile(void) { - char *filename; + const char *filename; qbyte *data; VM_SAFEPARMCOUNT(1,VM_loadfromfile); @@ -2394,7 +2383,7 @@ float search_begin(string pattern, float caseinsensitive, float quiet) void VM_search_begin(void) { int handle; - char *pattern; + const char *pattern; int caseinsens, quiet; VM_SAFEPARMCOUNT(3, VM_search_begin); @@ -2515,7 +2504,7 @@ void VM_search_getfilename(void) tmp = VM_GetTempString(); strcpy(tmp, VM_SEARCHLIST[handle]->filenames[filenum]); - PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp); + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(tmp); } /* @@ -2534,7 +2523,7 @@ void VM_chr(void) tmp[0] = (unsigned char) PRVM_G_FLOAT(OFS_PARM0); tmp[1] = 0; - PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp); + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(tmp); } //============================================================================= @@ -2564,7 +2553,7 @@ string precache_pic(string pic) */ void VM_precache_pic(void) { - char *s; + const char *s; VM_SAFEPARMCOUNT(1, VM_precache_pic); @@ -2578,7 +2567,7 @@ void VM_precache_pic(void) // AK Draw_CachePic is supposed to always return a valid pointer if( Draw_CachePic(s, false)->tex == r_texture_notexture ) - PRVM_G_INT(OFS_RETURN) = PRVM_SetString(""); + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(NULL); } /* @@ -2590,7 +2579,7 @@ freepic(string s) */ void VM_freepic(void) { - char *s; + const char *s; VM_SAFEPARMCOUNT(1,VM_freepic); @@ -2662,7 +2651,7 @@ float drawstring(vector position, string text, vector scale, vector rgb, float a void VM_drawstring(void) { float *pos,*scale,*rgb; - char *string; + const char *string; int flag; VM_SAFEPARMCOUNT(6,VM_drawstring); @@ -2710,7 +2699,7 @@ float drawpic(vector position, string pic, vector size, vector rgb, float alpha, */ void VM_drawpic(void) { - char *pic; + const char *pic; float *size, *pos, *rgb; int flag; @@ -2831,7 +2820,7 @@ vector getimagesize(string pic) */ void VM_getimagesize(void) { - char *p; + const char *p; cachepic_t *pic; VM_SAFEPARMCOUNT(1,VM_getimagesize); @@ -2861,8 +2850,8 @@ float cin_open(string file, string name) */ void VM_cin_open( void ) { - char *file; - char *name; + const char *file; + const char *name; VM_SAFEPARMCOUNT( 2, VM_cin_open ); @@ -2887,7 +2876,7 @@ void cin_close(string name) */ void VM_cin_close( void ) { - char *name; + const char *name; VM_SAFEPARMCOUNT( 1, VM_cin_close ); @@ -2905,7 +2894,7 @@ void cin_setstate(string name, float type) */ void VM_cin_setstate( void ) { - char *name; + const char *name; clvideostate_t state; clvideo_t *video; @@ -2930,7 +2919,7 @@ float cin_getstate(string name) */ void VM_cin_getstate( void ) { - char *name; + const char *name; clvideo_t *video; VM_SAFEPARMCOUNT( 1, VM_cin_getstate ); @@ -2954,7 +2943,7 @@ void cin_restart(string name) */ void VM_cin_restart( void ) { - char *name; + const char *name; clvideo_t *video; VM_SAFEPARMCOUNT( 1, VM_cin_restart ); @@ -2980,7 +2969,7 @@ float altstr_count(string) */ void VM_altstr_count( void ) { - char *altstr, *pos; + const char *altstr, *pos; int count; VM_SAFEPARMCOUNT( 1, VM_altstr_count ); @@ -3007,7 +2996,7 @@ string altstr_prepare(string) void VM_altstr_prepare( void ) { char *outstr, *out; - char *instr, *in; + const char *instr, *in; int size; VM_SAFEPARMCOUNT( 1, VM_altstr_prepare ); @@ -3025,7 +3014,7 @@ void VM_altstr_prepare( void ) *out = *in; *out = 0; - PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( outstr ); + PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( outstr ); } /* @@ -3037,7 +3026,8 @@ string altstr_get(string, float) */ void VM_altstr_get( void ) { - char *altstr, *pos, *outstr, *out; + const char *altstr, *pos; + char *outstr, *out; int count, size; VM_SAFEPARMCOUNT( 2, VM_altstr_get ); @@ -3055,7 +3045,7 @@ void VM_altstr_get( void ) count--; if( !*pos ) { - PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( "" ); + PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( NULL ); return; } @@ -3072,7 +3062,7 @@ void VM_altstr_get( void ) *out = *pos; *out = 0; - PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( outstr ); + PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( outstr ); } /* @@ -3085,8 +3075,8 @@ string altstr_set(string altstr, float num, string set) void VM_altstr_set( void ) { int num; - char *altstr, *str; - char *in; + const char *altstr, *str; + const char *in; char *outstr, *out; VM_SAFEPARMCOUNT( 3, VM_altstr_set ); @@ -3107,7 +3097,7 @@ void VM_altstr_set( void ) num--; if( !in ) { - PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( "" ); + PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( NULL ); return; } // copy set in @@ -3118,12 +3108,12 @@ void VM_altstr_set( void ) break; if( !in ) { - PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( "" ); + PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( NULL ); return; } strcpy( out, in ); - PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( outstr ); + PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( outstr ); } /* @@ -3136,10 +3126,10 @@ string altstr_ins(string altstr, float num, string set) void VM_altstr_ins(void) { int num; - char *setstr; - char *set; - char *instr; - char *in; + const char *setstr; + const char *set; + const char *instr; + const char *in; char *outstr; char *out; @@ -3157,29 +3147,18 @@ void VM_altstr_ins(void) for( ; *set ; *out++ = *set++ ); strcpy( out, in ); - PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( outstr ); + PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( outstr ); } void VM_Cmd_Init(void) { // only init the stuff for the current prog - VM_STRINGS_MEMPOOL = Mem_AllocPool(va("vm_stringsmempool[%s]",PRVM_NAME), 0, NULL); VM_Files_Init(); VM_Search_Init(); } void VM_Cmd_Reset(void) { - //Mem_EmptyPool(VM_STRINGS_MEMPOOL); - if( developer.integer >= 2 && VM_STRINGS_MEMPOOL ) { - memheader_t *header; - int i; - - for( i = 0, header = VM_STRINGS_MEMPOOL->chain ; header ; header = header->next, i++ ) - Con_DPrintf( "Leaked string %i (size: %i): %.*s\n", i, header->size, header->size, ((char*)header) + sizeof( memheader_t ) ); - } - - Mem_FreePool(&VM_STRINGS_MEMPOOL); CL_PurgeOwner( MENUOWNER ); VM_Search_Reset(); VM_Files_CloseAll(); @@ -3345,7 +3324,7 @@ mfunction_t *PRVM_ED_FindFunction (const char *name); void VM_M_callfunction(void) { mfunction_t *func; - char *s; + const char *s; if(prog->argc == 0) PRVM_ERROR("VM_M_callfunction: 1 parameter is required !\n"); @@ -3390,7 +3369,7 @@ mfunction_t *PRVM_ED_FindFunction (const char *name); void VM_M_isfunction(void) { mfunction_t *func; - char *s; + const char *s; VM_SAFEPARMCOUNT(1, VM_M_isfunction); @@ -3485,7 +3464,7 @@ void VM_M_keynumtostring(void) strcpy(tmp, Key_KeynumToString(keynum)); - PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp); + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(tmp); } /* @@ -3497,7 +3476,7 @@ float stringtokeynum(string key) */ void VM_M_stringtokeynum( void ) { - char *str; + const char *str; VM_SAFEPARMCOUNT( 1, VM_M_keynumtostring ); str = PRVM_G_STRING( OFS_PARM0 ); @@ -3516,10 +3495,11 @@ the returned string is an altstring */ #define NUMKEYS 5 // TODO: merge the constant in keys.c with this one somewhen -void M_FindKeysForCommand(char *command, int *keys); +void M_FindKeysForCommand(const char *command, int *keys); void VM_M_findkeysforcommand(void) { - char *cmd, *ret; + const char *cmd; + char *ret; int keys[NUMKEYS]; int i; @@ -3536,7 +3516,7 @@ void VM_M_findkeysforcommand(void) for(i = 0; i < NUMKEYS; i++) ret = strcat(ret, va(" \'%i\'", keys[i])); - PRVM_G_INT(OFS_RETURN) = PRVM_SetString(ret); + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(ret); } /* @@ -3619,7 +3599,7 @@ setserverlistmaskstring(float mask, float fld, string str, float op) */ void VM_M_setserverlistmaskstring( void ) { - char *str; + const char *str; int masknr; serverlist_mask_t *mask; int field; @@ -3758,26 +3738,26 @@ void VM_M_getserverliststring(void) cache = serverlist_viewlist[hostnr]; switch( (int) PRVM_G_FLOAT(OFS_PARM0) ) { case SLIF_CNAME: - PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( cache->info.cname ); + PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( cache->info.cname ); break; case SLIF_NAME: - PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( cache->info.name ); + PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( cache->info.name ); break; case SLIF_GAME: - PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( cache->info.game ); + PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( cache->info.game ); break; case SLIF_MOD: - PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( cache->info.mod ); + PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( cache->info.mod ); break; case SLIF_MAP: - PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( cache->info.map ); + PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( cache->info.map ); break; // TODO remove this again case 1024: - PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( cache->line1 ); + PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( cache->line1 ); break; case 1025: - PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( cache->line2 ); + PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( cache->line2 ); break; default: Con_Print("VM_M_getserverliststring: bad field number passed!\n"); @@ -3863,7 +3843,7 @@ float getserverlistindexforkey(string key) */ void VM_M_getserverlistindexforkey( void ) { - char *key; + const char *key; VM_SAFEPARMCOUNT( 1, VM_M_getserverlistindexforkey ); key = PRVM_G_STRING( OFS_PARM0 ); diff --git a/prvm_edict.c b/prvm_edict.c index 3f54cbeb..818dba62 100644 --- a/prvm_edict.c +++ b/prvm_edict.c @@ -435,7 +435,7 @@ char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val) { static char line[4096]; int i; - char *s; + const char *s; ddef_t *def; mfunction_t *f; @@ -564,7 +564,7 @@ void PRVM_ED_Print(prvm_edict_t *ed) ddef_t *d; int *v; int i, j; - char *name; + const char *name; int type; char tempstring[8192], tempstring2[260]; // temporary string buffers @@ -638,7 +638,7 @@ void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed) ddef_t *d; int *v; int i, j; - char *name; + const char *name; int type; FS_Print(f, "{\n"); @@ -802,7 +802,7 @@ void PRVM_ED_WriteGlobals (qfile_t *f) { ddef_t *def; int i; - char *name; + const char *name; int type; FS_Print(f,"{\n"); @@ -866,37 +866,6 @@ void PRVM_ED_ParseGlobals (const char *data) //============================================================================ -/* -============= -PRVM_ED_NewString -============= -*/ -char *PRVM_ED_NewString (const char *string) -{ - char *new, *new_p; - int i,l; - - l = strlen(string) + 1; - new = Mem_Alloc(prog->progs_mempool, l); - new_p = new; - - for (i=0 ; i< l ; i++) - { - if (string[i] == '\\' && i < l-1) - { - i++; - if (string[i] == 'n') - *new_p++ = '\n'; - else - *new_p++ = '\\'; - } - else - *new_p++ = string[i]; - } - - return new; -} - /* ============= PRVM_ED_ParseEval @@ -907,7 +876,8 @@ returns false if error */ qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s) { - int i; + int i, l; + char *new_p; ddef_t *def; prvm_eval_t *val; mfunction_t *func; @@ -919,7 +889,24 @@ qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s) switch (key->type & ~DEF_SAVEGLOBAL) { case ev_string: - val->string = PRVM_SetString(PRVM_ED_NewString(s)); + l = strlen(s) + 1; + new_p = PRVM_AllocString(l); + val->string = PRVM_SetQCString(new_p); + for (i = 0;i < l;i++) + { + if (s[i] == '\\' && i < l-1) + { + i++; + if (s[i] == 'n') + *new_p++ = '\n'; + else if (s[i] == 'r') + *new_p++ = '\r'; + else + *new_p++ = s[i]; + } + else + *new_p++ = s[i]; + } break; case ev_float: @@ -1233,19 +1220,8 @@ PRVM_ResetProg void PRVM_ResetProg() { - /*mempool_t *t1; - - t1 = prog->progs_mempool; - - Mem_EmptyPool(prog->progs_mempool);*/ Mem_FreePool(&prog->progs_mempool); - memset(prog,0,sizeof(prvm_prog_t)); - - /*prog->time = &prog->_time; - - prog->progs_mempool = t1;*/ - PRVM_GCALL(reset_cmd)(); } @@ -1282,7 +1258,19 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required //pr_functions = (dfunction_t *)((qbyte *)progs + progs->ofs_functions); dfunctions = (dfunction_t *)((qbyte *)prog->progs + prog->progs->ofs_functions); + prog->strings = (char *)prog->progs + prog->progs->ofs_strings; + prog->stringssize = 0; + for (i = 0;i < prog->progs->numstrings;i++) + { + if (prog->progs->ofs_strings + prog->stringssize >= fs_filesize) + PRVM_ERROR ("%s: %s strings go past end of file\n", PRVM_NAME, filename); + prog->stringssize += strlen (prog->strings + prog->stringssize) + 1; + } + prog->numknownstrings = 0; + prog->maxknownstrings = 0; + prog->knownstrings = NULL; + prog->globaldefs = (ddef_t *)((qbyte *)prog->progs + prog->progs->ofs_globaldefs); // we need to expand the fielddefs list to include all the engine fields, @@ -1341,7 +1329,7 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required { pr_fielddefs[progs->numfielddefs].type = dpfields[i].type; pr_fielddefs[progs->numfielddefs].ofs = progs->entityfields; - pr_fielddefs[progs->numfielddefs].s_name = PR_SetString(dpfields[i].string); + pr_fielddefs[progs->numfielddefs].s_name = PR_SetEngineString(dpfields[i].string); if (pr_fielddefs[progs->numfielddefs].type == ev_vector) progs->entityfields += 3; else @@ -1496,7 +1484,8 @@ void PRVM_Fields_f (void) { int i, j, ednum, used, usedamount; int *counts; - char tempstring[5000], tempstring2[260], *name; + char tempstring[5000], tempstring2[260]; + const char *name; prvm_edict_t *ed; ddef_t *d; int *v; @@ -1740,6 +1729,24 @@ int PRVM_GetProgNr() return prog - prog_list; } +void *_PRVM_Alloc(size_t buffersize, const char *filename, int fileline) +{ + return _Mem_Alloc(prog->progs_mempool, buffersize, filename, fileline); +} + +void _PRVM_Free(void *buffer, const char *filename, int fileline) +{ + _Mem_Free(buffer, filename, fileline); +} + +void _PRVM_FreeAll(const char *filename, int fileline) +{ + prog->progs = NULL; + prog->fielddefs = NULL; + prog->functions = NULL; + _Mem_EmptyPool(prog->progs_mempool, filename, fileline); +} + // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons prvm_edict_t *PRVM_EDICT_NUM_ERROR(int n, char *filename, int fileline) { @@ -1794,3 +1801,107 @@ edict_t *PROG_TO_EDICT(int n) } */ + +const char *PRVM_GetString(int num) +{ + if (num >= 0 && num < prog->stringssize) + return prog->strings + num; + else if (num < 0 && num >= -prog->numknownstrings) + { + num = -1 - num; + if (!prog->knownstrings[num]) + Host_Error("PRVM_GetString: attempt to get string that is already freed\n"); + return prog->knownstrings[num]; + } + else + { + Host_Error("PRVM_GetString: invalid string offset %i\n", num); + return ""; + } +} + +int PRVM_SetQCString(const char *s) +{ + int i; + if (!s) + return 0; + if (s >= prog->strings && s <= prog->strings + prog->stringssize) + return s - prog->strings; + for (i = 0;i < prog->numknownstrings;i++) + if (prog->knownstrings[i] == s) + return -1 - i; + Host_Error("PRVM_SetQCString: unknown string\n"); + return -1 - i; +} + +int PRVM_SetEngineString(const char *s) +{ + int i; + if (!s) + return 0; + if (s >= prog->strings && s <= prog->strings + prog->stringssize) + Host_Error("PRVM_SetEngineString: s in prog->strings area\n"); + for (i = 0;i < prog->numknownstrings;i++) + if (prog->knownstrings[i] == s) + return -1 - i; + // new unknown engine string + if (developer.integer >= 3) + Con_Printf("new engine string %p\n", s); + for (i = 0;i < prog->numknownstrings;i++) + if (!prog->knownstrings[i]) + break; + if (i >= prog->numknownstrings) + { + if (i >= prog->maxknownstrings) + { + const char **oldstrings = prog->knownstrings; + prog->maxknownstrings += 128; + prog->knownstrings = PRVM_Alloc(prog->maxknownstrings * sizeof(char *)); + if (prog->numknownstrings) + memcpy(prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *)); + } + prog->numknownstrings++; + } + prog->knownstrings[i] = s; + return -1 - i; +} + +char *PRVM_AllocString(int bufferlength) +{ + int i; + if (!bufferlength) + return 0; + for (i = 0;i < prog->numknownstrings;i++) + if (!prog->knownstrings[i]) + break; + if (i >= prog->numknownstrings) + { + if (i >= prog->maxknownstrings) + { + const char **oldstrings = prog->knownstrings; + prog->maxknownstrings += 128; + prog->knownstrings = PRVM_Alloc(prog->maxknownstrings * sizeof(char *)); + if (prog->numknownstrings) + memcpy(prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *)); + } + prog->numknownstrings++; + } + return (char *)(prog->knownstrings[i] = PRVM_Alloc(bufferlength)); +} + +void PRVM_FreeString(char *s) +{ + int i; + if (!s) + Host_Error("PRVM_FreeString: attempt to free a NULL string\n"); + if (s >= prog->strings && s <= prog->strings + prog->stringssize) + Host_Error("PRVM_FreeString: attempt to free a constant string\n"); + for (i = 0;i < prog->numknownstrings;i++) + if (prog->knownstrings[i] == s) + break; + if (i == prog->numknownstrings) + Host_Error("PRVM_FreeString: attempt to free a non-existent or already freed string\n"); + PRVM_Free((char *)prog->knownstrings[i]); + prog->knownstrings[i] = NULL; +} + diff --git a/server.h b/server.h index 770be3f7..5439f506 100644 --- a/server.h +++ b/server.h @@ -77,7 +77,7 @@ typedef struct // LordHavoc: precaches are now MAX_QPATH rather than a pointer // updated by SV_SoundIndex char sound_precache[MAX_SOUNDS][MAX_QPATH]; - char *lightstyles[MAX_LIGHTSTYLES]; + char lightstyles[MAX_LIGHTSTYLES][64]; int num_edicts; int max_edicts; // small edict_t structures which just contain pointers @@ -297,7 +297,7 @@ void SV_Init (void); void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count); void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate); -void SV_StartSound (edict_t *entity, int channel, char *sample, int volume, float attenuation); +void SV_StartSound (edict_t *entity, int channel, const char *sample, int volume, float attenuation); void SV_ConnectClient (int clientnum, netconn_t *netconnection); void SV_DropClient (qboolean crash); @@ -311,8 +311,8 @@ void SV_ReadClientMessage(void); // 0 = fail if not precached, // 1 = warn if not found and precache if possible // 2 = precache -int SV_ModelIndex(char *s, int precachemode); -int SV_SoundIndex(char *s, int precachemode); +int SV_ModelIndex(const char *s, int precachemode); +int SV_SoundIndex(const char *s, int precachemode); void SV_SetIdealPitch (void); diff --git a/sv_main.c b/sv_main.c index 2e2f18a6..c330e94b 100644 --- a/sv_main.c +++ b/sv_main.c @@ -201,7 +201,7 @@ Larger attenuations will drop off. (max 4 attenuation) ================== */ -void SV_StartSound (edict_t *entity, int channel, char *sample, int volume, float attenuation) +void SV_StartSound (edict_t *entity, int channel, const char *sample, int volume, float attenuation) { int sound_num, field_mask, i, ent; @@ -1136,9 +1136,9 @@ void SV_UpdateToReliableMessages (void) int i, j; client_t *client; eval_t *val; - char *name; - char *model; - char *skin; + const char *name; + const char *model; + const char *skin; // check for changes to be sent over the reliable streams for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++) @@ -1152,7 +1152,7 @@ void SV_UpdateToReliableMessages (void) name = ""; // always point the string back at host_client->name to keep it safe strlcpy (host_client->name, name, sizeof (host_client->name)); - host_client->edict->v->netname = PR_SetString(host_client->name); + host_client->edict->v->netname = PR_SetEngineString(host_client->name); if (strcmp(host_client->old_name, host_client->name)) { if (host_client->spawned) @@ -1184,7 +1184,7 @@ void SV_UpdateToReliableMessages (void) model = ""; // always point the string back at host_client->name to keep it safe strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel)); - GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PR_SetString(host_client->playermodel); + GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PR_SetEngineString(host_client->playermodel); } // NEXUIZ_PLAYERSKIN @@ -1194,7 +1194,7 @@ void SV_UpdateToReliableMessages (void) skin = ""; // always point the string back at host_client->name to keep it safe strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin)); - GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PR_SetString(host_client->playerskin); + GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PR_SetEngineString(host_client->playerskin); } // frags @@ -1333,7 +1333,7 @@ SV_ModelIndex ================ */ -int SV_ModelIndex(char *s, int precachemode) +int SV_ModelIndex(const char *s, int precachemode) { int i, limit = (sv.protocol == PROTOCOL_QUAKE ? 256 : MAX_MODELS); char filename[MAX_QPATH]; @@ -1382,7 +1382,7 @@ SV_SoundIndex ================ */ -int SV_SoundIndex(char *s, int precachemode) +int SV_SoundIndex(const char *s, int precachemode) { int i, limit = (sv.protocol == PROTOCOL_QUAKE ? 256 : MAX_SOUNDS); char filename[MAX_QPATH]; @@ -1762,7 +1762,7 @@ void SV_SpawnServer (const char *server) ent = EDICT_NUM(0); memset (ent->v, 0, progs->entityfields * 4); ent->e->free = false; - ent->v->model = PR_SetString(sv.modelname); + ent->v->model = PR_SetEngineString(sv.modelname); ent->v->modelindex = 1; // world model ent->v->solid = SOLID_BSP; ent->v->movetype = MOVETYPE_PUSH; @@ -1772,7 +1772,7 @@ void SV_SpawnServer (const char *server) else pr_global_struct->deathmatch = deathmatch.integer; - pr_global_struct->mapname = PR_SetString(sv.name); + pr_global_struct->mapname = PR_SetEngineString(sv.name); // serverflags are for cross level information (sigils) pr_global_struct->serverflags = svs.serverflags; diff --git a/sv_user.c b/sv_user.c index 24cc9a7b..ff18ccf4 100644 --- a/sv_user.c +++ b/sv_user.c @@ -776,7 +776,7 @@ void SV_ReadClientMessage(void) Cmd_ExecuteString (s, src_client); else if (SV_ParseClientCommandQC) { - G_INT(OFS_PARM0) = PR_SetString(s); + G_INT(OFS_PARM0) = PR_SetEngineString(s); pr_global_struct->self = EDICT_TO_PROG(host_client->edict); PR_ExecuteProgram ((func_t)(SV_ParseClientCommandQC - pr_functions), "QC function SV_ParseClientCommand is missing"); } diff --git a/wad.c b/wad.c index 35671d6e..333e619b 100644 --- a/wad.c +++ b/wad.c @@ -38,7 +38,7 @@ Space padding is so names can be printed nicely in tables. Can safely be performed in place. ================== */ -static void W_CleanupName (char *in, char *out) +static void W_CleanupName (const char *in, char *out) { int i; int c; @@ -58,7 +58,7 @@ static void W_CleanupName (char *in, char *out) out[i] = 0; } -void *W_GetLumpName(char *name) +void *W_GetLumpName(const char *name) { int i; lumpinfo_t *lump; diff --git a/wad.h b/wad.h index edef176d..87289a7a 100644 --- a/wad.h +++ b/wad.h @@ -69,7 +69,7 @@ extern int wad_numlumps; extern lumpinfo_t *wad_lumps; extern qbyte *wad_base; -void *W_GetLumpName (char *name); +void *W_GetLumpName (const char *name); // LordHavoc: added alternate texture WAD2/WAD3 system for easier loading of HalfLife texture wads -- 2.39.2