Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | pmbaty | 1 | /* |
2 | * This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>. |
||
3 | * It is copyright by its individual contributors, as recorded in the |
||
4 | * project's Git history. See COPYING.txt at the top level for license |
||
5 | * terms and a link to the Git history. |
||
6 | * |
||
7 | */ |
||
8 | /* |
||
9 | * |
||
10 | * Console variables |
||
11 | * |
||
12 | */ |
||
13 | |||
14 | #include <cstdarg> |
||
15 | #include <map> |
||
16 | #include <stdlib.h> |
||
17 | #include <physfs.h> |
||
18 | |||
19 | #include "console.h" |
||
20 | #include "cvar.h" |
||
21 | #include "dxxerror.h" |
||
22 | #include "strutil.h" |
||
23 | #include "u_mem.h" |
||
24 | #include "game.h" |
||
25 | #include "physfsx.h" |
||
26 | |||
27 | #include "dxxsconf.h" |
||
28 | #include "compiler-range_for.h" |
||
29 | |||
30 | #define CVAR_MAX_LENGTH 1024 |
||
31 | |||
32 | /* The list of cvars */ |
||
33 | typedef std::map<const char *, std::reference_wrapper<cvar_t>> cvar_list_type; |
||
34 | static cvar_list_type cvar_list; |
||
35 | |||
36 | const char *cvar_t::operator=(const char *s) |
||
37 | { |
||
38 | cvar_set_cvar(this, s); |
||
39 | return s; |
||
40 | } |
||
41 | |||
42 | int cvar_t::operator=(int i) { cvar_set_cvarf(this, "%d", i); return this->intval; } |
||
43 | |||
44 | void cvar_cmd_set(unsigned long argc, const char *const *const argv) |
||
45 | { |
||
46 | char buf[CVAR_MAX_LENGTH]; |
||
47 | int ret; |
||
48 | |||
49 | if (argc == 2) { |
||
50 | cvar_t *ptr; |
||
51 | |||
52 | if ((ptr = cvar_find(argv[1]))) |
||
53 | con_printf(CON_NORMAL, "%s: %s", ptr->name, ptr->string.c_str()); |
||
54 | else |
||
55 | con_printf(CON_NORMAL, "set: variable %s not found", argv[1]); |
||
56 | return; |
||
57 | } |
||
58 | |||
59 | if (argc == 1) { |
||
60 | range_for (const auto &i, cvar_list) |
||
61 | con_printf(CON_NORMAL, "%s: %s", i.first, i.second.get().string.c_str()); |
||
62 | return; |
||
63 | } |
||
64 | |||
65 | ret = snprintf(buf, sizeof(buf), "%s", argv[2]); |
||
66 | if (ret >= CVAR_MAX_LENGTH) { |
||
67 | con_printf(CON_CRITICAL, "set: value too long (max %d characters)", CVAR_MAX_LENGTH); |
||
68 | return; |
||
69 | } |
||
70 | |||
71 | size_t position = ret; |
||
72 | for (int i = 3; i < argc; i++) { |
||
73 | ret = snprintf(&buf[position], CVAR_MAX_LENGTH - position, " %s", argv[i]); |
||
74 | position += ret; |
||
75 | if (position >= CVAR_MAX_LENGTH) |
||
76 | { |
||
77 | con_printf(CON_CRITICAL, "set: value too long (max %d characters)", CVAR_MAX_LENGTH); |
||
78 | return; |
||
79 | } |
||
80 | } |
||
81 | cvar_set(argv[1], buf); |
||
82 | } |
||
83 | |||
84 | |||
85 | void cvar_init(void) |
||
86 | { |
||
87 | cmd_addcommand("set", cvar_cmd_set, "set <name> <value>\n" " set variable <name> equal to <value>\n" |
||
88 | "set <name>\n" " show value of <name>\n" |
||
89 | "set\n" " show value of all variables"); |
||
90 | } |
||
91 | |||
92 | |||
93 | cvar_t *cvar_find(const char *cvar_name) |
||
94 | { |
||
95 | const auto i = cvar_list.find(cvar_name); |
||
96 | return i == cvar_list.end() ? nullptr : &i->second.get(); |
||
97 | } |
||
98 | |||
99 | |||
100 | const char *cvar_complete(const char *text) |
||
101 | { |
||
102 | uint_fast32_t len = strlen(text); |
||
103 | if (!len) |
||
104 | return NULL; |
||
105 | range_for (const auto &i, cvar_list) |
||
106 | if (!d_strnicmp(text, i.first, len)) |
||
107 | return i.first; |
||
108 | return NULL; |
||
109 | } |
||
110 | |||
111 | |||
112 | /* Register a cvar */ |
||
113 | void cvar_registervariable (cvar_t &cvar) |
||
114 | { |
||
115 | cvar.value = fl2f(strtod(cvar.string.c_str(), NULL)); |
||
116 | cvar.intval = static_cast<int>(strtol(cvar.string.c_str(), NULL, 10)); |
||
117 | |||
118 | const auto i = cvar_list.insert(cvar_list_type::value_type(cvar.name, cvar)); |
||
119 | if (!i.second) |
||
120 | { |
||
121 | Int3(); |
||
122 | con_printf(CON_URGENT, "cvar %s already exists!", cvar.name); |
||
123 | return; |
||
124 | } |
||
125 | /* insert at end of list */ |
||
126 | } |
||
127 | |||
128 | |||
129 | /* Set a CVar's value */ |
||
130 | void cvar_set_cvar(cvar_t *cvar, const char *value) |
||
131 | { |
||
132 | if (!cvar) |
||
133 | return; |
||
134 | |||
135 | cvar->string = value; |
||
136 | cvar->value = fl2f(strtod(value, NULL)); |
||
137 | cvar->intval = static_cast<int>(strtol(value, NULL, 10)); |
||
138 | con_printf(CON_VERBOSE, "%s: %s", cvar->name, value); |
||
139 | } |
||
140 | |||
141 | |||
142 | void cvar_set_cvarf(cvar_t *cvar, const char *fmt, ...) |
||
143 | { |
||
144 | va_list arglist; |
||
145 | char buf[CVAR_MAX_LENGTH]; |
||
146 | int n; |
||
147 | |||
148 | va_start (arglist, fmt); |
||
149 | n = vsnprintf(buf, sizeof(buf), fmt, arglist); |
||
150 | va_end (arglist); |
||
151 | |||
152 | if (n < 0 || n > CVAR_MAX_LENGTH) { |
||
153 | Int3(); |
||
154 | con_printf(CON_CRITICAL, "error setting cvar %s", cvar->name); |
||
155 | return; |
||
156 | } |
||
157 | |||
158 | cvar_set_cvar(cvar, buf); |
||
159 | } |
||
160 | |||
161 | |||
162 | void cvar_set(const char *cvar_name, char *value) |
||
163 | { |
||
164 | cvar_t *cvar; |
||
165 | |||
166 | cvar = cvar_find(cvar_name); |
||
167 | if (!cvar) { |
||
168 | Int3(); |
||
169 | con_printf(CON_NORMAL, "cvar %s not found", cvar_name); |
||
170 | return; |
||
171 | } |
||
172 | |||
173 | if (cvar->flags & CVAR_CHEAT && !cheats_enabled()) |
||
174 | { |
||
175 | con_printf(CON_NORMAL, "cvar %s is cheat protected.", cvar_name); |
||
176 | return; |
||
177 | } |
||
178 | |||
179 | cvar_set_cvar(cvar, value); |
||
180 | } |
||
181 | |||
182 | |||
183 | /* Write archive cvars to file */ |
||
184 | void cvar_write(PHYSFS_File *file) |
||
185 | { |
||
186 | range_for (const auto &i, cvar_list) |
||
187 | if (i.second.get().flags & CVAR_ARCHIVE) |
||
188 | PHYSFSX_printf(file, "%s=%s\n", i.first, i.second.get().string.c_str()); |
||
189 | } |