]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - cvar.c
cvar: Don't memset cvar->aliases before it's even allocated
[xonotic/darkplaces.git] / cvar.c
diff --git a/cvar.c b/cvar.c
index 5ae8e521c53b6daf2231ceda3732606b1edbdecc..58562d6b642742e911d879ddc0fdc55dd50af0c4 100644 (file)
--- a/cvar.c
+++ b/cvar.c
@@ -1,5 +1,6 @@
 /*
 Copyright (C) 1996-1997 Id Software, Inc.
+Copyright (C) 2000-2021 DarkPlaces contributors
 
 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
@@ -22,82 +23,88 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "quakedef.h"
 
 const char *cvar_dummy_description = "custom cvar";
+static const char *cvar_null_string = "";
 
-cvar_t *cvar_vars = NULL;
-cvar_t *cvar_hashtable[CVAR_HASHSIZE];
-const char *cvar_null_string = "";
+cvar_state_t cvars_all;
+cvar_state_t cvars_null;
 
 /*
 ============
 Cvar_FindVar
 ============
 */
-cvar_t *Cvar_FindVar (const char *var_name)
+cvar_t *Cvar_FindVar(cvar_state_t *cvars, const char *var_name, int neededflags)
 {
        int hashindex;
-       cvar_t *var;
+       cvar_hash_t *hash;
 
        // use hash lookup to minimize search time
        hashindex = CRC_Block((const unsigned char *)var_name, strlen(var_name)) % CVAR_HASHSIZE;
-       for (var = cvar_hashtable[hashindex];var;var = var->nextonhashchain)
-               if (!strcmp (var_name, var->name))
-                       return var;
-
+       for (hash = cvars->hashtable[hashindex];hash;hash = hash->next)
+               if (!strcmp (var_name, hash->cvar->name) && (hash->cvar->flags & neededflags))
+                       return hash->cvar;
+               else
+                       for (char **alias = hash->cvar->aliases; alias && *alias; alias++)
+                               if (!strcmp (var_name, *alias) && (hash->cvar->flags & neededflags))
+                                       return hash->cvar;
        return NULL;
 }
 
-cvar_t *Cvar_FindVarAfter (const char *prev_var_name, int neededflags)
+cvar_t *Cvar_FindVarAfter(cvar_state_t *cvars, const char *prev_var_name, int neededflags)
 {
        cvar_t *var;
 
        if (*prev_var_name)
        {
-               var = Cvar_FindVar (prev_var_name);
+               var = Cvar_FindVar(cvars, prev_var_name, neededflags);
                if (!var)
                        return NULL;
                var = var->next;
        }
        else
-               var = cvar_vars;
+               var = cvars->vars;
 
        // search for the next cvar matching the needed flags
        while (var)
        {
-               if ((var->flags & neededflags) || !neededflags)
+               if (var->flags & neededflags)
                        break;
                var = var->next;
        }
        return var;
 }
 
-static cvar_t *Cvar_FindVarLink (const char *var_name, cvar_t **parent, cvar_t ***link, cvar_t **prev_alpha)
+static cvar_t *Cvar_FindVarLink(cvar_state_t *cvars, const char *var_name, cvar_t **parent, cvar_t ***link, cvar_t **prev_alpha, int neededflags)
 {
        int hashindex;
-       cvar_t *var;
+       cvar_hash_t *hash;
 
        // use hash lookup to minimize search time
-       hashindex = CRC_Block((const unsigned char *)var_name, strlen(var_name));
+       hashindex = CRC_Block((const unsigned char *)var_name, strlen(var_name)) % CVAR_HASHSIZE;
        if(parent) *parent = NULL;
        if(prev_alpha) *prev_alpha = NULL;
-       if(link) *link = &cvar_hashtable[hashindex];
-       for (var = cvar_hashtable[hashindex];var;var = var->nextonhashchain)
+       if(link) *link = &cvars->hashtable[hashindex]->cvar;
+       for (hash = cvars->hashtable[hashindex];hash;hash = hash->next)
        {
-               if (!strcmp (var_name, var->name))
-               {
-                       if(!prev_alpha || var == cvar_vars)
-                               return var;
-
-                       *prev_alpha = cvar_vars;
-                       // if prev_alpha happens to become NULL then there has been some inconsistency elsewhere
-                       // already - should I still insert '*prev_alpha &&' in the loop?
-                       while((*prev_alpha)->next != var)
-                               *prev_alpha = (*prev_alpha)->next;
-                       return var;
-               }
-               if(parent) *parent = var;
+               if (!strcmp (var_name, hash->cvar->name) && (hash->cvar->flags & neededflags))
+                       goto match;
+               else
+                       for (char **alias = hash->cvar->aliases; alias && *alias; alias++)
+                               if (!strcmp (var_name, *alias) && (hash->cvar->flags & neededflags))
+                                       goto match;
+               if(parent) *parent = hash->cvar;
        }
-
        return NULL;
+match:
+       if(!prev_alpha || hash->cvar == cvars->vars)
+               return hash->cvar;
+
+       *prev_alpha = cvars->vars;
+       // if prev_alpha happens to become NULL then there has been some inconsistency elsewhere
+       // already - should I still insert '*prev_alpha &&' in the loop?
+       while((*prev_alpha)->next != hash->cvar)
+               *prev_alpha = (*prev_alpha)->next;
+       return hash->cvar;
 }
 
 /*
@@ -105,19 +112,19 @@ static cvar_t *Cvar_FindVarLink (const char *var_name, cvar_t **parent, cvar_t *
 Cvar_VariableValue
 ============
 */
-float Cvar_VariableValueOr (const char *var_name, float def)
+float Cvar_VariableValueOr(cvar_state_t *cvars, const char *var_name, float def, int neededflags)
 {
        cvar_t *var;
 
-       var = Cvar_FindVar (var_name);
+       var = Cvar_FindVar(cvars, var_name, neededflags);
        if (!var)
                return def;
        return atof (var->string);
 }
 
-float Cvar_VariableValue (const char *var_name)
+float Cvar_VariableValue(cvar_state_t *cvars, const char *var_name, int neededflags)
 {
-       return Cvar_VariableValueOr(var_name, 0);
+       return Cvar_VariableValueOr(cvars, var_name, 0, neededflags);
 }
 
 /*
@@ -125,19 +132,19 @@ float Cvar_VariableValue (const char *var_name)
 Cvar_VariableString
 ============
 */
-const char *Cvar_VariableStringOr (const char *var_name, const char *def)
+const char *Cvar_VariableStringOr(cvar_state_t *cvars, const char *var_name, const char *def, int neededflags)
 {
        cvar_t *var;
 
-       var = Cvar_FindVar (var_name);
+       var = Cvar_FindVar(cvars, var_name, neededflags);
        if (!var)
                return def;
        return var->string;
 }
 
-const char *Cvar_VariableString (const char *var_name)
+const char *Cvar_VariableString(cvar_state_t *cvars, const char *var_name, int neededflags)
 {
-       return Cvar_VariableStringOr(var_name, cvar_null_string);
+       return Cvar_VariableStringOr(cvars, var_name, cvar_null_string, neededflags);
 }
 
 /*
@@ -145,11 +152,11 @@ const char *Cvar_VariableString (const char *var_name)
 Cvar_VariableDefString
 ============
 */
-const char *Cvar_VariableDefString (const char *var_name)
+const char *Cvar_VariableDefString(cvar_state_t *cvars, const char *var_name, int neededflags)
 {
        cvar_t *var;
 
-       var = Cvar_FindVar (var_name);
+       var = Cvar_FindVar(cvars, var_name, neededflags);
        if (!var)
                return cvar_null_string;
        return var->defstring;
@@ -160,11 +167,11 @@ const char *Cvar_VariableDefString (const char *var_name)
 Cvar_VariableDescription
 ============
 */
-const char *Cvar_VariableDescription (const char *var_name)
+const char *Cvar_VariableDescription(cvar_state_t *cvars, const char *var_name, int neededflags)
 {
        cvar_t *var;
 
-       var = Cvar_FindVar (var_name);
+       var = Cvar_FindVar(cvars, var_name, neededflags);
        if (!var)
                return cvar_null_string;
        return var->description;
@@ -176,7 +183,7 @@ const char *Cvar_VariableDescription (const char *var_name)
 Cvar_CompleteVariable
 ============
 */
-const char *Cvar_CompleteVariable (const char *partial)
+const char *Cvar_CompleteVariable(cvar_state_t *cvars, const char *partial, int neededflags)
 {
        cvar_t          *cvar;
        size_t          len;
@@ -187,8 +194,8 @@ const char *Cvar_CompleteVariable (const char *partial)
                return NULL;
 
 // check functions
-       for (cvar=cvar_vars ; cvar ; cvar=cvar->next)
-               if (!strncasecmp (partial,cvar->name, len))
+       for (cvar=cvars->vars ; cvar ; cvar=cvar->next)
+               if (!strncasecmp (partial,cvar->name, len) && (cvar->flags & neededflags))
                        return cvar->name;
 
        return NULL;
@@ -203,7 +210,7 @@ const char *Cvar_CompleteVariable (const char *partial)
        Thanks to Fett erich@heintz.com
 
 */
-int Cvar_CompleteCountPossible (const char *partial)
+int Cvar_CompleteCountPossible(cvar_state_t *cvars, const char *partial, int neededflags)
 {
        cvar_t  *cvar;
        size_t  len;
@@ -216,10 +223,14 @@ int Cvar_CompleteCountPossible (const char *partial)
                return  0;
 
        // Loop through the cvars and count all possible matches
-       for (cvar = cvar_vars; cvar; cvar = cvar->next)
-               if (!strncasecmp(partial, cvar->name, len))
+       for (cvar = cvars->vars; cvar; cvar = cvar->next)
+               if (!strncasecmp(partial, cvar->name, len) && (cvar->flags & neededflags))
                        h++;
-
+               else
+                       for (char **alias = cvar->aliases; alias && *alias; alias++)
+                               if (!strncasecmp(partial, *alias, len) && (cvar->flags & neededflags))
+                                       h++;
+               
        return h;
 }
 
@@ -232,45 +243,71 @@ int Cvar_CompleteCountPossible (const char *partial)
        Thanks to taniwha
 
 */
-const char **Cvar_CompleteBuildList (const char *partial)
+const char **Cvar_CompleteBuildList(cvar_state_t *cvars, const char *partial, int neededflags)
 {
        const cvar_t *cvar;
        size_t len = 0;
        size_t bpos = 0;
-       size_t sizeofbuf = (Cvar_CompleteCountPossible (partial) + 1) * sizeof (const char *);
+       size_t sizeofbuf = (Cvar_CompleteCountPossible(cvars, partial, neededflags) + 1) * sizeof(const char *);
        const char **buf;
 
        len = strlen(partial);
-       buf = (const char **)Mem_Alloc(tempmempool, sizeofbuf + sizeof (const char *));
+       buf = (const char **)Mem_Alloc(tempmempool, sizeofbuf + sizeof(const char *));
        // Loop through the alias list and print all matches
-       for (cvar = cvar_vars; cvar; cvar = cvar->next)
-               if (!strncasecmp(partial, cvar->name, len))
+       for (cvar = cvars->vars; cvar; cvar = cvar->next)
+               if (!strncasecmp(partial, cvar->name, len) && (cvar->flags & neededflags))
                        buf[bpos++] = cvar->name;
+               else
+                       for (char **alias = cvar->aliases; alias && *alias; alias++)
+                               if (!strncasecmp(partial, *alias, len) && (cvar->flags & neededflags))
+                                       buf[bpos++] = *alias;
+               
 
        buf[bpos] = NULL;
        return buf;
 }
 
-// written by LordHavoc
-void Cvar_CompleteCvarPrint (const char *partial)
+void Cvar_PrintHelp(cvar_t *cvar, const char *name, qbool full)
+{
+       // Aliases are purple, cvars are yellow
+       if (strcmp(cvar->name, name))
+               Con_Printf("^6");
+       else
+               Con_Printf("^3");
+       Con_Printf("%s^7 is \"%s\" [\"%s\"]", name, ((cvar->flags & CF_PRIVATE) ? "********"/*hunter2*/ : cvar->string), cvar->defstring);
+       if (strcmp(cvar->name, name))
+               Con_Printf(" (also ^3%s^7)", cvar->name);
+       if (full)
+               Con_Printf(" %s", cvar->description);
+       Con_Printf("\n");
+}
+
+// written by LadyHavoc
+void Cvar_CompleteCvarPrint(cvar_state_t *cvars, const char *partial, int neededflags)
 {
        cvar_t *cvar;
        size_t len = strlen(partial);
        // Loop through the command list and print all matches
-       for (cvar = cvar_vars; cvar; cvar = cvar->next)
-               if (!strncasecmp(partial, cvar->name, len))
-                       Con_Printf ("^3%s^7 is \"%s\" [\"%s\"] %s\n", cvar->name, cvar->string, cvar->defstring, cvar->description);
+       for (cvar = cvars->vars; cvar; cvar = cvar->next)
+               if (!strncasecmp(partial, cvar->name, len) && (cvar->flags & neededflags))
+                       Cvar_PrintHelp(cvar, cvar->name, true);
+               else
+                       for (char **alias = cvar->aliases; alias && *alias; alias++)
+                               if (!strncasecmp (partial, *alias, len) && (cvar->flags & neededflags))
+                                       Cvar_PrintHelp(cvar, *alias, true);
+
+               
 }
 
 // check if a cvar is held by some progs
-static qboolean Cvar_IsAutoCvar(cvar_t *var)
+static qbool Cvar_IsAutoCvar(cvar_t *var)
 {
        int i;
        prvm_prog_t *prog;
        for (i = 0;i < PRVM_PROG_MAX;i++)
        {
                prog = &prvm_prog_list[i];
-               if (prog->loaded && var->globaldefindex_progid[i] == prog->id)
+               if (prog->loaded && var->globaldefindex[i] >= 0)
                        return true;
        }
        return false;
@@ -287,7 +324,7 @@ static void Cvar_UpdateAutoCvar(cvar_t *var)
        for (i = 0;i < PRVM_PROG_MAX;i++)
        {
                prog = &prvm_prog_list[i];
-               if (prog->loaded && var->globaldefindex_progid[i] == prog->id)
+               if (prog->loaded && var->globaldefindex[i] >= 0)
                {
                        // MUST BE SYNCED WITH prvm_edict.c PRVM_LoadProgs
                        switch(prog->globaldefs[var->globaldefindex[i]].type & ~DEF_SAVEGLOBAL)
@@ -322,13 +359,25 @@ static void Cvar_UpdateAutoCvar(cvar_t *var)
 }
 
 // called after loading a savegame
-void Cvar_UpdateAllAutoCvars(void)
+void Cvar_UpdateAllAutoCvars(cvar_state_t *cvars)
 {
        cvar_t *var;
-       for (var = cvar_vars ; var ; var = var->next)
+       for (var = cvars->vars ; var ; var = var->next)
                Cvar_UpdateAutoCvar(var);
 }
 
+void Cvar_Callback(cvar_t *var)
+{
+       if (var == NULL)
+       {
+               Con_Print("Cvar_Callback: var == NULL\n");
+               return;
+       }
+
+       if(var->callback)
+               var->callback(var);
+}
+
 /*
 ============
 Cvar_Set
@@ -337,16 +386,15 @@ Cvar_Set
 extern cvar_t sv_disablenotify;
 static void Cvar_SetQuick_Internal (cvar_t *var, const char *value)
 {
-       qboolean changed;
+       qbool changed;
        size_t valuelen;
-       char vabuf[1024];
 
        changed = strcmp(var->string, value) != 0;
-       // LordHavoc: don't reallocate when there is no change
+       // LadyHavoc: don't reallocate when there is no change
        if (!changed)
                return;
 
-       // LordHavoc: don't reallocate when the buffer is the same size
+       // LadyHavoc: don't reallocate when the buffer is the same size
        valuelen = strlen(value);
        if (!var->string || strlen(var->string) != valuelen)
        {
@@ -357,11 +405,11 @@ static void Cvar_SetQuick_Internal (cvar_t *var, const char *value)
        memcpy ((char *)var->string, value, valuelen + 1);
        var->value = atof (var->string);
        var->integer = (int) var->value;
-       if ((var->flags & CVAR_NOTIFY) && changed && sv.active && !sv_disablenotify.integer)
-               SV_BroadcastPrintf("\"%s\" changed to \"%s\"\n", var->name, var->string);
+       if ((var->flags & CF_NOTIFY) && sv.active && !sv_disablenotify.integer)
+               SV_BroadcastPrintf("\003^3Server cvar \"%s\" changed to \"%s\"\n", var->name, var->string);
 #if 0
        // TODO: add infostring support to the server?
-       if ((var->flags & CVAR_SERVERINFO) && changed && sv.active)
+       if ((var->flags & CF_SERVERINFO) && changed && sv.active)
        {
                InfoString_SetValue(svs.serverinfo, sizeof(svs.serverinfo), var->name, var->string);
                if (sv.active)
@@ -372,52 +420,13 @@ static void Cvar_SetQuick_Internal (cvar_t *var, const char *value)
                }
        }
 #endif
-       if ((var->flags & CVAR_USERINFO) && cls.state != ca_dedicated)
+       if (var->flags & CF_USERINFO)
                CL_SetInfo(var->name, var->string, true, false, false, false);
-       else if ((var->flags & CVAR_NQUSERINFOHACK) && cls.state != ca_dedicated)
-       {
-               // update the cls.userinfo to have proper values for the
-               // silly nq config variables.
-               //
-               // this is done when these variables are changed rather than at
-               // connect time because if the user or code checks the userinfo and it
-               // holds weird values it may cause confusion...
-               if (!strcmp(var->name, "_cl_color"))
-               {
-                       int top = (var->integer >> 4) & 15, bottom = var->integer & 15;
-                       CL_SetInfo("topcolor", va(vabuf, sizeof(vabuf), "%i", top), true, false, false, false);
-                       CL_SetInfo("bottomcolor", va(vabuf, sizeof(vabuf), "%i", bottom), true, false, false, false);
-                       if (cls.protocol != PROTOCOL_QUAKEWORLD && cls.netcon)
-                       {
-                               MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
-                               MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "color %i %i", top, bottom));
-                       }
-               }
-               else if (!strcmp(var->name, "_cl_rate"))
-                       CL_SetInfo("rate", va(vabuf, sizeof(vabuf), "%i", var->integer), true, false, false, false);
-               else if (!strcmp(var->name, "_cl_rate_burstsize"))
-                       CL_SetInfo("rate_burstsize", va(vabuf, sizeof(vabuf), "%i", var->integer), true, false, false, false);
-               else if (!strcmp(var->name, "_cl_playerskin"))
-                       CL_SetInfo("playerskin", var->string, true, false, false, false);
-               else if (!strcmp(var->name, "_cl_playermodel"))
-                       CL_SetInfo("playermodel", var->string, true, false, false, false);
-               else if (!strcmp(var->name, "_cl_name"))
-                       CL_SetInfo("name", var->string, true, false, false, false);
-               else if (!strcmp(var->name, "rcon_secure"))
-               {
-                       // whenever rcon_secure is changed to 0, clear rcon_password for
-                       // security reasons (prevents a send-rcon-password-as-plaintext
-                       // attack based on NQ protocol session takeover and svc_stufftext)
-                       if(var->integer <= 0)
-                               Cvar_Set("rcon_password", "");
-               }
-#ifdef CONFIG_MENU
-               else if (!strcmp(var->name, "net_slist_favorites"))
-                       NetConn_UpdateFavorites();
-#endif
-       }
 
        Cvar_UpdateAutoCvar(var);
+
+       // Call the function stored in the cvar for bounds checking, cleanup, etc
+       Cvar_Callback(var);
 }
 
 void Cvar_SetQuick (cvar_t *var, const char *value)
@@ -434,10 +443,10 @@ void Cvar_SetQuick (cvar_t *var, const char *value)
        Cvar_SetQuick_Internal(var, value);
 }
 
-void Cvar_Set (const char *var_name, const char *value)
+void Cvar_Set(cvar_state_t *cvars, const char *var_name, const char *value)
 {
        cvar_t *var;
-       var = Cvar_FindVar (var_name);
+       var = Cvar_FindVar(cvars, var_name, ~0);
        if (var == NULL)
        {
                Con_Printf("Cvar_Set: variable %s not found\n", var_name);
@@ -462,7 +471,7 @@ void Cvar_SetValueQuick(cvar_t *var, float value)
        Cvar_SetQuick(var, val);
 }
 
-void Cvar_SetValue(const char *var_name, float value)
+void Cvar_SetValue(cvar_state_t *cvars, const char *var_name, float value)
 {
        char val[MAX_INPUTLINE];
 
@@ -470,7 +479,94 @@ void Cvar_SetValue(const char *var_name, float value)
                dpsnprintf(val, sizeof(val), "%i", (int)value);
        else
                dpsnprintf(val, sizeof(val), "%f", value);
-       Cvar_Set(var_name, val);
+       Cvar_Set(cvars, var_name, val);
+}
+
+void Cvar_RegisterCallback(cvar_t *variable, void (*callback)(cvar_t *))
+{
+       if (variable == NULL)
+       {
+               Con_Print("Cvar_RegisterCallback: var == NULL\n");
+               return;
+       }
+       variable->callback = callback;
+}
+
+void Cvar_RegisterAlias(cvar_t *variable, const char *alias )
+{
+       cvar_state_t *cvars = &cvars_all;
+       cvar_hash_t *hash;
+       int hashindex;
+
+       if(!*alias)
+       {
+               Con_Printf("Cvar_RegisterAlias: invalid alias name\n");
+               return;
+       }
+
+       // check for overlap with a command
+       if (Cmd_Exists(cmd_local, alias))
+       {
+               Con_Printf("Cvar_RegisterAlias: %s is a command\n", alias);
+               return;
+       }
+
+       if(Cvar_FindVar(&cvars_all, alias, 0))
+       {
+               Con_Printf("Cvar_RegisterAlias: %s is a cvar\n", alias);
+               return;
+       }
+
+       if(!variable->aliases)
+               variable->aliases = (char **)Z_Malloc(sizeof(char *) * 2); // For NULL terminator
+       else
+               variable->aliases = (char **)Mem_Realloc(zonemempool, variable->aliases, sizeof(char *) * (variable->aliases_size + 1));
+       
+       variable->aliases[variable->aliases_size + 1] = NULL;
+       
+       // Add to it
+       variable->aliases[variable->aliases_size] = (char *)Z_Malloc(strlen(alias) + 1);
+       memcpy(variable->aliases[variable->aliases_size], alias, strlen(alias) + 1);
+       variable->aliases_size++;
+
+       // link to head of list in this hash table index
+       hash = (cvar_hash_t *)Z_Malloc(sizeof(cvar_hash_t));
+       hashindex = CRC_Block((const unsigned char *)alias, strlen(alias)) % CVAR_HASHSIZE;
+       hash->next = cvars->hashtable[hashindex];
+       cvars->hashtable[hashindex] = hash;
+       hash->cvar = variable;
+}
+
+/*
+============
+Cvar_Link
+
+Links a variable to the variable list and hashtable
+============
+*/
+static void Cvar_Link(cvar_t *variable, cvar_state_t *cvars)
+{
+       cvar_t *current, *next;
+       cvar_hash_t *hash;
+       int hashindex;
+       /*
+        * Link the variable in
+        * alphanumerical order
+        */
+       for( current = NULL, next = cvars->vars ; next && strcmp( next->name, variable->name ) < 0 ; current = next, next = next->next )
+               ;
+       if(current)
+               current->next = variable;
+       else
+               cvars->vars = variable;
+       variable->next = next;
+
+       // link to head of list in this hash table index
+       hash = (cvar_hash_t *)Z_Malloc(sizeof(cvar_hash_t));
+       hashindex = CRC_Block((const unsigned char *)variable->name, strlen(variable->name)) % CVAR_HASHSIZE;
+       hash->next = cvars->hashtable[hashindex];
+       hash->cvar = variable;
+       cvars->hashtable[hashindex] = hash;
 }
 
 /*
@@ -482,19 +578,33 @@ Adds a freestanding variable to the variable list.
 */
 void Cvar_RegisterVariable (cvar_t *variable)
 {
-       int hashindex;
-       cvar_t *current, *next, *cvar;
-       char *oldstr;
-       size_t alloclen;
+       cvar_state_t *cvars = NULL;
+       cvar_t *current, *cvar;
+       int i;
+
+       switch (variable->flags & (CF_CLIENT | CF_SERVER))
+       {
+       case CF_CLIENT:
+       case CF_SERVER:
+       case CF_CLIENT | CF_SERVER:
+               cvars = &cvars_all;
+               break;
+       case 0:
+               Sys_Error("Cvar_RegisterVariable({\"%s\", \"%s\", %i}) with no CF_CLIENT | CF_SERVER flags\n", variable->name, variable->string, variable->flags);
+               break;
+       default:
+               Sys_Error("Cvar_RegisterVariable({\"%s\", \"%s\", %i}) with weird CF_CLIENT | CF_SERVER flags\n", variable->name, variable->string, variable->flags);
+               break;
+       }
 
        if (developer_extra.integer)
                Con_DPrintf("Cvar_RegisterVariable({\"%s\", \"%s\", %i});\n", variable->name, variable->string, variable->flags);
 
-// first check to see if it has already been defined
-       cvar = Cvar_FindVar (variable->name);
+       // first check to see if it has already been defined
+       cvar = Cvar_FindVar(cvars, variable->name, ~0);
        if (cvar)
        {
-               if (cvar->flags & CVAR_ALLOCATED)
+               if (cvar->flags & CF_ALLOCATED)
                {
                        if (developer_extra.integer)
                                Con_DPrintf("...  replacing existing allocated cvar {\"%s\", \"%s\", %i}\n", cvar->name, cvar->string, cvar->flags);
@@ -502,23 +612,26 @@ void Cvar_RegisterVariable (cvar_t *variable)
                        // (because the engine directly accesses fixed variables)
                        // NOTE: this isn't actually used currently
                        // (all cvars are registered before config parsing)
-                       variable->flags |= (cvar->flags & ~CVAR_ALLOCATED);
+                       variable->flags |= (cvar->flags & ~CF_ALLOCATED);
                        // cvar->string is now owned by variable instead
                        variable->string = cvar->string;
                        variable->defstring = cvar->defstring;
                        variable->value = atof (variable->string);
                        variable->integer = (int) variable->value;
+                       // Preserve autocvar status.
+                       memcpy(variable->globaldefindex, cvar->globaldefindex, sizeof(variable->globaldefindex));
+                       memcpy(variable->globaldefindex_stringno, cvar->globaldefindex_stringno, sizeof(variable->globaldefindex_stringno));
                        // replace cvar with this one...
                        variable->next = cvar->next;
-                       if (cvar_vars == cvar)
+                       if (cvars->vars == cvar)
                        {
                                // head of the list is easy to change
-                               cvar_vars = variable;
+                               cvars->vars = variable;
                        }
                        else
                        {
                                // otherwise find it somewhere in the list
-                               for (current = cvar_vars;current->next != cvar;current = current->next)
+                               for (current = cvars->vars;current->next != cvar;current = current->next)
                                        ;
                                current->next = variable;
                        }
@@ -533,38 +646,28 @@ void Cvar_RegisterVariable (cvar_t *variable)
                return;
        }
 
-// check for overlap with a command
-       if (Cmd_Exists (variable->name))
+       // check for overlap with a command
+       if (Cmd_Exists(cmd_local, variable->name))
        {
                Con_Printf("Cvar_RegisterVariable: %s is a command\n", variable->name);
                return;
        }
 
-// copy the value off, because future sets will Z_Free it
-       oldstr = (char *)variable->string;
-       alloclen = strlen(variable->string) + 1;
-       variable->string = (char *)Z_Malloc (alloclen);
-       memcpy ((char *)variable->string, oldstr, alloclen);
-       variable->defstring = (char *)Z_Malloc (alloclen);
-       memcpy ((char *)variable->defstring, oldstr, alloclen);
+       // copy the value off, because future sets will Z_Free it
+       variable->name = (char *)Mem_strdup(zonemempool, variable->name);
+       variable->string = (char *)Mem_strdup(zonemempool, variable->string);
+       variable->defstring = (char *)Mem_strdup(zonemempool, variable->string);
        variable->value = atof (variable->string);
        variable->integer = (int) variable->value;
+       variable->aliases = NULL;
+       variable->aliases_size = 0;
+       variable->initstate = NULL;
 
-// link the variable in
-// alphanumerical order
-       for( current = NULL, next = cvar_vars ; next && strcmp( next->name, variable->name ) < 0 ; current = next, next = next->next )
-               ;
-       if( current ) {
-               current->next = variable;
-       } else {
-               cvar_vars = variable;
-       }
-       variable->next = next;
+       // Mark it as not an autocvar.
+       for (i = 0;i < PRVM_PROG_MAX;i++)
+               variable->globaldefindex[i] = -1;
 
-       // link to head of list in this hash table index
-       hashindex = CRC_Block((const unsigned char *)variable->name, strlen(variable->name)) % CVAR_HASHSIZE;
-       variable->nextonhashchain = cvar_hashtable[hashindex];
-       cvar_hashtable[hashindex] = variable;
+       Cvar_Link(variable, cvars);
 }
 
 /*
@@ -574,21 +677,21 @@ Cvar_Get
 Adds a newly allocated variable to the variable list or sets its value.
 ============
 */
-cvar_t *Cvar_Get (const char *name, const char *value, int flags, const char *newdescription)
+cvar_t *Cvar_Get(cvar_state_t *cvars, const char *name, const char *value, int flags, const char *newdescription)
 {
-       int hashindex;
-       cvar_t *current, *next, *cvar;
+       cvar_t *cvar;
+       int i;
 
        if (developer_extra.integer)
                Con_DPrintf("Cvar_Get(\"%s\", \"%s\", %i);\n", name, value, flags);
 
-// first check to see if it has already been defined
-       cvar = Cvar_FindVar (name);
+       // first check to see if it has already been defined
+       cvar = Cvar_FindVar(cvars, name, ~0);
        if (cvar)
        {
                cvar->flags |= flags;
                Cvar_SetQuick_Internal (cvar, value);
-               if(newdescription && (cvar->flags & CVAR_ALLOCATED))
+               if(newdescription && (cvar->flags & CF_ALLOCATED))
                {
                        if(cvar->description != cvar_dummy_description)
                                Z_Free((char *)cvar->description);
@@ -601,54 +704,60 @@ cvar_t *Cvar_Get (const char *name, const char *value, int flags, const char *ne
                return cvar;
        }
 
-// check for pure evil
+       // check for pure evil
        if (!*name)
        {
                Con_Printf("Cvar_Get: invalid variable name\n");
                return NULL;
        }
 
-// check for overlap with a command
-       if (Cmd_Exists (name))
+       // check for overlap with a command
+       if (Cmd_Exists(cmd_local, name))
        {
                Con_Printf("Cvar_Get: %s is a command\n", name);
                return NULL;
        }
 
-// allocate a new cvar, cvar name, and cvar string
-// TODO: factorize the following code with the one at the end of Cvar_RegisterVariable()
-// FIXME: these never get Z_Free'd
+       // allocate a new cvar, cvar name, and cvar string
+       // TODO: factorize the following code with the one at the end of Cvar_RegisterVariable()
+       // FIXME: these never get Z_Free'd
        cvar = (cvar_t *)Z_Malloc(sizeof(cvar_t));
-       cvar->flags = flags | CVAR_ALLOCATED;
+       cvar->flags = flags | CF_ALLOCATED;
        cvar->name = (char *)Mem_strdup(zonemempool, name);
        cvar->string = (char *)Mem_strdup(zonemempool, value);
        cvar->defstring = (char *)Mem_strdup(zonemempool, value);
        cvar->value = atof (cvar->string);
        cvar->integer = (int) cvar->value;
+       cvar->aliases = NULL;
+       cvar->aliases_size = 0;
+       cvar->initstate = NULL;
 
        if(newdescription && *newdescription)
                cvar->description = (char *)Mem_strdup(zonemempool, newdescription);
        else
                cvar->description = cvar_dummy_description; // actually checked by VM_cvar_type
 
-// link the variable in
-// alphanumerical order
-       for( current = NULL, next = cvar_vars ; next && strcmp( next->name, cvar->name ) < 0 ; current = next, next = next->next )
-               ;
-       if( current )
-               current->next = cvar;
-       else
-               cvar_vars = cvar;
-       cvar->next = next;
+       // Mark it as not an autocvar.
+       for (i = 0;i < PRVM_PROG_MAX;i++)
+               cvar->globaldefindex[i] = -1;
 
-       // link to head of list in this hash table index
-       hashindex = CRC_Block((const unsigned char *)cvar->name, strlen(cvar->name)) % CVAR_HASHSIZE;
-       cvar->nextonhashchain = cvar_hashtable[hashindex];
-       cvar_hashtable[hashindex] = cvar;
+       Cvar_Link(cvar, cvars);
 
        return cvar;
 }
 
+qbool Cvar_Readonly (cvar_t *var, const char *cmd_name)
+{
+       if (var->flags & CF_READONLY)
+       {
+               if(cmd_name)
+                       Con_Printf("%s: ",cmd_name);
+               Con_Printf("%s", var->name);
+               Con_Printf(" is read-only\n");
+               return true;
+       }
+       return false;
+}
 
 /*
 ============
@@ -657,58 +766,57 @@ Cvar_Command
 Handles variable inspection and changing from the console
 ============
 */
-qboolean       Cvar_Command (void)
+qbool  Cvar_Command (cmd_state_t *cmd)
 {
+       cvar_state_t    *cvars = cmd->cvars;
        cvar_t                  *v;
 
-// check variables
-       v = Cvar_FindVar (Cmd_Argv(0));
+       // check variables
+       v = Cvar_FindVar(cvars, Cmd_Argv(cmd, 0), (cmd->cvars_flagsmask));
        if (!v)
                return false;
 
-// perform a variable print or set
-       if (Cmd_Argc() == 1)
+       // perform a variable print or set
+       if (Cmd_Argc(cmd) == 1)
        {
-               Con_Printf("\"%s\" is \"%s\" [\"%s\"]\n", v->name, ((v->flags & CVAR_PRIVATE) ? "********"/*hunter2*/ : v->string), v->defstring);
+               Cvar_PrintHelp(v, Cmd_Argv(cmd, 0), true);
                return true;
        }
 
        if (developer_extra.integer)
                Con_DPrint("Cvar_Command: ");
 
-       if (v->flags & CVAR_READONLY)
-       {
-               Con_Printf("%s is read-only\n", v->name);
+       if(Cvar_Readonly(v, NULL))
                return true;
-       }
-       Cvar_Set (v->name, Cmd_Argv(1));
+
+       Cvar_SetQuick(v, Cmd_Argv(cmd, 1));
        if (developer_extra.integer)
                Con_DPrint("\n");
        return true;
 }
 
-
-void Cvar_UnlockDefaults (void)
+void Cvar_UnlockDefaults(cmd_state_t *cmd)
 {
+       cvar_state_t *cvars = cmd->cvars;
        cvar_t *var;
        // unlock the default values of all cvars
-       for (var = cvar_vars ; var ; var = var->next)
-               var->flags &= ~CVAR_DEFAULTSET;
+       for (var = cvars->vars ; var ; var = var->next)
+               var->flags &= ~CF_DEFAULTSET;
 }
 
-
-void Cvar_LockDefaults_f (void)
+void Cvar_LockDefaults_f(cmd_state_t *cmd)
 {
+       cvar_state_t *cvars = cmd->cvars;
        cvar_t *var;
        // lock in the default values of all cvars
-       for (var = cvar_vars ; var ; var = var->next)
+       for (var = cvars->vars ; var ; var = var->next)
        {
-               if (!(var->flags & CVAR_DEFAULTSET))
+               if (!(var->flags & CF_DEFAULTSET))
                {
                        size_t alloclen;
 
                        //Con_Printf("locking cvar %s (%s -> %s)\n", var->name, var->string, var->defstring);
-                       var->flags |= CVAR_DEFAULTSET;
+                       var->flags |= CF_DEFAULTSET;
                        Z_Free((char *)var->defstring);
                        alloclen = strlen(var->string) + 1;
                        var->defstring = (char *)Z_Malloc(alloclen);
@@ -717,56 +825,51 @@ void Cvar_LockDefaults_f (void)
        }
 }
 
-void Cvar_SaveInitState(void)
+void Cvar_SaveInitState(cvar_state_t *cvars)
 {
        cvar_t *c;
-       for (c = cvar_vars;c;c = c->next)
+       for (c = cvars->vars;c;c = c->next)
        {
-               c->initstate = true;
-               c->initflags = c->flags;
-               c->initdefstring = Mem_strdup(zonemempool, c->defstring);
-               c->initstring = Mem_strdup(zonemempool, c->string);
-               c->initvalue = c->value;
-               c->initinteger = c->integer;
-               VectorCopy(c->vector, c->initvector);
+               c->initstate = (cvar_t *)Z_Malloc(sizeof(cvar_t));
+               memcpy(c->initstate, c, sizeof(cvar_t));
        }
 }
 
-void Cvar_RestoreInitState(void)
+void Cvar_RestoreInitState(cvar_state_t *cvars)
 {
        int hashindex;
        cvar_t *c, **cp;
        cvar_t *c2, **cp2;
-       for (cp = &cvar_vars;(c = *cp);)
+       for (cp = &cvars->vars;(c = *cp);)
        {
                if (c->initstate)
                {
                        // restore this cvar, it existed at init
-                       if (((c->flags ^ c->initflags) & CVAR_MAXFLAGSVAL)
-                        || strcmp(c->defstring ? c->defstring : "", c->initdefstring ? c->initdefstring : "")
-                        || strcmp(c->string ? c->string : "", c->initstring ? c->initstring : ""))
+                       if (((c->flags ^ c->initstate->flags) & CF_MAXFLAGSVAL)
+                        || strcmp(c->defstring ? c->defstring : "", c->initstate->defstring ? c->initstate->defstring : "")
+                        || strcmp(c->string ? c->string : "", c->initstate->string ? c->initstate->string : ""))
                        {
                                Con_DPrintf("Cvar_RestoreInitState: Restoring cvar \"%s\"\n", c->name);
                                if (c->defstring)
                                        Z_Free((char *)c->defstring);
-                               c->defstring = Mem_strdup(zonemempool, c->initdefstring);
+                               c->defstring = Mem_strdup(zonemempool, c->initstate->defstring);
                                if (c->string)
                                        Z_Free((char *)c->string);
-                               c->string = Mem_strdup(zonemempool, c->initstring);
+                               c->string = Mem_strdup(zonemempool, c->initstate->string);
                        }
-                       c->flags = c->initflags;
-                       c->value = c->initvalue;
-                       c->integer = c->initinteger;
-                       VectorCopy(c->initvector, c->vector);
+                       c->flags = c->initstate->flags;
+                       c->value = c->initstate->value;
+                       c->integer = c->initstate->integer;
+                       VectorCopy(c->initstate->vector, c->vector);
                        cp = &c->next;
                }
                else
                {
-                       if (!(c->flags & CVAR_ALLOCATED))
+                       if (!(c->flags & CF_ALLOCATED))
                        {
                                Con_DPrintf("Cvar_RestoreInitState: Unable to destroy cvar \"%s\", it was registered after init!\n", c->name);
                                // In this case, at least reset it to the default.
-                               if((c->flags & CVAR_NORESETTODEFAULTS) == 0)
+                               if((c->flags & CF_PERSISTENT) == 0)
                                        Cvar_SetQuick(c, c->defstring);
                                cp = &c->next;
                                continue;
@@ -775,7 +878,7 @@ void Cvar_RestoreInitState(void)
                        {
                                Con_DPrintf("Cvar_RestoreInitState: Unable to destroy cvar \"%s\", it is an autocvar used by running progs!\n", c->name);
                                // In this case, at least reset it to the default.
-                               if((c->flags & CVAR_NORESETTODEFAULTS) == 0)
+                               if((c->flags & CF_PERSISTENT) == 0)
                                        Cvar_SetQuick(c, c->defstring);
                                cp = &c->next;
                                continue;
@@ -784,15 +887,15 @@ void Cvar_RestoreInitState(void)
                        Con_DPrintf("Cvar_RestoreInitState: Destroying cvar \"%s\"\n", c->name);
                        // unlink struct from hash
                        hashindex = CRC_Block((const unsigned char *)c->name, strlen(c->name)) % CVAR_HASHSIZE;
-                       for (cp2 = &cvar_hashtable[hashindex];(c2 = *cp2);)
+                       for (cp2 = &cvars->hashtable[hashindex]->cvar;(c2 = *cp2);)
                        {
                                if (c2 == c)
                                {
-                                       *cp2 = c2->nextonhashchain;
+                                       *cp2 = cvars->hashtable[hashindex]->next->cvar;
                                        break;
                                }
                                else
-                                       cp2 = &c2->nextonhashchain;
+                                       cp2 = &cvars->hashtable[hashindex]->next->cvar;
                        }
                        // unlink struct from main list
                        *cp = c->next;
@@ -809,36 +912,43 @@ void Cvar_RestoreInitState(void)
        }
 }
 
-void Cvar_ResetToDefaults_All_f (void)
+void Cvar_ResetToDefaults_All_f(cmd_state_t *cmd)
 {
+       cvar_state_t *cvars = cmd->cvars;
        cvar_t *var;
        // restore the default values of all cvars
-       for (var = cvar_vars ; var ; var = var->next)
-               if((var->flags & CVAR_NORESETTODEFAULTS) == 0)
+       for (var = cvars->vars ; var ; var = var->next)
+       {
+               if((var->flags & CF_PERSISTENT) == 0)
                        Cvar_SetQuick(var, var->defstring);
+       }
 }
 
-
-void Cvar_ResetToDefaults_NoSaveOnly_f (void)
+void Cvar_ResetToDefaults_NoSaveOnly_f(cmd_state_t *cmd)
 {
+       cvar_state_t *cvars = cmd->cvars;
        cvar_t *var;
        // restore the default values of all cvars
-       for (var = cvar_vars ; var ; var = var->next)
-               if ((var->flags & (CVAR_NORESETTODEFAULTS | CVAR_SAVE)) == 0)
+       for (var = cvars->vars ; var ; var = var->next)
+       {
+               if ((var->flags & (CF_PERSISTENT | CF_ARCHIVE)) == 0)
                        Cvar_SetQuick(var, var->defstring);
+       }
 }
 
 
-void Cvar_ResetToDefaults_SaveOnly_f (void)
+void Cvar_ResetToDefaults_SaveOnly_f(cmd_state_t *cmd)
 {
+       cvar_state_t *cvars = cmd->cvars;
        cvar_t *var;
        // restore the default values of all cvars
-       for (var = cvar_vars ; var ; var = var->next)
-               if ((var->flags & (CVAR_NORESETTODEFAULTS | CVAR_SAVE)) == CVAR_SAVE)
+       for (var = cvars->vars ; var ; var = var->next)
+       {
+               if ((var->flags & (CF_PERSISTENT | CF_ARCHIVE)) == CF_ARCHIVE)
                        Cvar_SetQuick(var, var->defstring);
+       }
 }
 
-
 /*
 ============
 Cvar_WriteVariables
@@ -847,22 +957,22 @@ Writes lines containing "set variable value" for all variables
 with the archive flag set to true.
 ============
 */
-void Cvar_WriteVariables (qfile_t *f)
+void Cvar_WriteVariables (cvar_state_t *cvars, qfile_t *f)
 {
        cvar_t  *var;
        char buf1[MAX_INPUTLINE], buf2[MAX_INPUTLINE];
 
        // don't save cvars that match their default value
-       for (var = cvar_vars ; var ; var = var->next)
-               if ((var->flags & CVAR_SAVE) && (strcmp(var->string, var->defstring) || ((var->flags & CVAR_ALLOCATED) && !(var->flags & CVAR_DEFAULTSET))))
+       for (var = cvars->vars ; var ; var = var->next) {
+               if ((var->flags & CF_ARCHIVE) && (strcmp(var->string, var->defstring) || ((var->flags & CF_ALLOCATED) && !(var->flags & CF_DEFAULTSET))))
                {
                        Cmd_QuoteString(buf1, sizeof(buf1), var->name, "\"\\$", false);
                        Cmd_QuoteString(buf2, sizeof(buf2), var->string, "\"\\$", false);
-                       FS_Printf(f, "%s\"%s\" \"%s\"\n", var->flags & CVAR_ALLOCATED ? "seta " : "", buf1, buf2);
+                       FS_Printf(f, "%s\"%s\" \"%s\"\n", var->flags & CF_ALLOCATED ? "seta " : "", buf1, buf2);
                }
+       }
 }
 
-
 // Added by EvilTypeGuy eviltypeguy@qeradiant.com
 // 2000-01-09 CvarList command By Matthias "Maddes" Buecher, http://www.inside3d.com/qip/
 /*
@@ -870,132 +980,140 @@ void Cvar_WriteVariables (qfile_t *f)
 Cvar_List
 =========
 */
-void Cvar_List_f (void)
+void Cvar_List_f(cmd_state_t *cmd)
 {
+       cvar_state_t *cvars = cmd->cvars;
        cvar_t *cvar;
        const char *partial;
-       size_t len;
        int count;
-       qboolean ispattern;
+       qbool ispattern;
+       char vabuf[1024];
 
-       if (Cmd_Argc() > 1)
+       if (Cmd_Argc(cmd) > 1)
        {
-               partial = Cmd_Argv (1);
-               len = strlen(partial);
+               partial = Cmd_Argv(cmd, 1);
                ispattern = (strchr(partial, '*') || strchr(partial, '?'));
+               if(!ispattern)
+                       partial = va(vabuf, sizeof(vabuf), "%s*", partial);
        }
        else
        {
-               partial = NULL;
-               len = 0;
+               partial = va(vabuf, sizeof(vabuf), "*");
                ispattern = false;
        }
 
        count = 0;
-       for (cvar = cvar_vars; cvar; cvar = cvar->next)
+       for (cvar = cvars->vars; cvar; cvar = cvar->next)
        {
-               if (len && (ispattern ? !matchpattern_with_separator(cvar->name, partial, false, "", false) : strncmp (partial,cvar->name,len)))
-                       continue;
-
-               Con_Printf("%s is \"%s\" [\"%s\"] %s\n", cvar->name, ((cvar->flags & CVAR_PRIVATE) ? "********"/*hunter2*/ : cvar->string), cvar->defstring, cvar->description);
-               count++;
+               if (matchpattern_with_separator(cvar->name, partial, false, "", false))
+               {
+                       Cvar_PrintHelp(cvar, cvar->name, true);
+                       count++;
+               }
+               for (char **alias = cvar->aliases; alias && *alias; alias++)
+               {
+                       if (matchpattern_with_separator(*alias, partial, false, "", false))
+                       {
+                               Cvar_PrintHelp(cvar, *alias, true);
+                               count++;
+                       }
+               }
        }
 
-       if (len)
+       if (Cmd_Argc(cmd) > 1)
        {
                if(ispattern)
                        Con_Printf("%i cvar%s matching \"%s\"\n", count, (count > 1) ? "s" : "", partial);
                else
-                       Con_Printf("%i cvar%s beginning with \"%s\"\n", count, (count > 1) ? "s" : "", partial);
+                       Con_Printf("%i cvar%s beginning with \"%s\"\n", count, (count > 1) ? "s" : "", Cmd_Argv(cmd,1));
        }
        else
                Con_Printf("%i cvar(s)\n", count);
 }
 // 2000-01-09 CvarList command by Maddes
 
-void Cvar_Set_f (void)
+void Cvar_Set_f(cmd_state_t *cmd)
 {
+       cvar_state_t *cvars = cmd->cvars;
        cvar_t *cvar;
 
        // make sure it's the right number of parameters
-       if (Cmd_Argc() < 3)
+       if (Cmd_Argc(cmd) < 3)
        {
                Con_Printf("Set: wrong number of parameters, usage: set <variablename> <value> [<description>]\n");
                return;
        }
 
        // check if it's read-only
-       cvar = Cvar_FindVar(Cmd_Argv(1));
-       if (cvar && cvar->flags & CVAR_READONLY)
-       {
-               Con_Printf("Set: %s is read-only\n", cvar->name);
-               return;
-       }
+       cvar = Cvar_FindVar(cvars, Cmd_Argv(cmd, 1), ~0);
+       if (cvar)
+               if(Cvar_Readonly(cvar,"Set"))
+                       return;
 
        if (developer_extra.integer)
                Con_DPrint("Set: ");
 
        // all looks ok, create/modify the cvar
-       Cvar_Get(Cmd_Argv(1), Cmd_Argv(2), 0, Cmd_Argc() > 3 ? Cmd_Argv(3) : NULL);
+       Cvar_Get(cvars, Cmd_Argv(cmd, 1), Cmd_Argv(cmd, 2), cmd->cvars_flagsmask, Cmd_Argc(cmd) > 3 ? Cmd_Argv(cmd, 3) : NULL);
 }
 
-void Cvar_SetA_f (void)
+void Cvar_SetA_f(cmd_state_t *cmd)
 {
+       cvar_state_t *cvars = cmd->cvars;
        cvar_t *cvar;
 
        // make sure it's the right number of parameters
-       if (Cmd_Argc() < 3)
+       if (Cmd_Argc(cmd) < 3)
        {
                Con_Printf("SetA: wrong number of parameters, usage: seta <variablename> <value> [<description>]\n");
                return;
        }
 
        // check if it's read-only
-       cvar = Cvar_FindVar(Cmd_Argv(1));
-       if (cvar && cvar->flags & CVAR_READONLY)
-       {
-               Con_Printf("SetA: %s is read-only\n", cvar->name);
-               return;
-       }
+       cvar = Cvar_FindVar(cvars, Cmd_Argv(cmd, 1), ~0);
+       if (cvar)
+               if(Cvar_Readonly(cvar,"SetA"))
+                       return;
 
        if (developer_extra.integer)
                Con_DPrint("SetA: ");
 
        // all looks ok, create/modify the cvar
-       Cvar_Get(Cmd_Argv(1), Cmd_Argv(2), CVAR_SAVE, Cmd_Argc() > 3 ? Cmd_Argv(3) : NULL);
+       Cvar_Get(cvars, Cmd_Argv(cmd, 1), Cmd_Argv(cmd, 2), cmd->cvars_flagsmask | CF_ARCHIVE, Cmd_Argc(cmd) > 3 ? Cmd_Argv(cmd, 3) : NULL);
 }
 
-void Cvar_Del_f (void)
+void Cvar_Del_f(cmd_state_t *cmd)
 {
+       cvar_state_t *cvars = cmd->cvars;
+       int neededflags = ~0;
        int i;
-       cvar_t *cvar, *parent, **link, *prev;
+       cvar_t *parent, **link;
+       cvar_t *cvar, *prev;
 
-       if(Cmd_Argc() < 2)
+       if(Cmd_Argc(cmd) < 2)
        {
-               Con_Printf("Del: wrong number of parameters, useage: unset <variablename1> [<variablename2> ...]\n");
+               Con_Printf("%s: wrong number of parameters, usage: unset <variablename1> [<variablename2> ...]\n", Cmd_Argv(cmd, 0));
                return;
        }
-       for(i = 1; i < Cmd_Argc(); ++i)
+       for(i = 1; i < Cmd_Argc(cmd); ++i)
        {
-               cvar = Cvar_FindVarLink(Cmd_Argv(i), &parent, &link, &prev);
+               cvar = Cvar_FindVarLink(cvars, Cmd_Argv(cmd, i), &parent, &link, &prev, neededflags);
+
                if(!cvar)
                {
-                       Con_Printf("Del: %s is not defined\n", Cmd_Argv(i));
+                       Con_Printf("%s: %s is not defined\n", Cmd_Argv(cmd, 0), Cmd_Argv(cmd, i));
                        continue;
                }
-               if(cvar->flags & CVAR_READONLY)
-               {
-                       Con_Printf("Del: %s is read-only\n", cvar->name);
+               if(Cvar_Readonly(cvar, Cmd_Argv(cmd, 0)))
                        continue;
-               }
-               if(!(cvar->flags & CVAR_ALLOCATED))
+               if(!(cvar->flags & CF_ALLOCATED))
                {
-                       Con_Printf("Del: %s is static and cannot be deleted\n", cvar->name);
+                       Con_Printf("%s: %s is static and cannot be deleted\n", Cmd_Argv(cmd, 0), cvar->name);
                        continue;
                }
-               if(cvar == cvar_vars)
+               if(cvar == cvars->vars)
                {
-                       cvar_vars = cvar->next;
+                       cvars->vars = cvar->next;
                }
                else
                {
@@ -1005,10 +1123,9 @@ void Cvar_Del_f (void)
                }
 
                if(parent)
-                       parent->nextonhashchain = cvar->nextonhashchain;
+                       parent->next = cvar->next;
                else if(link)
-                       *link = cvar->nextonhashchain;
-
+                       *link = cvar->next;
                if(cvar->description != cvar_dummy_description)
                        Z_Free((char *)cvar->description);
 
@@ -1020,25 +1137,25 @@ void Cvar_Del_f (void)
 }
 
 #ifdef FILLALLCVARSWITHRUBBISH
-void Cvar_FillAll_f()
+void Cvar_FillAll_f(cmd_state_t *cmd)
 {
        char *buf, *p, *q;
        int n, i;
        cvar_t *var;
-       qboolean verify;
-       if(Cmd_Argc() != 2)
+       qbool verify;
+       if(Cmd_Argc(cmd) != 2)
        {
-               Con_Printf("Usage: %s length to plant rubbish\n", Cmd_Argv(0));
-               Con_Printf("Usage: %s -length to verify that the rubbish is still there\n", Cmd_Argv(0));
+               Con_Printf("Usage: %s length to plant rubbish\n", Cmd_Argv(cmd, 0));
+               Con_Printf("Usage: %s -length to verify that the rubbish is still there\n", Cmd_Argv(cmd, 0));
                return;
        }
-       n = atoi(Cmd_Argv(1));
+       n = atoi(Cmd_Argv(cmd, 1));
        verify = (n < 0);
        if(verify)
                n = -n;
        buf = Z_Malloc(n + 1);
        buf[n] = 0;
-       for(var = cvar_vars; var; var = var->next)
+       for(var = cvars->vars; var; var = var->next)
        {
                for(i = 0, p = buf, q = var->name; i < n; ++i)
                {