File: qcommon\cvar.c

    1 /*
    2 Copyright (C) 1997-2001 Id Software, Inc.
    3 
    4 This program is free software; you can redistribute it and/or
    5 modify it under the terms of the GNU General Public License
    6 as published by the Free Software Foundation; either version 2
    7 of the License, or (at your option) any later version.
    8 
    9 This program is distributed in the hope that it will be useful,
   10 but WITHOUT ANY WARRANTY; without even the implied warranty of
   11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
   12 
   13 See the GNU General Public License for more details.
   14 
   15 You should have received a copy of the GNU General Public License
   16 along with this program; if not, write to the Free Software
   17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   18 
   19 */
   20 // cvar.c -- dynamic variable tracking
   21 
   22 #include "qcommon.h"
   23 
   24 cvar_t  *cvar_vars;
   25 
   26 /*
   27 ============
   28 Cvar_InfoValidate
   29 ============
   30 */
   31 static qboolean Cvar_InfoValidate (char *s)
   32 {
   33         if (strstr (s, "\\"))
   34                 return false;
   35         if (strstr (s, "\""))
   36                 return false;
   37         if (strstr (s, ";"))
   38                 return false;
   39         return true;
   40 }
   41 
   42 /*
   43 ============
   44 Cvar_FindVar
   45 ============
   46 */
   47 static cvar_t *Cvar_FindVar (char *var_name)
   48 {
   49         cvar_t  *var;
   50         
   51         for (var=cvar_vars ; var ; var=var->next)
   52                 if (!strcmp (var_name, var->name))
   53                         return var;
   54 
   55         return NULL;
   56 }
   57 
   58 /*
   59 ============
   60 Cvar_VariableValue
   61 ============
   62 */
   63 float Cvar_VariableValue (char *var_name)
   64 {
   65         cvar_t  *var;
   66         
   67         var = Cvar_FindVar (var_name);
   68         if (!var)
   69                 return 0;
   70         return atof (var->string);
   71 }
   72 
   73 
   74 /*
   75 ============
   76 Cvar_VariableString
   77 ============
   78 */
   79 char *Cvar_VariableString (char *var_name)
   80 {
   81         cvar_t *var;
   82         
   83         var = Cvar_FindVar (var_name);
   84         if (!var)
   85                 return "";
   86         return var->string;
   87 }
   88 
   89 
   90 /*
   91 ============
   92 Cvar_CompleteVariable
   93 ============
   94 */
   95 char *Cvar_CompleteVariable (char *partial)
   96 {
   97         cvar_t          *cvar;
   98         int                     len;
   99         
  100         len = strlen(partial);
  101         
  102         if (!len)
  103                 return NULL;
  104                 
  105         // check exact match
  106         for (cvar=cvar_vars ; cvar ; cvar=cvar->next)
  107                 if (!strcmp (partial,cvar->name))
  108                         return cvar->name;
  109 
  110         // check partial match
  111         for (cvar=cvar_vars ; cvar ; cvar=cvar->next)
  112                 if (!strncmp (partial,cvar->name, len))
  113                         return cvar->name;
  114 
  115         return NULL;
  116 }
  117 
  118 
  119 /*
  120 ============
  121 Cvar_Get
  122 
  123 If the variable already exists, the value will not be set
  124 The flags will be or'ed in if the variable exists.
  125 ============
  126 */
  127 cvar_t *Cvar_Get (char *var_name, char *var_value, int flags)
  128 {
  129         cvar_t  *var;
  130         
  131         if (flags & (CVAR_USERINFO | CVAR_SERVERINFO))
  132         {
  133                 if (!Cvar_InfoValidate (var_name))
  134                 {
  135                         Com_Printf("invalid info cvar name\n");
  136                         return NULL;
  137                 }
  138         }
  139 
  140         var = Cvar_FindVar (var_name);
  141         if (var)
  142         {
  143                 var->flags |= flags;
  144                 return var;
  145         }
  146 
  147         if (!var_value)
  148                 return NULL;
  149 
  150         if (flags & (CVAR_USERINFO | CVAR_SERVERINFO))
  151         {
  152                 if (!Cvar_InfoValidate (var_value))
  153                 {
  154                         Com_Printf("invalid info cvar value\n");
  155                         return NULL;
  156                 }
  157         }
  158 
  159         var = Z_Malloc (sizeof(*var));
  160         var->name = CopyString (var_name);
  161         var->string = CopyString (var_value);
  162         var->modified = true;
  163         var->value = atof (var->string);
  164 
  165         // link the variable in
  166         var->next = cvar_vars;
  167         cvar_vars = var;
  168 
  169         var->flags = flags;
  170 
  171         return var;
  172 }
  173 
  174 /*
  175 ============
  176 Cvar_Set2
  177 ============
  178 */
  179 cvar_t *Cvar_Set2 (char *var_name, char *value, qboolean force)
  180 {
  181         cvar_t  *var;
  182 
  183         var = Cvar_FindVar (var_name);
  184         if (!var)
  185         {       // create it
  186                 return Cvar_Get (var_name, value, 0);
  187         }
  188 
  189         if (var->flags & (CVAR_USERINFO | CVAR_SERVERINFO))
  190         {
  191                 if (!Cvar_InfoValidate (value))
  192                 {
  193                         Com_Printf("invalid info cvar value\n");
  194                         return var;
  195                 }
  196         }
  197 
  198         if (!force)
  199         {
  200                 if (var->flags & CVAR_NOSET)
  201                 {
  202                         Com_Printf ("%s is write protected.\n", var_name);
  203                         return var;
  204                 }
  205 
  206                 if (var->flags & CVAR_LATCH)
  207                 {
  208                         if (var->latched_string)
  209                         {
  210                                 if (strcmp(value, var->latched_string) == 0)
  211                                         return var;
  212                                 Z_Free (var->latched_string);
  213                         }
  214                         else
  215                         {
  216                                 if (strcmp(value, var->string) == 0)
  217                                         return var;
  218                         }
  219 
  220                         if (Com_ServerState())
  221                         {
  222                                 Com_Printf ("%s will be changed for next game.\n", var_name);
  223                                 var->latched_string = CopyString(value);
  224                         }
  225                         else
  226                         {
  227                                 var->string = CopyString(value);
  228                                 var->value = atof (var->string);
  229                                 if (!strcmp(var->name, "game"))
  230                                 {
  231                                         FS_SetGamedir (var->string);
  232                                         FS_ExecAutoexec ();
  233                                 }
  234                         }
  235                         return var;
  236                 }
  237         }
  238         else
  239         {
  240                 if (var->latched_string)
  241                 {
  242                         Z_Free (var->latched_string);
  243                         var->latched_string = NULL;
  244                 }
  245         }
  246 
  247         if (!strcmp(value, var->string))
  248                 return var;             // not changed
  249 
  250         var->modified = true;
  251 
  252         if (var->flags & CVAR_USERINFO)
  253                 userinfo_modified = true;       // transmit at next oportunity
  254         
  255         Z_Free (var->string);   // free the old value string
  256         
  257         var->string = CopyString(value);
  258         var->value = atof (var->string);
  259 
  260         return var;
  261 }
  262 
  263 /*
  264 ============
  265 Cvar_ForceSet
  266 ============
  267 */
  268 cvar_t *Cvar_ForceSet (char *var_name, char *value)
  269 {
  270         return Cvar_Set2 (var_name, value, true);
  271 }
  272 
  273 /*
  274 ============
  275 Cvar_Set
  276 ============
  277 */
  278 cvar_t *Cvar_Set (char *var_name, char *value)
  279 {
  280         return Cvar_Set2 (var_name, value, false);
  281 }
  282 
  283 /*
  284 ============
  285 Cvar_FullSet
  286 ============
  287 */
  288 cvar_t *Cvar_FullSet (char *var_name, char *value, int flags)
  289 {
  290         cvar_t  *var;
  291         
  292         var = Cvar_FindVar (var_name);
  293         if (!var)
  294         {       // create it
  295                 return Cvar_Get (var_name, value, flags);
  296         }
  297 
  298         var->modified = true;
  299 
  300         if (var->flags & CVAR_USERINFO)
  301                 userinfo_modified = true;       // transmit at next oportunity
  302         
  303         Z_Free (var->string);   // free the old value string
  304         
  305         var->string = CopyString(value);
  306         var->value = atof (var->string);
  307         var->flags = flags;
  308 
  309         return var;
  310 }
  311 
  312 /*
  313 ============
  314 Cvar_SetValue
  315 ============
  316 */
  317 void Cvar_SetValue (char *var_name, float value)
  318 {
  319         char    val[32];
  320 
  321         if (value == (int)value)
  322                 Com_sprintf (val, sizeof(val), "%i",(int)value);
  323         else
  324                 Com_sprintf (val, sizeof(val), "%f",value);
  325         Cvar_Set (var_name, val);
  326 }
  327 
  328 
  329 /*
  330 ============
  331 Cvar_GetLatchedVars
  332 
  333 Any variables with latched values will now be updated
  334 ============
  335 */
  336 void Cvar_GetLatchedVars (void)
  337 {
  338         cvar_t  *var;
  339 
  340         for (var = cvar_vars ; var ; var = var->next)
  341         {
  342                 if (!var->latched_string)
  343                         continue;
  344                 Z_Free (var->string);
  345                 var->string = var->latched_string;
  346                 var->latched_string = NULL;
  347                 var->value = atof(var->string);
  348                 if (!strcmp(var->name, "game"))
  349                 {
  350                         FS_SetGamedir (var->string);
  351                         FS_ExecAutoexec ();
  352                 }
  353         }
  354 }
  355 
  356 /*
  357 ============
  358 Cvar_Command
  359 
  360 Handles variable inspection and changing from the console
  361 ============
  362 */
  363 qboolean Cvar_Command (void)
  364 {
  365         cvar_t                  *v;
  366 
  367 // check variables
  368         v = Cvar_FindVar (Cmd_Argv(0));
  369         if (!v)
  370                 return false;
  371                 
  372 // perform a variable print or set
  373         if (Cmd_Argc() == 1)
  374         {
  375                 Com_Printf ("\"%s\" is \"%s\"\n", v->name, v->string);
  376                 return true;
  377         }
  378 
  379         Cvar_Set (v->name, Cmd_Argv(1));
  380         return true;
  381 }
  382 
  383 
  384 /*
  385 ============
  386 Cvar_Set_f
  387 
  388 Allows setting and defining of arbitrary cvars from console
  389 ============
  390 */
  391 void Cvar_Set_f (void)
  392 {
  393         int             c;
  394         int             flags;
  395 
  396         c = Cmd_Argc();
  397         if (c != 3 && c != 4)
  398         {
  399                 Com_Printf ("usage: set <variable> <value> [u / s]\n");
  400                 return;
  401         }
  402 
  403         if (c == 4)
  404         {
  405                 if (!strcmp(Cmd_Argv(3), "u"))
  406                         flags = CVAR_USERINFO;
  407                 else if (!strcmp(Cmd_Argv(3), "s"))
  408                         flags = CVAR_SERVERINFO;
  409                 else
  410                 {
  411                         Com_Printf ("flags can only be 'u' or 's'\n");
  412                         return;
  413                 }
  414                 Cvar_FullSet (Cmd_Argv(1), Cmd_Argv(2), flags);
  415         }
  416         else
  417                 Cvar_Set (Cmd_Argv(1), Cmd_Argv(2));
  418 }
  419 
  420 
  421 /*
  422 ============
  423 Cvar_WriteVariables
  424 
  425 Appends lines containing "set variable value" for all variables
  426 with the archive flag set to true.
  427 ============
  428 */
  429 void Cvar_WriteVariables (char *path)
  430 {
  431         cvar_t  *var;
  432         char    buffer[1024];
  433         FILE    *f;
  434 
  435         f = fopen (path, "a");
  436         for (var = cvar_vars ; var ; var = var->next)
  437         {
  438                 if (var->flags & CVAR_ARCHIVE)
  439                 {
  440                         Com_sprintf (buffer, sizeof(buffer), "set %s \"%s\"\n", var->name, var->string);
  441                         fprintf (f, "%s", buffer);
  442                 }
  443         }
  444         fclose (f);
  445 }
  446 
  447 /*
  448 ============
  449 Cvar_List_f
  450 
  451 ============
  452 */
  453 void Cvar_List_f (void)
  454 {
  455         cvar_t  *var;
  456         int             i;
  457 
  458         i = 0;
  459         for (var = cvar_vars ; var ; var = var->next, i++)
  460         {
  461                 if (var->flags & CVAR_ARCHIVE)
  462                         Com_Printf ("*");
  463                 else
  464                         Com_Printf (" ");
  465                 if (var->flags & CVAR_USERINFO)
  466                         Com_Printf ("U");
  467                 else
  468                         Com_Printf (" ");
  469                 if (var->flags & CVAR_SERVERINFO)
  470                         Com_Printf ("S");
  471                 else
  472                         Com_Printf (" ");
  473                 if (var->flags & CVAR_NOSET)
  474                         Com_Printf ("-");
  475                 else if (var->flags & CVAR_LATCH)
  476                         Com_Printf ("L");
  477                 else
  478                         Com_Printf (" ");
  479                 Com_Printf (" %s \"%s\"\n", var->name, var->string);
  480         }
  481         Com_Printf ("%i cvars\n", i);
  482 }
  483 
  484 
  485 qboolean userinfo_modified;
  486 
  487 
  488 char    *Cvar_BitInfo (int bit)
  489 {
  490         static char     info[MAX_INFO_STRING];
  491         cvar_t  *var;
  492 
  493         info[0] = 0;
  494 
  495         for (var = cvar_vars ; var ; var = var->next)
  496         {
  497                 if (var->flags & bit)
  498                         Info_SetValueForKey (info, var->name, var->string);
  499         }
  500         return info;
  501 }
  502 
  503 // returns an info string containing all the CVAR_USERINFO cvars
  504 char    *Cvar_Userinfo (void)
  505 {
  506         return Cvar_BitInfo (CVAR_USERINFO);
  507 }
  508 
  509 // returns an info string containing all the CVAR_SERVERINFO cvars
  510 char    *Cvar_Serverinfo (void)
  511 {
  512         return Cvar_BitInfo (CVAR_SERVERINFO);
  513 }
  514 
  515 /*
  516 ============
  517 Cvar_Init
  518 
  519 Reads in all archived cvars
  520 ============
  521 */
  522 void Cvar_Init (void)
  523 {
  524         Cmd_AddCommand ("set", Cvar_Set_f);
  525         Cmd_AddCommand ("cvarlist", Cvar_List_f);
  526 
  527 }
  528