]> git.rm.cloudns.org Git - xonotic/darkplaces.git/commitdiff
cvar: Use the generic linked list for cvars. Made virtual cvars actual cvar_t's
authorCloudwalk <cloudwalk009@gmail.com>
Sun, 18 Jul 2021 04:34:11 +0000 (00:34 -0400)
committerCloudwalk <cloudwalk009@gmail.com>
Sun, 18 Jul 2021 04:34:11 +0000 (00:34 -0400)
* cvar_hash_t is gone
* Virtual cvars now use a linked list around their parent and have a
  pointer to their parent.
* Cvars will now store their own hashindex to make deletions from the
  hashtable easier. Implemented Cvar_Delete where this is leveraged.
  Cvar_FindVarLink is eliminated also. Not needed anymore.
* Implemented Cvar_DeleteVirtual and Cvar_DeleteVirtual_All
  to... delete virtual cvars.
* Eliminated redundancy of Cvar_SetQuick_Internal by merging it with
  Cvar_SetQuick.
* Misc cleanups

cl_cmd.c
cmd.c
cvar.c
cvar.h
prvm_cmds.c
prvm_edict.c

index 9277ad50964b77614057f9673895fd83a0cfd15b..d3a855be3e10ccb1b51e56066777c4176021a09e 100644 (file)
--- a/cl_cmd.c
+++ b/cl_cmd.c
@@ -211,7 +211,7 @@ static void CL_SendCvar_f(cmd_state_t *cmd)
                if(!c || (c->flags & CF_PRIVATE))
                        CL_ForwardToServer(va(vabuf, sizeof(vabuf), "sentcvar %s", cvarname));
                else
-                       CL_ForwardToServer(va(vabuf, sizeof(vabuf), "sentcvar %s \"%s\"", c->name, c->string));
+                       CL_ForwardToServer(va(vabuf, sizeof(vabuf), "sentcvar %s \"%s\"", c->name, c->parent ? c->parent->string : c->string));
                return;
        }
 }
diff --git a/cmd.c b/cmd.c
index abc512eef3a4e547ba72e24e07e1aaad43cbe961..ed76ba8769e68b20229ee4cacff776486f515084 100644 (file)
--- a/cmd.c
+++ b/cmd.c
@@ -925,6 +925,7 @@ static void Cmd_Toggle_f(cmd_state_t *cmd)
        { // Correct Arguments Specified
                // Acquire Potential CVar
                cvar_t* cvCVar = Cvar_FindVar(cmd->cvars, Cmd_Argv(cmd, 1), cmd->cvars_flagsmask);
+               cvCVar = cvCVar->parent ? cvCVar->parent : cvCVar;
 
                if(cvCVar != NULL)
                { // Valid CVar
@@ -1173,7 +1174,7 @@ static const char *Cmd_GetDirectCvarValue(cmd_state_t *cmd, const char *varname,
        }
 
        if((cvar = Cvar_FindVar(cmd->cvars, varname, cmd->cvars_flagsmask)) && !(cvar->flags & CF_PRIVATE))
-               return cvar->string;
+               return cvar->parent ? cvar->parent->string : cvar->string;
 
        return NULL;
 }
@@ -1579,24 +1580,15 @@ static void Cmd_Apropos_f(cmd_state_t *cmd)
                partial = va(vabuf, sizeof(vabuf), "*%s*", partial);
 
        count = 0;
-       for (cvar = cmd->cvars->vars; cvar; cvar = cvar->next)
+       List_For_Each_Entry(cvar, &cmd->cvars->vars->list, list)
        {
                if (matchpattern_with_separator(cvar->name, partial, true, "", false) ||
                    matchpattern_with_separator(cvar->description, partial, true, "", false))
                {
                        Con_Printf ("cvar ");
-                       Cvar_PrintHelp(cvar, cvar->name, true);
+                       Cvar_PrintHelp(cvar->parent ? cvar->parent : cvar, cvar->name, true);
                        count++;
                }
-               for (char **cvar_alias = cvar->aliases; cvar_alias && *cvar_alias; cvar_alias++)
-               {
-                       if (matchpattern_with_separator(*cvar_alias, partial, true, "", false))
-                       {
-                               Con_Printf ("cvar ");
-                               Cvar_PrintHelp(cvar, *cvar_alias, true);
-                               count++;
-                       }
-               }
        }
        for (func = cmd->userdefined->qc_functions; func; func = func->next)
        {
@@ -1636,6 +1628,8 @@ static cmd_state_t *Cmd_AddInterpreter(cmd_buf_t *cbuf, cvar_state_t *cvars, int
        cmd->null_string = "";
 
        cmd->cvars = cvars;
+       cmd->cvars->vars = (cvar_t *)Z_Malloc(sizeof(cvar_t));
+       cmd->cvars->vars->list.next = cmd->cvars->vars->list.prev = &cmd->cvars->vars->list;
        cmd->cvars_flagsmask = cvars_flagsmask;
        cmd->cmd_flags = cmds_flagsmask;
        cmd->userdefined = userdefined;
diff --git a/cvar.c b/cvar.c
index cbe8b0f6b56205446f0da1c285de48c6c25fcd74..98d2a666ab127b881ff14d02868e66b021cca403 100644 (file)
--- a/cvar.c
+++ b/cvar.c
@@ -36,17 +36,13 @@ Cvar_FindVar
 cvar_t *Cvar_FindVar(cvar_state_t *cvars, const char *var_name, int neededflags)
 {
        int hashindex;
-       cvar_hash_t *hash;
+       cvar_t *hash;
 
        // use hash lookup to minimize search time
        hashindex = CRC_Block((const unsigned char *)var_name, strlen(var_name)) % CVAR_HASHSIZE;
-       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;
+       for (hash = cvars->hashtable[hashindex];hash;hash = hash->hnext)
+               if (!strcmp (var_name, hash->name) && (hash->flags & neededflags))
+                       return hash;
        return NULL;
 }
 
@@ -59,54 +55,22 @@ cvar_t *Cvar_FindVarAfter(cvar_state_t *cvars, const char *prev_var_name, int ne
                var = Cvar_FindVar(cvars, prev_var_name, neededflags);
                if (!var)
                        return NULL;
-               var = var->next;
+               var = List_Next_Entry(var->parent ? var->parent : var, list);
        }
        else
                var = cvars->vars;
 
        // search for the next cvar matching the needed flags
-       while (var)
+       List_For_Each_Entry_From(var, &cvars->vars->list, list)
        {
+               if (var->parent)
+                       continue;
                if (var->flags & neededflags)
                        break;
-               var = var->next;
        }
        return var;
 }
 
-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_hash_t *hash;
-
-       // use hash lookup to minimize search time
-       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 = &cvars->hashtable[hashindex]->cvar;
-       for (hash = cvars->hashtable[hashindex];hash;hash = hash->next)
-       {
-               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;
-}
-
 /*
 ============
 Cvar_VariableValue
@@ -119,7 +83,7 @@ float Cvar_VariableValueOr(cvar_state_t *cvars, const char *var_name, float def,
        var = Cvar_FindVar(cvars, var_name, neededflags);
        if (!var)
                return def;
-       return atof (var->string);
+       return atof (var->parent ? var->parent->string : var->string);
 }
 
 float Cvar_VariableValue(cvar_state_t *cvars, const char *var_name, int neededflags)
@@ -139,7 +103,7 @@ const char *Cvar_VariableStringOr(cvar_state_t *cvars, const char *var_name, con
        var = Cvar_FindVar(cvars, var_name, neededflags);
        if (!var)
                return def;
-       return var->string;
+       return var->parent ? var->parent->string : var->string;
 }
 
 const char *Cvar_VariableString(cvar_state_t *cvars, const char *var_name, int neededflags)
@@ -159,7 +123,7 @@ const char *Cvar_VariableDefString(cvar_state_t *cvars, const char *var_name, in
        var = Cvar_FindVar(cvars, var_name, neededflags);
        if (!var)
                return cvar_null_string;
-       return var->defstring;
+       return var->parent ? var->parent->defstring : var->defstring;
 }
 
 /*
@@ -194,14 +158,13 @@ const char *Cvar_CompleteVariable(cvar_state_t *cvars, const char *partial, int
                return NULL;
 
 // check functions
-       for (cvar=cvars->vars ; cvar ; cvar=cvar->next)
+       List_For_Each_Entry(cvar, &cvars->vars->list, list)
                if (!strncasecmp (partial,cvar->name, len) && (cvar->flags & neededflags))
                        return cvar->name;
 
        return NULL;
 }
 
-
 /*
        CVar_CompleteCountPossible
 
@@ -223,14 +186,9 @@ int Cvar_CompleteCountPossible(cvar_state_t *cvars, const char *partial, int nee
                return  0;
 
        // Loop through the cvars and count all possible matches
-       for (cvar = cvars->vars; cvar; cvar = cvar->next)
+       List_For_Each_Entry(cvar, &cvars->vars->list, list)
                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;
 }
 
@@ -254,14 +212,9 @@ const char **Cvar_CompleteBuildList(cvar_state_t *cvars, const char *partial, in
        len = strlen(partial);
        buf = (const char **)Mem_Alloc(tempmempool, sizeofbuf + sizeof(const char *));
        // Loop through the alias list and print all matches
-       for (cvar = cvars->vars; cvar; cvar = cvar->next)
+       List_For_Each_Entry(cvar, &cvars->vars->list, list)
                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;
@@ -288,15 +241,9 @@ void Cvar_CompleteCvarPrint(cvar_state_t *cvars, const char *partial, int needed
        cvar_t *cvar;
        size_t len = strlen(partial);
        // Loop through the command list and print all matches
-       for (cvar = cvars->vars; cvar; cvar = cvar->next)
+       List_For_Each_Entry(cvar, &cvars->vars->list, list)
                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);
-
-               
+                       Cvar_PrintHelp(cvar->parent ? cvar->parent : cvar, cvar->name, true);
 }
 
 // check if a cvar is held by some progs
@@ -362,8 +309,12 @@ static void Cvar_UpdateAutoCvar(cvar_t *var)
 void Cvar_UpdateAllAutoCvars(cvar_state_t *cvars)
 {
        cvar_t *var;
-       for (var = cvars->vars ; var ; var = var->next)
+       List_For_Each_Entry(var, &cvars->vars->list, list)
+       {
+               if(var->parent)
+                       continue;
                Cvar_UpdateAutoCvar(var);
+       }
 }
 
 void Cvar_Callback(cvar_t *var)
@@ -384,14 +335,18 @@ Cvar_Set
 ============
 */
 extern cvar_t sv_disablenotify;
-static void Cvar_SetQuick_Internal (cvar_t *var, const char *value)
+void Cvar_SetQuick (cvar_t *var, const char *value)
 {
-       qbool changed;
        size_t valuelen;
 
-       changed = strcmp(var->string, value) != 0;
-       // LadyHavoc: don't reallocate when there is no change
-       if (!changed)
+       if (var == NULL)
+       {
+               Con_Print("Cvar_SetQuick: var == NULL\n");
+               return;
+       }
+
+       // Don't reallocate when there is no change
+       if (!strcmp(var->string, value))
                return;
 
        // LadyHavoc: don't reallocate when the buffer is the same size
@@ -429,20 +384,6 @@ static void Cvar_SetQuick_Internal (cvar_t *var, const char *value)
        Cvar_Callback(var);
 }
 
-void Cvar_SetQuick (cvar_t *var, const char *value)
-{
-       if (var == NULL)
-       {
-               Con_Print("Cvar_SetQuick: var == NULL\n");
-               return;
-       }
-
-       if (developer_extra.integer)
-               Con_DPrintf("Cvar_SetQuick({\"%s\", \"%s\", %i, \"%s\"}, \"%s\");\n", var->name, var->string, var->flags, var->defstring, value);
-
-       Cvar_SetQuick_Internal(var, value);
-}
-
 void Cvar_Set(cvar_state_t *cvars, const char *var_name, const char *value)
 {
        cvar_t *var;
@@ -452,7 +393,7 @@ void Cvar_Set(cvar_state_t *cvars, const char *var_name, const char *value)
                Con_Printf("Cvar_Set: variable %s not found\n", var_name);
                return;
        }
-       Cvar_SetQuick(var, value);
+       Cvar_SetQuick(var->parent ? var->parent : var, value);
 }
 
 /*
@@ -482,6 +423,32 @@ void Cvar_SetValue(cvar_state_t *cvars, const char *var_name, float value)
        Cvar_Set(cvars, var_name, val);
 }
 
+/*
+============
+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;
+       int hashindex;
+
+       // Link the object in alphanumerical order
+       List_For_Each_Entry(current, &cvars->vars->list, list)
+               if(strcmp(current->name, variable->name) > 0)
+                       break;
+
+       List_Add_Tail(&variable->list, &current->list);
+
+       // link to head of list in this hash table index
+       hashindex = CRC_Block((const unsigned char *)variable->name, strlen(variable->name)) % CVAR_HASHSIZE;
+       variable->hnext = cvars->hashtable[hashindex];
+       cvars->hashtable[hashindex] = variable;
+       variable->hashindex = hashindex;
+}
+
 void Cvar_RegisterCallback(cvar_t *variable, void (*callback)(cvar_t *))
 {
        if (variable == NULL)
@@ -492,11 +459,25 @@ void Cvar_RegisterCallback(cvar_t *variable, void (*callback)(cvar_t *))
        variable->callback = callback;
 }
 
-void Cvar_RegisterVirtual(cvar_t *variable, const char *name )
+static void Cvar_DeleteVirtual(cvar_t *vcvar)
+{
+       List_Delete(&vcvar->vlist);
+       Z_Free((char *)vcvar->name);
+       Z_Free(vcvar);
+}
+
+static void Cvar_DeleteVirtual_All(cvar_t *var)
+{
+       cvar_t *vcvar, *vcvar_next;
+
+       List_For_Each_Entry_Safe(vcvar, vcvar_next, &var->vlist, vlist)
+               Cvar_DeleteVirtual(vcvar);
+}
+
+void Cvar_RegisterVirtual(cvar_t *variable, const char *name)
 {
        cvar_state_t *cvars = &cvars_all;
-       cvar_hash_t *hash;
-       int hashindex;
+       cvar_t *vcvar;
 
        if(!*name)
        {
@@ -517,56 +498,16 @@ void Cvar_RegisterVirtual(cvar_t *variable, const char *name )
                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(name) + 1);
-       memcpy(variable->aliases[variable->aliases_size], name, strlen(name) + 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 *)name, strlen(name)) % CVAR_HASHSIZE;
-       hash->next = cvars->hashtable[hashindex];
-       cvars->hashtable[hashindex] = hash;
-       hash->cvar = variable;
-}
-
-/*
-============
-Cvar_Link
+       vcvar = (cvar_t *)Z_Malloc(sizeof(cvar_t));
+       vcvar->parent = variable;
+       vcvar->flags = variable->flags; 
+       vcvar->name = (char *)Mem_strdup(zonemempool, name);
+       vcvar->description = variable->description;
 
-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;
+       // Add to it
+       List_Add_Tail(&vcvar->vlist, &variable->vlist);
 
-       // 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;
+       Cvar_Link(vcvar, cvars);
 }
 
 /*
@@ -579,7 +520,7 @@ Adds a freestanding variable to the variable list.
 void Cvar_RegisterVariable (cvar_t *variable)
 {
        cvar_state_t *cvars = NULL;
-       cvar_t *current, *cvar;
+       cvar_t *cvar;
        int i;
 
        switch (variable->flags & (CF_CLIENT | CF_SERVER))
@@ -622,19 +563,7 @@ void Cvar_RegisterVariable (cvar_t *variable)
                        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 (cvars->vars == cvar)
-                       {
-                               // head of the list is easy to change
-                               cvars->vars = variable;
-                       }
-                       else
-                       {
-                               // otherwise find it somewhere in the list
-                               for (current = cvars->vars;current->next != cvar;current = current->next)
-                                       ;
-                               current->next = variable;
-                       }
+                       List_Replace(&cvar->list, &variable->list);
 
                        // get rid of old allocated cvar
                        // (but not cvar->string and cvar->defstring, because we kept those)
@@ -659,9 +588,9 @@ void Cvar_RegisterVariable (cvar_t *variable)
        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;
+       variable->parent = NULL;
+       variable->vlist.next = variable->vlist.prev = &variable->vlist;
 
        // Mark it as not an autocvar.
        for (i = 0;i < PRVM_PROG_MAX;i++)
@@ -685,12 +614,25 @@ cvar_t *Cvar_Get(cvar_state_t *cvars, const char *name, const char *value, int f
        if (developer_extra.integer)
                Con_DPrintf("Cvar_Get(\"%s\", \"%s\", %i);\n", name, value, flags);
 
+       // check for pure evil
+       if (!*name)
+       {
+               Con_Printf("Cvar_Get: invalid variable name\n");
+               return NULL;
+       }
+
        // first check to see if it has already been defined
        cvar = Cvar_FindVar(cvars, name, ~0);
        if (cvar)
        {
+               if(cvar->parent)
+               {
+                       List_Delete(&cvar->vlist);
+                       cvar->parent = NULL;
+               }
+
                cvar->flags |= flags;
-               Cvar_SetQuick_Internal (cvar, value);
+               Cvar_SetQuick (cvar, value);
                if(newdescription && (cvar->flags & CF_ALLOCATED))
                {
                        if(cvar->description != cvar_dummy_description)
@@ -704,13 +646,6 @@ cvar_t *Cvar_Get(cvar_state_t *cvars, const char *name, const char *value, int f
                return cvar;
        }
 
-       // 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(cmd_local, name))
        {
@@ -728,9 +663,9 @@ cvar_t *Cvar_Get(cvar_state_t *cvars, const char *name, const char *value, int f
        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;
+       cvar->parent = NULL;
+       cvar->vlist.next = cvar->vlist.prev = &cvar->vlist;
 
        if(newdescription && *newdescription)
                cvar->description = (char *)Mem_strdup(zonemempool, newdescription);
@@ -746,6 +681,35 @@ cvar_t *Cvar_Get(cvar_state_t *cvars, const char *name, const char *value, int f
        return cvar;
 }
 
+static void Cvar_Delete(cvar_t *cvar)
+{
+       cvar_state_t *cvars = &cvars_all;
+
+       List_Delete(&cvar->list);
+
+       for (cvar_t *hash = cvars->hashtable[cvar->hashindex]; hash->hnext != hash; hash = hash->hnext)
+       {
+               if(hash->hnext == cvar)
+               {
+                       hash->hnext = cvar->hnext;
+                       break;
+               }
+       }
+
+       Cvar_DeleteVirtual_All(cvar);
+
+       if(cvar->flags & CF_ALLOCATED)
+       {
+               if(cvar->description != cvar_dummy_description)
+                       Z_Free((char *)cvar->description);
+
+               Z_Free((char *)cvar->name);
+               Z_Free((char *)cvar->string);
+               Z_Free((char *)cvar->defstring);
+               Z_Free(cvar);
+       }
+}
+
 qbool Cvar_Readonly (cvar_t *var, const char *cmd_name)
 {
        if (var->flags & CF_READONLY)
@@ -766,30 +730,30 @@ Cvar_Command
 Handles variable inspection and changing from the console
 ============
 */
-qbool  Cvar_Command (cmd_state_t *cmd)
+qbool Cvar_Command (cmd_state_t *cmd)
 {
-       cvar_state_t    *cvars = cmd->cvars;
-       cvar_t                  *v;
+       cvar_state_t *cvars = cmd->cvars;
+       cvar_t *var;
 
        // check variables
-       v = Cvar_FindVar(cvars, Cmd_Argv(cmd, 0), (cmd->cvars_flagsmask));
-       if (!v)
+       var = Cvar_FindVar(cvars, Cmd_Argv(cmd, 0), (cmd->cvars_flagsmask));
+       if (!var)
                return false;
 
        // perform a variable print or set
        if (Cmd_Argc(cmd) == 1)
        {
-               Cvar_PrintHelp(v, Cmd_Argv(cmd, 0), true);
+               Cvar_PrintHelp(var->parent ? var->parent : var, Cmd_Argv(cmd, 0), true);
                return true;
        }
 
        if (developer_extra.integer)
                Con_DPrint("Cvar_Command: ");
 
-       if(Cvar_Readonly(v, NULL))
+       if(Cvar_Readonly(var, NULL))
                return true;
 
-       Cvar_SetQuick(v, Cmd_Argv(cmd, 1));
+       Cvar_SetQuick(var->parent ? var->parent : var, Cmd_Argv(cmd, 1));
        if (developer_extra.integer)
                Con_DPrint("\n");
        return true;
@@ -800,7 +764,7 @@ 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 = cvars->vars ; var ; var = var->next)
+       List_For_Each_Entry(var, &cvars->vars->list, list)
                var->flags &= ~CF_DEFAULTSET;
 }
 
@@ -809,9 +773,9 @@ 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 = cvars->vars ; var ; var = var->next)
+       List_For_Each_Entry(var, &cvars->vars->list, list)
        {
-               if (!(var->flags & CF_DEFAULTSET))
+               if (!var->parent && !(var->flags & CF_DEFAULTSET))
                {
                        size_t alloclen;
 
@@ -827,87 +791,81 @@ void Cvar_LockDefaults_f(cmd_state_t *cmd)
 
 void Cvar_SaveInitState(cvar_state_t *cvars)
 {
-       cvar_t *c;
-       for (c = cvars->vars;c;c = c->next)
+       cvar_t *cvar, *vcvar;
+
+       List_For_Each_Entry(cvar, &cvars->vars->list, list)
        {
-               c->initstate = (cvar_t *)Z_Malloc(sizeof(cvar_t));
-               memcpy(c->initstate, c, sizeof(cvar_t));
+               // Get the the virtual cvars separately
+               if(cvar->parent)
+                       continue;
+
+               cvar->initstate = (cvar_t *)Z_Malloc(sizeof(cvar_t));
+               memcpy(cvar->initstate, cvar, sizeof(cvar_t));
+
+               /*
+                * Consider any virtual cvar created up to this point as
+                * existing during init. Use the initstate of the parent cvar.
+                */
+               List_For_Each_Entry(vcvar, &cvar->vlist, list)
+                       vcvar->initstate = cvar->initstate;
        }
 }
 
 void Cvar_RestoreInitState(cvar_state_t *cvars)
 {
-       int hashindex;
-       cvar_t *c, **cp;
-       cvar_t *c2, **cp2;
-       for (cp = &cvars->vars;(c = *cp);)
+       cvar_t *var/*, *vcvar*/, *next/*, *vnext*/;
+
+       List_For_Each_Entry_Safe(var, next, &cvars->vars->list, list)
        {
-               if (c->initstate)
+               // Ignore virtual cvars
+               if(var->parent)
+                       continue;
+
+               // Cloudwalk FIXME: This crashes for some reason, so it's disabled for now.
+               
+               // Destroy all virtual cvars that didn't exist at init
+               //List_For_Each_Entry_Safe(vcvar, vnext, &var->vlist, vlist)
+               //      if(!vcvar->initstate)
+               //              Cvar_DeleteVirtual(vcvar);
+
+               if (var->initstate)
                {
                        // restore this cvar, it existed at init
-                       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 : ""))
+                       if (((var->flags ^ var->initstate->flags) & CF_MAXFLAGSVAL)
+                        || strcmp(var->defstring ? var->defstring : "", var->initstate->defstring ? var->initstate->defstring : "")
+                        || strcmp(var->string ? var->string : "", var->initstate->string ? var->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->initstate->defstring);
-                               if (c->string)
-                                       Z_Free((char *)c->string);
-                               c->string = Mem_strdup(zonemempool, c->initstate->string);
+                               Con_DPrintf("Cvar_RestoreInitState: Restoring cvar \"%s\"\n", var->name);
+                               if (var->defstring)
+                                       Z_Free((char *)var->defstring);
+                               var->defstring = Mem_strdup(zonemempool, var->initstate->defstring);
+                               if (var->string)
+                                       Z_Free((char *)var->string);
+                               var->string = Mem_strdup(zonemempool, var->initstate->string);
                        }
-                       c->flags = c->initstate->flags;
-                       c->value = c->initstate->value;
-                       c->integer = c->initstate->integer;
-                       VectorCopy(c->initstate->vector, c->vector);
-                       cp = &c->next;
+                       var->flags = var->initstate->flags;
+                       var->value = var->initstate->value;
+                       var->integer = var->initstate->integer;
+                       VectorCopy(var->initstate->vector, var->vector);
+
                }
                else
                {
-                       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 & CF_PERSISTENT) == 0)
-                                       Cvar_SetQuick(c, c->defstring);
-                               cp = &c->next;
-                               continue;
-                       }
-                       if (Cvar_IsAutoCvar(c))
+                       if (!(var->flags & CF_ALLOCATED))
+                               Con_DPrintf("Cvar_RestoreInitState: Unable to destroy cvar \"%s\", it was registered after init!\n", var->name);
+                       else if (Cvar_IsAutoCvar(var))
+                               Con_DPrintf("Cvar_RestoreInitState: Unable to destroy cvar \"%s\", it is an autocvar used by running progs!\n", var->name);
+                       else
                        {
-                               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 & CF_PERSISTENT) == 0)
-                                       Cvar_SetQuick(c, c->defstring);
-                               cp = &c->next;
+                               // remove this cvar, it did not exist at init
+                               Con_DPrintf("Cvar_RestoreInitState: Destroying cvar \"%s\"\n", var->name);
+                               Cvar_Delete(var);
                                continue;
                        }
-                       // remove this cvar, it did not exist at init
-                       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 = &cvars->hashtable[hashindex]->cvar;(c2 = *cp2);)
-                       {
-                               if (c2 == c)
-                               {
-                                       *cp2 = cvars->hashtable[hashindex]->next->cvar;
-                                       break;
-                               }
-                               else
-                                       cp2 = &cvars->hashtable[hashindex]->next->cvar;
-                       }
-                       // unlink struct from main list
-                       *cp = c->next;
-                       // free strings
-                       if (c->defstring)
-                               Z_Free((char *)c->defstring);
-                       if (c->string)
-                               Z_Free((char *)c->string);
-                       if (c->description && c->description != cvar_dummy_description)
-                               Z_Free((char *)c->description);
-                       // free struct
-                       Z_Free(c);
+
+                       // At least reset it to the default.
+                       if((var->flags & CF_PERSISTENT) == 0)
+                               Cvar_SetQuick(var, var->defstring);
                }
        }
 }
@@ -917,9 +875,9 @@ 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 = cvars->vars ; var ; var = var->next)
+       List_For_Each_Entry(var, &cvars->vars->list, list)
        {
-               if((var->flags & CF_PERSISTENT) == 0)
+               if(!var->parent && !(var->flags & CF_PERSISTENT))
                        Cvar_SetQuick(var, var->defstring);
        }
 }
@@ -929,22 +887,21 @@ 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 = cvars->vars ; var ; var = var->next)
+       List_For_Each_Entry(var, &cvars->vars->list, list)
        {
-               if ((var->flags & (CF_PERSISTENT | CF_ARCHIVE)) == 0)
+               if (!var->parent && !(var->flags & (CF_PERSISTENT | CF_ARCHIVE)))
                        Cvar_SetQuick(var, var->defstring);
        }
 }
 
-
 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 = cvars->vars ; var ; var = var->next)
+       List_For_Each_Entry(var, &cvars->vars->list, list)
        {
-               if ((var->flags & (CF_PERSISTENT | CF_ARCHIVE)) == CF_ARCHIVE)
+               if (!var->parent && (var->flags & (CF_PERSISTENT | CF_ARCHIVE)) == CF_ARCHIVE)
                        Cvar_SetQuick(var, var->defstring);
        }
 }
@@ -963,7 +920,10 @@ void Cvar_WriteVariables (cvar_state_t *cvars, qfile_t *f)
        char buf1[MAX_INPUTLINE], buf2[MAX_INPUTLINE];
 
        // don't save cvars that match their default value
-       for (var = cvars->vars ; var ; var = var->next) {
+       List_For_Each_Entry(var, &cvars->vars->list, list)
+       {
+               if(var->parent)
+                       continue;
                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);
@@ -1003,21 +963,13 @@ void Cvar_List_f(cmd_state_t *cmd)
        }
 
        count = 0;
-       for (cvar = cvars->vars; cvar; cvar = cvar->next)
+       List_For_Each_Entry(cvar, &cvars->vars->list, list)
        {
                if (matchpattern_with_separator(cvar->name, partial, false, "", false))
                {
-                       Cvar_PrintHelp(cvar, cvar->name, true);
+                       Cvar_PrintHelp(cvar->parent ? cvar->parent : 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 (Cmd_Argc(cmd) > 1)
@@ -1087,8 +1039,7 @@ void Cvar_Del_f(cmd_state_t *cmd)
        cvar_state_t *cvars = cmd->cvars;
        int neededflags = ~0;
        int i;
-       cvar_t *parent, **link;
-       cvar_t *cvar, *prev;
+       cvar_t *cvar;
 
        if(Cmd_Argc(cmd) < 2)
        {
@@ -1097,7 +1048,7 @@ void Cvar_Del_f(cmd_state_t *cmd)
        }
        for(i = 1; i < Cmd_Argc(cmd); ++i)
        {
-               cvar = Cvar_FindVarLink(cvars, Cmd_Argv(cmd, i), &parent, &link, &prev, neededflags);
+               cvar = Cvar_FindVar(cvars, Cmd_Argv(cmd, i), neededflags);
 
                if(!cvar)
                {
@@ -1111,28 +1062,7 @@ void Cvar_Del_f(cmd_state_t *cmd)
                        Con_Printf("%s: %s is static and cannot be deleted\n", Cmd_Argv(cmd, 0), cvar->name);
                        continue;
                }
-               if(cvar == cvars->vars)
-               {
-                       cvars->vars = cvar->next;
-               }
-               else
-               {
-                       // in this case, prev must be set, otherwise there has been some inconsistensy
-                       // elsewhere already... should I still check for prev != NULL?
-                       prev->next = cvar->next;
-               }
-
-               if(parent)
-                       parent->next = cvar->next;
-               else if(link)
-                       *link = cvar->next;
-               if(cvar->description != cvar_dummy_description)
-                       Z_Free((char *)cvar->description);
-
-               Z_Free((char *)cvar->name);
-               Z_Free((char *)cvar->string);
-               Z_Free((char *)cvar->defstring);
-               Z_Free(cvar);
+               Cvar_Delete(cvar);
        }
 }
 
diff --git a/cvar.h b/cvar.h
index 92ea81cdc54ee26ce172ce63e5ee429cb8d235b9..c1690f1649a1064870326bf8ca55cd14679429e9 100644 (file)
--- a/cvar.h
+++ b/cvar.h
@@ -59,6 +59,8 @@ interface from being ambiguous.
 
 #include "qtypes.h"
 #include "qdefs.h"
+#include "com_list.h"
+
 struct cmd_state_s;
 struct qfile_s;
 
@@ -78,27 +80,22 @@ typedef struct cvar_s
 
        void (*callback)(struct cvar_s *var);
 
-       char **aliases;
-       int aliases_size;
+       int globaldefindex[3];
+       int globaldefindex_stringno[3];
+
+       int hashindex; // Index in hash table, to avoid looking up a cvar twice when unlinking
 
        struct cvar_s *initstate; // snapshot of cvar during init
 
-       int globaldefindex[3];
-       int globaldefindex_stringno[3];
+       struct cvar_s *parent, *hnext;
 
-       struct cvar_s *next;
+       llist_t list, vlist;
 } cvar_t;
 
-typedef struct cvar_hash_s
-{
-       cvar_t *cvar;
-       struct cvar_hash_s *next;
-} cvar_hash_t;
-
 typedef struct cvar_state_s
 {
        cvar_t *vars;
-       cvar_hash_t *hashtable[CVAR_HASHSIZE];
+       cvar_t *hashtable[CVAR_HASHSIZE];
 }
 cvar_state_t;
 
index 07adabf396246c2a6ec3b0e140ff3d389b1813c7..9606c6878bef234464b46a888b9b956959d68c7e 100644 (file)
@@ -4619,7 +4619,7 @@ void VM_buf_cvarlist(prvm_prog_t *prog)
        antiispattern = antipartial && (strchr(antipartial, '*') || strchr(antipartial, '?'));
 
        n = 0;
-       for(cvar = prog->console_cmd->cvars->vars; cvar; cvar = cvar->next)
+       List_For_Each_Entry(cvar, &prog->console_cmd->cvars->vars->list, list)
        {
                if(len && (ispattern ? !matchpattern_with_separator(cvar->name, partial, false, "", false) : strncmp(partial, cvar->name, len)))
                        continue;
@@ -4635,7 +4635,7 @@ void VM_buf_cvarlist(prvm_prog_t *prog)
                stringbuffer->strings = (char **)Mem_Alloc(prog->progs_mempool, sizeof(stringbuffer->strings[0]) * stringbuffer->max_strings);
        
        n = 0;
-       for(cvar = prog->console_cmd->cvars->vars; cvar; cvar = cvar->next)
+       List_For_Each_Entry(cvar, &prog->console_cmd->cvars->vars->list, list)
        {
                if(len && (ispattern ? !matchpattern_with_separator(cvar->name, partial, false, "", false) : strncmp(partial, cvar->name, len)))
                        continue;
index 3c50397e70a4e324c5d4811758f4500418d6fdfe..27226b3854e7c3f3c8729985ca4d12acbf79e811 100644 (file)
@@ -2573,7 +2573,7 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, unsigned char * da
                }
        }
 
-       for (cvar = prog->console_cmd->cvars->vars; cvar; cvar = cvar->next)
+       List_For_Each_Entry(cvar, &prog->console_cmd->cvars->vars->list, list)
                cvar->globaldefindex[prog - prvm_prog_list] = -1;
 
        for (i=0 ; i<prog->numglobaldefs ; i++)