From dcd9b0040e018733952b403f89e51d5dfcc0d5bf Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 4 Nov 2001 07:50:39 +0000 Subject: [PATCH] rewrite the info strings to use hash tables instead of a static string. This required changes to the api (info_t instead of char *) but should be a net gain in speed (not a lot, admittedly: it was pretty fast to begin with, but this paves the way for some other changes I have in mind). --- include/QF/info.h | 28 +++- libs/util/info.c | 335 +++++++++++++++------------------------- qw/include/client.h | 6 +- qw/include/server.h | 8 +- qw/source/cl_cvar.c | 1 - qw/source/cl_demo.c | 5 +- qw/source/cl_main.c | 35 +++-- qw/source/cl_parse.c | 16 +- qw/source/cl_slist.c | 25 +-- qw/source/game.c | 3 +- qw/source/skin.c | 2 +- qw/source/sv_ccmds.c | 9 +- qw/source/sv_cvar.c | 2 - qw/source/sv_init.c | 8 +- qw/source/sv_main.c | 49 +++--- qw/source/sv_pr_cmds.c | 5 +- qw/source/sv_progs.c | 3 +- qw/source/sv_sys_unix.c | 2 +- qw/source/sv_user.c | 5 +- 19 files changed, 249 insertions(+), 298 deletions(-) diff --git a/include/QF/info.h b/include/QF/info.h index 956d0d359..7a03ba7ff 100644 --- a/include/QF/info.h +++ b/include/QF/info.h @@ -36,13 +36,27 @@ #define MAX_SERVERINFO_STRING 512 #define MAX_LOCALINFO_STRING 32768 +typedef struct info_s { + struct hashtab_s *tab; + int maxsize; + int cursize; +} info_t; + +typedef struct info_key_s { + const char *key; + const char *value; +} info_key_t; + qboolean Info_FilterForKey (const char *key, const char **filter_list); -void Info_Print (const char *s); -void Info_RemoveKey (char *s, const char *key); -void Info_RemovePrefixedKeys (char *start, char prefix, const char **filter_list); -void Info_SetValueForKey (char *s, const char *key, const char *value, size_t maxsize, int flags); -void Info_SetValueForStarKey (char *s, const char *key, const char *value, size_t maxsize, int flags); -const char *Info_ValueForKey (const char *s, const char *key); -qboolean Info_Validate (const char *s); + +void Info_Print (info_t *info); +void Info_RemoveKey (info_t *info, const char *key); +void Info_SetValueForKey (info_t *info, const char *key, const char *value, int flags); +void Info_SetValueForStarKey (info_t *info, const char *key, const char *value, int flags); +const char *Info_ValueForKey (info_t *info, const char *key); + +info_t *Info_ParseString (const char *s, int maxsize); +void Info_Destroy (info_t *info); +char *Info_MakeString (info_t *info, int (*filter)(const char *)); #endif // _INFO_H diff --git a/libs/util/info.c b/libs/util/info.c index 64a01ff25..8137ef9e9 100644 --- a/libs/util/info.c +++ b/libs/util/info.c @@ -40,8 +40,10 @@ static const char rcsid[] = #include #include +#include "QF/hash.h" #include "QF/info.h" #include "QF/sys.h" +#include "QF/zone.h" #include "compat.h" @@ -71,139 +73,31 @@ Info_FilterForKey (const char *key, const char **filter_list) key and returns the associated value, or an empty string. */ const char * -Info_ValueForKey (const char *s, const char *key) +Info_ValueForKey (info_t *info, const char *key) { - char pkey[512]; - static char value[4][512]; // use two buffers so compares + info_key_t *k = Hash_Find (info->tab, key); + if (k) + return k->value; + return ""; +} - // work without stomping on each other - static int valueindex; - char *o; +void +Info_RemoveKey (info_t *info, const char *key) +{ + info_key_t *k = Hash_Del (info->tab, key); - valueindex = (valueindex + 1) % 4; - if (*s == '\\') - s++; - while (1) { - o = pkey; - while (*s != '\\') { - if (!*s) - return ""; - *o++ = *s++; - } - *o = 0; - s++; - - o = value[valueindex]; - - while (*s != '\\' && *s) { - if (!*s) - return ""; - *o++ = *s++; - } - *o = 0; - - if (!strcmp (key, pkey)) - return value[valueindex]; - - if (!*s) - return ""; - s++; + if (k) { + free ((char*)k->key); + free ((char*)k->value); + free (k); } } void -Info_RemoveKey (char *s, const char *key) +Info_SetValueForStarKey (info_t *info, const char *key, const char *value, int flags) { - char *start; - char pkey[512]; - char value[512]; - char *o; - - if (strstr (key, "\\")) { - Sys_Printf ("Can't use a key with a \\\n"); - return; - } - - while (1) { - start = s; - if (*s == '\\') - s++; - o = pkey; - while (*s != '\\') { - if (!*s) - return; - *o++ = *s++; - } - *o = 0; - s++; - - o = value; - while (*s != '\\' && *s) { - if (!*s) - return; - *o++ = *s++; - } - *o = 0; - - if (!strcmp (key, pkey)) { - strcpy (start, s); // remove this part - return; - } - - if (!*s) - return; - } - -} - -void -Info_RemovePrefixedKeys (char *start, char prefix, const char **filter_list) -{ - char *s; - char pkey[512]; - char value[512]; - char *o; - - s = start; - - while (1) { - if (*s == '\\') - s++; - o = pkey; - while (*s != '\\') { - if (!*s) - return; - *o++ = *s++; - } - *o = 0; - s++; - - o = value; - while (*s != '\\' && *s) { - if (!*s) - return; - *o++ = *s++; - } - *o = 0; - - if (pkey[0] == prefix - || (filter_list && !Info_FilterForKey (pkey, filter_list))) { - Info_RemoveKey (start, pkey); - s = start; - } - - if (!*s) - return; - } - -} - -void -Info_SetValueForStarKey (char *s, const char *key, const char *value, size_t maxsize, int flags) -{ - char newstr[1024]; - const char *v; - int c; + info_key_t *k; + int cursize; if (strstr (key, "\\") || strstr (value, "\\")) { Sys_Printf ("Can't use keys or values with a \\\n"); @@ -219,110 +113,137 @@ Info_SetValueForStarKey (char *s, const char *key, const char *value, size_t max Sys_Printf ("Keys and values must be < 64 characters.\n"); return; } - // this next line is kinda trippy - if (*(v = Info_ValueForKey (s, key))) { - // key exists, make sure we have enough room for new value, if we - // don't, - // don't change it! - if (strlen (value) - strlen (v) + strlen (s) > maxsize) { - Sys_Printf ("Info string length exceeded\n"); - return; - } + k = Hash_Find (info->tab, key); + cursize = info->cursize; + if (k) { + cursize -= strlen (k->key) + 1; + cursize -= strlen (k->value) + 1; } - Info_RemoveKey (s, key); - if (!value || !strlen (value)) - return; - - snprintf (newstr, sizeof (newstr), "\\%s\\%s", key, value); - - if ((int) (strlen (newstr) + strlen (s)) > maxsize) { + if (cursize + strlen (key) + 1 + strlen (value) + 1 > info->maxsize) { Sys_Printf ("Info string length exceeded\n"); return; } - // only copy ascii values - s += strlen (s); - v = newstr; - while (*v) { - c = (unsigned char) *v++; - // client only allows highbits on name - if (flags & 1) { - c &= 127; - if (c < 32 || c > 127) - continue; - // auto lowercase team - if (flags & 2) - c = tolower (c); - } - if (c > 13) - *s++ = c; + if (k) { + if (strequal (k->value, value)) + return; + free ((char*)k->value); + } else { + if (!(k = malloc (sizeof (info_key_t)))) + Sys_Error ("Info_SetValueForStarKey: out of memory\n"); + if (!(k->key = strdup (key))) + Sys_Error ("Info_SetValueForStarKey: out of memory\n"); + info->cursize += strlen (key) + 1; + Hash_Add (info->tab, k); } - *s = 0; + if (!(k->value = strdup (value))) + Sys_Error ("Info_SetValueForStarKey: out of memory\n"); + info->cursize += strlen (value) + 1; } void -Info_SetValueForKey (char *s, const char *key, const char *value, - size_t maxsize, int flags) +Info_SetValueForKey (info_t *info, const char *key, const char *value, + int flags) { if (key[0] == '*') { Sys_Printf ("Can't set * keys\n"); return; } - Info_SetValueForStarKey (s, key, value, maxsize, flags); + Info_SetValueForStarKey (info, key, value, flags); } void -Info_Print (const char *s) +Info_Print (info_t *info) { - char key[512]; - char value[512]; - char *o; - int l; + info_key_t **key_list; + info_key_t **key; - if (*s == '\\') - s++; - while (*s) { - o = key; - while (*s && *s != '\\') - *o++ = *s++; + key_list = (info_key_t **)Hash_GetList (info->tab); - l = o - key; - if (l < 20) { - memset (o, ' ', 20 - l); - key[20] = 0; - } else - *o = 0; - Sys_Printf ("%s", key); - - if (!*s) { - Sys_Printf ("MISSING VALUE\n"); - return; - } - - o = value; - s++; - while (*s && *s != '\\') - *o++ = *s++; - *o = 0; - - if (*s) - s++; - Sys_Printf ("%s\n", value); + for (key = key_list; *key; key++) { + Sys_Printf ("%20s %s\n", (*key)->key, (*key)->value); } + free (key_list); } -qboolean -Info_Validate (const char *s) +static const char * +get_key (void *k, void *unused) { - int count; - const char *p; - - if (!s || *s == '\0') - return false; - - for (p = s, count = 0; *p != '\0'; p++) - if (*p == '\\') - count++; - - return (!(count % 2)); + return ((info_key_t *)k)->key; +} + +static void +free_key (void *_k, void *unused) +{ + info_key_t *k = (info_key_t *)_k; + free ((char*)k->key); + free ((char*)k->value); + free (k); +} + +info_t * +Info_ParseString (const char *s, int maxsize) +{ + info_t *info; + char *string = Hunk_TempAlloc (strlen (s) + 1); + char *key, *value, *end; + + info = malloc (sizeof (info_t)); + info->tab = Hash_NewTable (61, get_key, free_key, 0); + info->maxsize = maxsize; + info->cursize = 0; + + strcpy (string, s); + key = string; + if (*key == '\\') + key++; + while (*key) { + value = key; + while (*value && *value != '\\') + value++; + if (*value) { + *value++ = 0; + for (end = value; *end && *end != '\\'; end++) + ; + if (*end) + *end++ = 0; + } else { + value = end = ""; + } + Info_SetValueForStarKey (info, key, value, 0); + key = end; + } + return info; +} + +void +Info_Destroy (info_t *info) +{ + Hash_DelTable (info->tab); + free (info); +} + +char * +Info_MakeString (info_t *info, int (*filter)(const char *)) +{ + char *string = Hunk_TempAlloc (info->cursize + 1); + const char *s; + char *d = string;; + info_key_t **key_list; + info_key_t **key; + + key_list = (info_key_t **)Hash_GetList (info->tab); + + for (key = key_list; *key; key++) { + if (filter && filter ((*key)->key)) + continue; + *d++ = '\\'; + for (s = (*key)->key; *s; s++) + *d++ = *s; + *d++ = '\\'; + for (s = (*key)->value; *s; s++) + *d++ = *s; + } + free (key_list); + return string; } diff --git a/qw/include/client.h b/qw/include/client.h index f7d897e96..f35674241 100644 --- a/qw/include/client.h +++ b/qw/include/client.h @@ -75,7 +75,7 @@ typedef struct player_state_s { typedef struct player_info_s { int userid; - char userinfo[MAX_INFO_STRING]; + struct info_s *userinfo; // scoreboard information char name[MAX_SCOREBOARDNAME]; @@ -148,7 +148,7 @@ typedef struct netchan_t netchan; // private userinfo for sending to masterless servers - char userinfo[MAX_INFO_STRING]; + struct info_s *userinfo; char servername[MAX_OSPATH]; // name of server from original connect @@ -190,7 +190,7 @@ typedef struct { int servercount; // server identification for prespawns - char serverinfo[MAX_SERVERINFO_STRING]; + struct info_s *serverinfo; int parsecount; // server message counter int validsequence; // this is the sequence number of the last good diff --git a/qw/include/server.h b/qw/include/server.h index b1f7fac5e..fcec31612 100644 --- a/qw/include/server.h +++ b/qw/include/server.h @@ -161,7 +161,7 @@ typedef struct client_s int lossage; // loss percentage int userid; // identifying number - char userinfo[MAX_INFO_STRING]; // infostring + struct info_s *userinfo; // infostring usercmd_t lastcmd; // for filling in big drops and partial predictions double localtime; // of last message @@ -276,7 +276,7 @@ typedef struct int heartbeat_sequence; svstats_t stats; - char info[MAX_SERVERINFO_STRING]; + info_t *info; // log messages are used so that fraglog processes can get stats int logsequence; // the message currently being filled @@ -397,7 +397,7 @@ extern struct cvar_s *fraglimit; extern struct cvar_s *timelimit; extern server_static_t svs; // persistant server info -extern char *svs_info; // evil memory saving hack :) +extern struct info_s **svs_info; extern server_t sv; // local server extern client_t *host_client; @@ -406,7 +406,7 @@ extern struct edict_s *sv_player; extern char localmodels[MAX_MODELS][5]; // inline model names for precache -extern char localinfo[MAX_LOCALINFO_STRING+1]; +extern struct info_s *localinfo; extern int host_hunklevel; extern VFile *sv_logfile; diff --git a/qw/source/cl_cvar.c b/qw/source/cl_cvar.c index e60c1d69b..21e107318 100644 --- a/qw/source/cl_cvar.c +++ b/qw/source/cl_cvar.c @@ -49,7 +49,6 @@ Cvar_Info (cvar_t *var) { if (var->flags & CVAR_USERINFO) { Info_SetValueForKey (cls.userinfo, var->name, var->string, - MAX_INFO_STRING, ((!strequal(var->name, "name")) |(strequal(var->name, "team") << 1))); if (cls.state >= ca_connected) { diff --git a/qw/source/cl_demo.c b/qw/source/cl_demo.c index 9ba508e28..f61121743 100644 --- a/qw/source/cl_demo.c +++ b/qw/source/cl_demo.c @@ -483,7 +483,8 @@ CL_Record_f (void) // send server info string MSG_WriteByte (&buf, svc_stufftext); - MSG_WriteString (&buf, va ("fullserverinfo \"%s\"\n", cl.serverinfo)); + MSG_WriteString (&buf, va ("fullserverinfo \"%s\"\n", + Info_MakeString (cl.serverinfo, 0))); // flush packet CL_WriteRecordDemoMessage (&buf, seq++); @@ -626,7 +627,7 @@ CL_Record_f (void) MSG_WriteByte (&buf, svc_updateuserinfo); MSG_WriteByte (&buf, i); MSG_WriteLong (&buf, player->userid); - MSG_WriteString (&buf, player->userinfo); + MSG_WriteString (&buf, Info_MakeString (player->userinfo, 0)); if (buf.cursize > MAX_MSGLEN / 2) { CL_WriteRecordDemoMessage (&buf, seq++); diff --git a/qw/source/cl_main.c b/qw/source/cl_main.c index 56164ba96..ca23e9157 100644 --- a/qw/source/cl_main.c +++ b/qw/source/cl_main.c @@ -294,7 +294,7 @@ CL_SendConnectPacket (void) // Con_Printf ("Connecting to %s...\n", cls.servername); snprintf (data, sizeof (data), "%c%c%c%cconnect %i %i %i \"%s\"\n", 255, 255, 255, 255, PROTOCOL_VERSION, cls.qport, cls.challenge, - cls.userinfo); + Info_MakeString (cls.userinfo, 0)); NET_SendPacket (strlen (data), data, adr); } @@ -419,7 +419,9 @@ CL_ClearState (void) R_ClearFires (); // wipe the entire cl structure + Info_Destroy (cl.serverinfo); memset (&cl, 0, sizeof (cl)); + cl.serverinfo = Info_ParseString ("", MAX_INFO_STRING); SZ_Clear (&cls.netchan.message); @@ -572,8 +574,9 @@ CL_FullServerinfo_f (void) } Con_DPrintf ("Cmd_Argv(1): '%s'\n", Cmd_Argv (1)); - strcpy (cl.serverinfo, Cmd_Argv (1)); - Con_DPrintf ("cl.serverinfo: '%s'\n", cl.serverinfo); + Info_Destroy (cl.serverinfo); + cl.serverinfo = Info_ParseString (Cmd_Argv (1), MAX_SERVERINFO_STRING); + Con_DPrintf ("cl.serverinfo: '%s'\n", Info_MakeString (cl.serverinfo, 0)); if ((p = Info_ValueForKey (cl.serverinfo, "*qf_version")) && *p) { if (server_version == NULL) @@ -620,11 +623,9 @@ CL_AddQFInfoKeys (void) #ifdef HAVE_ZLIB strncat (cap, "z", sizeof (cap) - strlen (cap) - 1); #endif - Info_SetValueForStarKey (cls.userinfo, "*cap", cap, MAX_INFO_STRING, 0); - Info_SetValueForStarKey (cls.userinfo, "*qf_version", VERSION, - MAX_INFO_STRING, 0); - Info_SetValueForStarKey (cls.userinfo, "*qsg_version", QW_QSG_VERSION, - MAX_INFO_STRING, 0); + Info_SetValueForStarKey (cls.userinfo, "*cap", cap, 0); + Info_SetValueForStarKey (cls.userinfo, "*qf_version", VERSION, 0); + Info_SetValueForStarKey (cls.userinfo, "*qsg_version", QW_QSG_VERSION, 0); Con_Printf ("QuakeForge server detected\n"); } @@ -680,7 +681,7 @@ CL_FullInfo_f (void) if (strcaseequal (key, pmodel_name) || strcaseequal (key, emodel_name)) continue; - Info_SetValueForKey (cls.userinfo, key, value, MAX_INFO_STRING, + Info_SetValueForKey (cls.userinfo, key, value, (!strequal (key, "name")) | (strequal (key, "team") << 1)); } @@ -707,7 +708,6 @@ CL_SetInfo_f (void) return; Info_SetValueForKey (cls.userinfo, Cmd_Argv (1), Cmd_Argv (2), - MAX_INFO_STRING, (!strequal (Cmd_Argv (1), "name")) | (strequal (Cmd_Argv (2), "team") << 1)); if (cls.state >= ca_connected) @@ -1092,14 +1092,14 @@ CL_Init (void) CL_SetState (ca_disconnected); - Info_SetValueForKey (cls.userinfo, "name", "unnamed", MAX_INFO_STRING, 0); - Info_SetValueForKey (cls.userinfo, "topcolor", "0", MAX_INFO_STRING, 0); - Info_SetValueForKey (cls.userinfo, "bottomcolor", "0", MAX_INFO_STRING, 0); - Info_SetValueForKey (cls.userinfo, "rate", "2500", MAX_INFO_STRING, 0); - Info_SetValueForKey (cls.userinfo, "msg", "1", MAX_INFO_STRING, 0); + Info_SetValueForKey (cls.userinfo, "name", "unnamed", 0); + Info_SetValueForKey (cls.userinfo, "topcolor", "0", 0); + Info_SetValueForKey (cls.userinfo, "bottomcolor", "0", 0); + Info_SetValueForKey (cls.userinfo, "rate", "2500", 0); + Info_SetValueForKey (cls.userinfo, "msg", "1", 0); // snprintf (st, sizeof(st), "%s-%04d", QW_VERSION, build_number()); snprintf (st, sizeof (st), "%s", QW_VERSION); - Info_SetValueForStarKey (cls.userinfo, "*ver", st, MAX_INFO_STRING, 0); + Info_SetValueForStarKey (cls.userinfo, "*ver", st, 0); CL_Input_Init (); CL_Ents_Init (); @@ -1577,6 +1577,9 @@ Host_Init (void) Sys_Init_Cvars (); Sys_Init (); + cls.userinfo = Info_ParseString ("", MAX_INFO_STRING); + cl.serverinfo = Info_ParseString ("", MAX_INFO_STRING); + Cbuf_Init (); Cmd_Init (); Locs_Init (); diff --git a/qw/source/cl_parse.c b/qw/source/cl_parse.c index 5aa3666e4..ddc53714c 100644 --- a/qw/source/cl_parse.c +++ b/qw/source/cl_parse.c @@ -300,7 +300,7 @@ Model_NextDownload (void) aliashdr_t *ahdr = Cache_Get (&cl.model_precache[i]->cache); Info_SetValueForKey (cls.userinfo, info_key, va ("%d", ahdr->crc), - MAX_INFO_STRING, 0); + 0); MSG_WriteByte (&cls.netchan.message, clc_stringcmd); SZ_Print (&cls.netchan.message, va ("setinfo %s %d", info_key, ahdr->crc)); @@ -1039,8 +1039,10 @@ CL_ParseUpdateUserInfo (void) player = &cl.players[updateuserinfo.slot]; player->userid = updateuserinfo.userid; - strncpy (player->userinfo, updateuserinfo.userinfo, - sizeof (player->userinfo) - 1); + if (player->userinfo) + Info_Destroy (player->userinfo); + player->userinfo = Info_ParseString (updateuserinfo.userinfo, + MAX_INFO_STRING); CL_ProcessUserInfo (updateuserinfo.slot, player); } @@ -1063,14 +1065,15 @@ CL_SetInfo (void) } player = &cl.players[setinfo.slot]; + if (!player->userinfo) + player->userinfo = Info_ParseString ("", MAX_INFO_STRING); Con_DPrintf ("SETINFO %s: %s=%s\n", player->name, setinfo.key, setinfo.value); flags = !strequal (setinfo.key, "name"); flags |= strequal (setinfo.key, "team") << 1; - Info_SetValueForKey (player->userinfo, setinfo.key, setinfo.value, - MAX_INFO_STRING, flags); + Info_SetValueForKey (player->userinfo, setinfo.key, setinfo.value, flags); CL_ProcessUserInfo (setinfo.slot, player); } @@ -1087,8 +1090,7 @@ CL_ServerInfo (void) Con_DPrintf ("SERVERINFO: %s=%s\n", block.key, block.value); - Info_SetValueForKey (cl.serverinfo, block.key, block.value, - MAX_SERVERINFO_STRING, 0); + Info_SetValueForKey (cl.serverinfo, block.key, block.value, 0); if (strequal (block.key, "chase")) { cl.chase = atoi (block.value); } else if (strequal (block.key, "watervis")) { diff --git a/qw/source/cl_slist.c b/qw/source/cl_slist.c index 4cce4aff7..f68790dc1 100644 --- a/qw/source/cl_slist.c +++ b/qw/source/cl_slist.c @@ -75,7 +75,7 @@ static const char rcsid[] = typedef struct server_entry_s { char *server; char *desc; - char *status; + info_t *status; int waitstatus; double pingsent; double pongback; @@ -480,11 +480,15 @@ SL_Con_Details (server_entry_t *sldata, int slitemno) Con_Printf("N/A\n"); if (cp->status) { + char *s; + Con_Printf("Name: %s\n", cp->desc); Con_Printf("Game: %s\n", Info_ValueForKey (cp->status, "*gamedir")); Con_Printf("Map: %s\n", Info_ValueForKey (cp->status, "map")); - for (i = 0; i < strlen(cp->status); i++) - if (cp->status[i] == '\n') + + s = Info_MakeString (cp->status, 0); + for (i = 0; i < strlen (s); i++) + if (s[i] == '\n') playercount++; Con_Printf("Players: %i/%s\n", playercount, Info_ValueForKey(cp->status, "maxclients")); @@ -693,13 +697,14 @@ SL_CheckStatus (const char *cs_from, const char *cs_data) { if (strcmp (cs_from, temp->server) == 0) { - int i; - temp->status = realloc(temp->status, strlen(cs_data) + 1); - strcpy(temp->status, cs_data); + //int i; + if (temp->status) + Info_Destroy (temp->status); + temp->status = Info_ParseString (cs_data, strlen (cs_data)); temp->waitstatus = 0; tmp_desc = Info_ValueForKey (temp->status, "hostname"); - if (tmp_desc[0] != '\0') - { + /*FIXME update for new info api + if (tmp_desc[0] != '\0') { temp->desc = realloc(temp->desc, strlen(tmp_desc) + 1); strcpy(temp->desc, tmp_desc); } else { @@ -707,11 +712,11 @@ SL_CheckStatus (const char *cs_from, const char *cs_data) strcpy(temp->desc, temp->server); } for (i = 0; i < strlen(temp->status); i++) - if (temp->status[i] == '\n') - { + if (temp->status[i] == '\n') { temp->status[i] = '\\'; break; } + */ return (1); } } diff --git a/qw/source/game.c b/qw/source/game.c index 0b81a29c7..52318b725 100644 --- a/qw/source/game.c +++ b/qw/source/game.c @@ -82,8 +82,7 @@ SV_Gamedir_f (void) COM_Gamedir (dir); if (is_server) { - Info_SetValueForStarKey (svs_info, "*gamedir", dir, - MAX_SERVERINFO_STRING, 0); + Info_SetValueForStarKey (*svs_info, "*gamedir", dir, 0); } } diff --git a/qw/source/skin.c b/qw/source/skin.c index 34183f418..46912ace3 100644 --- a/qw/source/skin.c +++ b/qw/source/skin.c @@ -101,7 +101,7 @@ Skin_Find (player_info_t *sc) strcpy (name, "base"); if (!allskins[0] && (!s || !strcaseequal (name, s))) - Info_SetValueForKey (sc->userinfo, "skin", name, MAX_INFO_STRING, 1); + Info_SetValueForKey (sc->userinfo, "skin", name, 1); COM_StripExtension (name, name); diff --git a/qw/source/sv_ccmds.c b/qw/source/sv_ccmds.c index 8f6676c87..8ab3fd080 100644 --- a/qw/source/sv_ccmds.c +++ b/qw/source/sv_ccmds.c @@ -866,7 +866,7 @@ SV_Serverinfo_f (void) return; } Info_SetValueForKey (svs.info, Cmd_Argv (1), Cmd_Argv (2), - MAX_SERVERINFO_STRING, !sv_highchars->int_val); + !sv_highchars->int_val); // if this is a cvar, change it too var = Cvar_FindVar (Cmd_Argv (1)); @@ -902,7 +902,7 @@ SV_Localinfo_f (void) return; } Info_SetValueForKey (localinfo, Cmd_Argv (1), Cmd_Argv (2), - MAX_LOCALINFO_STRING, !sv_highchars->int_val); + !sv_highchars->int_val); } /* @@ -953,7 +953,7 @@ SV_Gamedir (void) return; } - Info_SetValueForStarKey (svs.info, "*gamedir", dir, MAX_SERVERINFO_STRING, + Info_SetValueForStarKey (svs.info, "*gamedir", dir, !sv_highchars->int_val); } @@ -1102,8 +1102,7 @@ SV_InitOperatorCommands (void) { if (COM_CheckParm ("-cheats")) { sv_allow_cheats = true; - Info_SetValueForStarKey (svs.info, "*cheats", "ON", - MAX_SERVERINFO_STRING, 0); + Info_SetValueForStarKey (svs.info, "*cheats", "ON", 0); } Cmd_AddCommand ("logfile", SV_Logfile_f, "Toggles logging of console text " diff --git a/qw/source/sv_cvar.c b/qw/source/sv_cvar.c index 3492bb17c..6aa54402a 100644 --- a/qw/source/sv_cvar.c +++ b/qw/source/sv_cvar.c @@ -62,11 +62,9 @@ Cvar_Info (cvar_t *var) } *p = 0; Info_SetValueForKey (svs.info, var->name, info, - MAX_SERVERINFO_STRING, (sv_highchars && !sv_highchars->int_val)); } else Info_SetValueForKey (svs.info, var->name, var->string, - MAX_SERVERINFO_STRING, (sv_highchars && !sv_highchars->int_val)); SV_SendServerInfoChange (var->name, var->string); diff --git a/qw/source/sv_init.c b/qw/source/sv_init.c index 0d137158a..731e1625a 100644 --- a/qw/source/sv_init.c +++ b/qw/source/sv_init.c @@ -39,6 +39,7 @@ static const char rcsid[] = #include "QF/crc.h" #include "QF/cvar.h" +#include "QF/info.h" #include "QF/msg.h" #include "QF/va.h" #include "QF/vfs.h" @@ -50,7 +51,7 @@ static const char rcsid[] = #include "sv_progs.h" #include "world.h" -char localinfo[MAX_LOCALINFO_STRING + 1]; // local game info +info_t *localinfo; // local game info char localmodels[MAX_MODELS][5]; // inline model names for precache entity_state_t baselines[MAX_EDICTS]; @@ -332,7 +333,7 @@ SV_SpawnServer (const char *server) // edict is SV_LoadProgs (); Info_SetValueForStarKey (svs.info, "*progs", va ("%i", sv_pr_state.crc), - MAX_SERVERINFO_STRING, !sv_highchars->int_val); + !sv_highchars->int_val); // allocate edicts sv.edicts = PR_InitEdicts (&sv_pr_state, MAX_EDICTS); @@ -423,7 +424,6 @@ SV_SpawnServer (const char *server) SV_CreateBaseline (); sv.signon_buffer_size[sv.num_signon_buffers - 1] = sv.signon.cursize; - Info_SetValueForKey (svs.info, "map", sv.name, MAX_SERVERINFO_STRING, - !sv_highchars->int_val); + Info_SetValueForKey (svs.info, "map", sv.name, !sv_highchars->int_val); Con_DPrintf ("Server spawned.\n"); } diff --git a/qw/source/sv_main.c b/qw/source/sv_main.c index 9dc59260e..366caad87 100644 --- a/qw/source/sv_main.c +++ b/qw/source/sv_main.c @@ -327,7 +327,9 @@ SV_DropClient (client_t *drop) drop->old_frags = 0; SVfloat (drop->edict, frags) = 0; drop->name[0] = 0; - memset (drop->userinfo, 0, sizeof (drop->userinfo)); + + Info_Destroy (drop->userinfo); + drop->userinfo = 0; // send notification to all remaining clients SV_FullClientUpdate (drop, &sv.reliable_datagram); @@ -355,6 +357,12 @@ SV_CalcPing (client_t *cl) return ping * 1000; } +static int +make_info_string_filter (const char *key) +{ + return *key == '_' || Info_FilterForKey (key, client_info_filters); +} + /* SV_FullClientUpdate @@ -363,7 +371,7 @@ SV_CalcPing (client_t *cl) void SV_FullClientUpdate (client_t *client, sizebuf_t *buf) { - char info[MAX_INFO_STRING]; + char *info; int i; net_svc_updateuserinfo_t block; @@ -387,8 +395,8 @@ SV_FullClientUpdate (client_t *client, sizebuf_t *buf) MSG_WriteByte (buf, i); MSG_WriteFloat (buf, realtime - client->connection_started); - strncpy (info, client->userinfo, sizeof (info)); - Info_RemovePrefixedKeys (info, '_', client_info_filters); // server passwords, etc + info = client->userinfo ? Info_MakeString (client->userinfo, + make_info_string_filter) : ""; block.slot = i; block.userid = client->userid; @@ -405,7 +413,9 @@ SV_FullClientUpdate (client_t *client, sizebuf_t *buf) void SV_FullClientUpdateToClient (client_t *client, client_t *cl) { - ClientReliableCheckBlock (cl, 24 + strlen (client->userinfo)); + if (client->state < cs_connected) + return; + ClientReliableCheckBlock (cl, 24 + client->userinfo->cursize); if (cl->num_backbuf) { SV_FullClientUpdate (client, &cl->backbuf); ClientReliable_FinishWrite (cl); @@ -507,7 +517,7 @@ SVC_Status (void) con_printf_no_log = 1; Cmd_TokenizeString ("status"); SV_BeginRedirect (RD_PACKET); - SV_Printf ("%s\n", svs.info); + SV_Printf ("%s\n", Info_MakeString (svs.info, 0)); for (i = 0; i < MAX_CLIENTS; i++) { cl = &svs.clients[i]; if ((cl->state == cs_connected || cl->state == cs_spawned) @@ -670,7 +680,7 @@ SVC_GetChallenge (void) void SVC_DirectConnect (void) { - char userinfo[1024]; + info_t *userinfo; const char *s; client_t *cl, *newcl; client_t temp; @@ -695,12 +705,10 @@ SVC_DirectConnect (void) challenge = atoi (Cmd_Argv (3)); - // note an extra byte is needed to replace spectator key - strncpy (userinfo, Cmd_Argv (4), sizeof (userinfo) - 2); - userinfo[sizeof (userinfo) - 2] = 0; + userinfo = Info_ParseString (Cmd_Argv (4), 1023); // Validate the userinfo string. - if (!Info_Validate(userinfo)) { + if (!userinfo) { Netchan_OutOfBandPrint (net_from, "%c\nInvalid userinfo string.\n", A2C_PRINT); return; @@ -750,7 +758,7 @@ SVC_DirectConnect (void) return; } Info_RemoveKey (userinfo, "spectator"); // remove passwd - Info_SetValueForStarKey (userinfo, "*spectator", "1", MAX_INFO_STRING, + Info_SetValueForStarKey (userinfo, "*spectator", "1", !sv_highchars->int_val); spectator = true; } else { @@ -786,7 +794,7 @@ SVC_DirectConnect (void) if (*q > 31 && *q <= 127) *p++ = *q; } else - strncpy (newcl->userinfo, userinfo, sizeof (newcl->userinfo) - 1); + newcl->userinfo = userinfo; // if there is allready a slot for this ip, drop it for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) { @@ -1801,11 +1809,11 @@ SV_CheckVars (void) SV_Printf ("Updated needpass.\n"); if (!v) - Info_SetValueForKey (svs.info, "needpass", "", MAX_SERVERINFO_STRING, + Info_SetValueForKey (svs.info, "needpass", "", !sv_highchars->int_val); else Info_SetValueForKey (svs.info, "needpass", va ("%i", v), - MAX_SERVERINFO_STRING, !sv_highchars->int_val); + !sv_highchars->int_val); } /* @@ -2083,13 +2091,13 @@ SV_InitLocal (void) snprintf (localmodels[i], sizeof (localmodels[i]), "*%i", i); Info_SetValueForStarKey (svs.info, "*version", QW_VERSION, - MAX_SERVERINFO_STRING, !sv_highchars->int_val); + !sv_highchars->int_val); // Brand server as QF, with appropriate QSG standards version --KB Info_SetValueForStarKey (svs.info, "*qf_version", VERSION, - MAX_SERVERINFO_STRING, !sv_highchars->int_val); + !sv_highchars->int_val); Info_SetValueForStarKey (svs.info, "*qsg_version", QW_QSG_VERSION, - MAX_SERVERINFO_STRING, !sv_highchars->int_val); + !sv_highchars->int_val); CF_Init (); @@ -2242,7 +2250,7 @@ SV_ExtractFromUserinfo (client_t *cl) // set the name if (strcmp (newname, val) || strcmp (cl->name, newname)) { - Info_SetValueForKey (cl->userinfo, "name", newname, MAX_INFO_STRING, + Info_SetValueForKey (cl->userinfo, "name", newname, !sv_highchars->int_val); val = Info_ValueForKey (cl->userinfo, "name"); SVstring (cl->edict, netname) = PR_SetString (&sv_pr_state, newname); @@ -2353,6 +2361,9 @@ SV_Init (void) Sys_Init_Cvars (); Sys_Init (); + svs.info = Info_ParseString ("", MAX_SERVERINFO_STRING); + localinfo = Info_ParseString ("", MAX_LOCALINFO_STRING); + Cbuf_Init (); Cmd_Init (); SV_InitOperatorCommands (); diff --git a/qw/source/sv_pr_cmds.c b/qw/source/sv_pr_cmds.c index 6d73e5383..98b9c88cf 100644 --- a/qw/source/sv_pr_cmds.c +++ b/qw/source/sv_pr_cmds.c @@ -1361,11 +1361,10 @@ PF_setinfokey (progs_t *pr) net_svc_setinfo_t block; if (e1 == 0) { - Info_SetValueForKey (localinfo, key, value, MAX_LOCALINFO_STRING, - !sv_highchars->int_val); + Info_SetValueForKey (localinfo, key, value, !sv_highchars->int_val); } else if (e1 <= MAX_CLIENTS) { Info_SetValueForKey (svs.clients[e1 - 1].userinfo, key, value, - MAX_INFO_STRING, !sv_highchars->int_val); + !sv_highchars->int_val); SV_ExtractFromUserinfo (&svs.clients[e1 - 1]); if (Info_FilterForKey (key, client_info_filters)) { diff --git a/qw/source/sv_progs.c b/qw/source/sv_progs.c index 83601c032..abd6a815f 100644 --- a/qw/source/sv_progs.c +++ b/qw/source/sv_progs.c @@ -155,8 +155,7 @@ parse_field (progs_t *pr, const char *key, const char *value) if (strcaseequal (key, "skyname") // QuakeForge || strcaseequal (key, "sky") // Q2/DarkPlaces || strcaseequal (key, "qlsky")) { // QuakeLives - Info_SetValueForKey (svs.info, "skybox", "1", MAX_SERVERINFO_STRING, - !sv_highchars->int_val); + Info_SetValueForKey (svs.info, "skybox", "1", !sv_highchars->int_val); Cvar_Set (r_skyname, value); return 1; } diff --git a/qw/source/sv_sys_unix.c b/qw/source/sv_sys_unix.c index c91218e89..ad6dc1ea9 100644 --- a/qw/source/sv_sys_unix.c +++ b/qw/source/sv_sys_unix.c @@ -61,7 +61,7 @@ static const char rcsid[] = qboolean is_server = true; qboolean stdin_ready; server_static_t svs; -char *svs_info = svs.info; +info_t **svs_info = &svs.info; void Sys_Init (void) diff --git a/qw/source/sv_user.c b/qw/source/sv_user.c index 437e15cb7..999d3178c 100644 --- a/qw/source/sv_user.c +++ b/qw/source/sv_user.c @@ -141,7 +141,8 @@ SV_New_f (void) // send server info string MSG_WriteByte (&host_client->netchan.message, svc_stufftext); MSG_WriteString (&host_client->netchan.message, - va ("fullserverinfo \"%s\"\n", svs.info)); + va ("fullserverinfo \"%s\"\n", + Info_MakeString (svs.info, 0))); } /* @@ -1165,7 +1166,7 @@ SV_SetInfo_f (void) strcpy (oldval, Info_ValueForKey (host_client->userinfo, Cmd_Argv (1))); Info_SetValueForKey (host_client->userinfo, Cmd_Argv (1), Cmd_Argv (2), - MAX_INFO_STRING, !sv_highchars->int_val); + !sv_highchars->int_val); if (strequal (Info_ValueForKey (host_client->userinfo, Cmd_Argv (1)), oldval)) return; // key hasn't changed