Merge branch 'terencehill/eraseable_functions'
[xonotic/xonotic-data.pk3dir.git] / qcsrc / lib / cvar.qh
1 #pragma once
2
3 #include "nil.qh"
4 #include "progname.qh"
5 #include "static.qh"
6
7 [[eraseable]]
8 void RegisterCvars(void(string name, string def, string desc, bool archive, string file) f) {}
9
10 [[eraseable]]
11 bool cvar_value_issafe(string s)
12 {
13         if (strstrofs(s, "\"", 0) >= 0) return false;
14         if (strstrofs(s, "\\", 0) >= 0) return false;
15         if (strstrofs(s, ";", 0) >= 0) return false;
16         if (strstrofs(s, "$", 0) >= 0) return false;
17         if (strstrofs(s, "\r", 0) >= 0) return false;
18         if (strstrofs(s, "\n", 0) >= 0) return false;
19         return true;
20 }
21
22 /** escape the string to make it safe for consoles */
23 [[eraseable]]
24 string MakeConsoleSafe(string input)
25 {
26         input = strreplace("\n", "", input);
27         input = strreplace("\\", "\\\\", input);
28         input = strreplace("$", "$$", input);
29         input = strreplace("\"", "\\\"", input);
30         return input;
31 }
32
33 [[eraseable]]
34 void cvar_describe(string name, string desc)
35 {
36         localcmd(sprintf("\nset %1$s \"$%1$s\" \"%2$s\"\n", name, MakeConsoleSafe(desc)));
37 }
38
39 [[eraseable]]
40 void cvar_archive(string name)
41 {
42         localcmd(sprintf("\nseta %1$s \"$%1$s\"\n", name));
43 }
44
45 [[eraseable]]
46 void RegisterCvars_Set(string name, string def, string desc, bool archive, string file)
47 {
48         cvar_describe(name, desc);
49         if (archive) cvar_archive(name);
50 }
51
52 int RegisterCvars_Save_fd;
53 [[eraseable]]
54 void RegisterCvars_Save(string name, string def, string desc, bool archive, string file)
55 {
56         if (!archive) return;
57         fputs(RegisterCvars_Save_fd, sprintf("seta %s \"%s\"\n", name, def));
58 }
59
60 STATIC_INIT_LATE(Cvars)
61 {
62         RegisterCvars(RegisterCvars_Set);
63         RegisterCvars_Save_fd = fopen(sprintf("default%s.cfg", PROGNAME), FILE_WRITE);
64         if (RegisterCvars_Save_fd >= 0)
65         {
66                 RegisterCvars(RegisterCvars_Save);
67                 fclose(RegisterCvars_Save_fd);
68         }
69 }
70
71 const noref bool default_bool = false;
72 const noref int default_int = 0;
73 const noref float default_float = 0;
74 const noref string default_string = "";
75 const noref vector default_vector = '0 0 0';
76
77 #define repr_cvar_bool(x) ((x) ? "1" : "0")
78 #define repr_cvar_int(x) (ftos(x))
79 #define repr_cvar_float(x) (ftos(x))
80 #define repr_cvar_string(x) (x)
81 #define repr_cvar_vector(x) (sprintf("%v", x))
82
83 //pseudo prototypes:
84 // void AUTOCVAR(<cvar_name>, <qc_var_type>, default_cvar_value, string desc)
85 // void AUTOCVAR_SAVE(<cvar_name>, <qc_var_type>, default_cvar_value, string desc)
86 //  where default_cvar_value has type <qc_var_type>
87 //  e.g.: AUTOCVAR(mycvar, float, 2.5, "cvar description")
88
89 #define __AUTOCVAR(file, archive, var, type, desc, default) \
90         [[accumulate]] void RegisterCvars(void(string, string, string, bool, string) f) \
91         { \
92                 f( #var, repr_cvar_##type(default), desc, archive, file); \
93         } \
94         type autocvar_##var = default
95 #define AUTOCVAR_5(file, archive, var, type, desc) \
96         __AUTOCVAR(file, archive, var, type, desc, default_##type)
97 #define AUTOCVAR_6(file, archive, var, type, default, desc) \
98         __AUTOCVAR(file, archive, var, type, desc, default)
99 #define _AUTOCVAR(...) EVAL__AUTOCVAR(OVERLOAD(AUTOCVAR, __FILE__, __VA_ARGS__))
100 #define EVAL__AUTOCVAR(...) __VA_ARGS__
101 #define AUTOCVAR_SAVE(...) _AUTOCVAR(true, __VA_ARGS__)
102 #define AUTOCVAR(...) _AUTOCVAR(false, __VA_ARGS__)