1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: m_misc.cpp 4469 2014-01-03 23:38:29Z dr_sean $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Copyright (C) 2006-2014 by The Odamex Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // DESCRIPTION:
20 // Default Config File.
21 //
22 //-----------------------------------------------------------------------------
23
24
25 #include <cstdio>
26 #include <cstdlib>
27 #include <ctime>
28 #include <string>
29 #include <sstream>
30 #include <vector>
31
32 #include "c_bind.h"
33 #include "c_cvars.h"
34 #include "c_dispatch.h"
35 #include "doomdef.h"
36 #include "doomtype.h"
37 #include "m_argv.h"
38 #include "m_fileio.h"
39 #include "m_misc.h"
40 #include "i_system.h"
41 #include "m_fileio.h"
42 #include "version.h"
43
44 // Used to identify the version of the game that saved
45 // a config file to compensate for new features that get
46 // put into newer configfiles.
47 static CVAR (configver, CONFIGVERSIONSTR, "", CVARTYPE_STRING, CVAR_ARCHIVE | CVAR_NOENABLEDISABLE)
48
49 EXTERN_CVAR (cl_name)
50 EXTERN_CVAR (sv_maxplayers)
51
52 extern unsigned int last_revision;
53 extern std::vector<std::string> wadfiles;
54
55 /**
56 * Get configuration file path. This file contains commands to set all
57 * archived cvars, bind commands to keys, and set other general game
58 * information.
59 *
60 * @author Randy Heit
61 * @return The filename of the configuration file path.
62 */
M_GetConfigPath(void)63 std::string M_GetConfigPath(void)
64 {
65 const char *p = Args.CheckValue("-config");
66
67 if (p)
68 return p;
69
70 return I_GetUserFileName("odamex.cfg");
71 }
72
73 // [RH] Don't write a config file if M_LoadDefaults hasn't been called.
74 bool DefaultsLoaded;
75
76 /**
77 * Save a configuration file.
78 *
79 * @author Randy Heit
80 * @param Optional: The filename to save the current configuration to.
81 */
M_SaveDefaults(std::string filename)82 void STACK_ARGS M_SaveDefaults(std::string filename)
83 {
84 FILE *f;
85
86 if (!DefaultsLoaded)
87 return;
88
89 std::string configfile;
90 if (!filename.empty())
91 {
92 M_AppendExtension(filename, ".cfg", true);
93 configfile = filename;
94 }
95 else
96 {
97 configfile = M_GetConfigPath();
98 }
99
100 // Make sure the user hasn't changed configver
101 configver.Set(CONFIGVERSIONSTR);
102
103 if ((f = fopen(configfile.c_str(), "w")))
104 {
105 fprintf(f, "// Generated by Odamex " DOTVERSIONSTR " - don't hurt anything\n\n");
106
107 // Archive all cvars marked as CVAR_ARCHIVE
108 fprintf(f, "// --- Console variables ---\n\n");
109 cvar_t::C_ArchiveCVars(f);
110
111 // Archive all active key bindings
112 fprintf(f, "// --- Key Bindings ---\n\n");
113 C_ArchiveBindings(f);
114
115 // Archive all aliases
116 fprintf(f, "\n// --- Aliases ---\n\n");
117 DConsoleAlias::C_ArchiveAliases(f);
118
119 fclose(f);
120
121 Printf(PRINT_HIGH, "Configuration saved to %s.\n", configfile.c_str());
122 }
123 }
124
BEGIN_COMMAND(savecfg)125 BEGIN_COMMAND (savecfg)
126 {
127 if (argc > 1)
128 M_SaveDefaults(argv[1]);
129 else
130 M_SaveDefaults();
131 }
132 END_COMMAND (savecfg)
133
134 extern int cvar_defflags;
135
136 /**
137 * Load a configuration file from the default configuration file.
138 *
139 * @author Randy Heit
140 */
M_LoadDefaults(void)141 void M_LoadDefaults(void)
142 {
143 extern char DefBindings[];
144
145 // Set default key bindings. These will be overridden
146 // by the bindings in the config file if it exists.
147 AddCommandString(DefBindings);
148
149 std::string cmd = "exec " + C_QuoteString(M_GetConfigPath());
150
151 cvar_defflags = CVAR_ARCHIVE;
152 AddCommandString(cmd);
153 cvar_defflags = 0;
154
155 AddCommandString("alias ? help");
156
157 DefaultsLoaded = true;
158 }
159
160 // Expands tokens that could be passed to a filename
M_ExpandTokens(const std::string & str)161 std::string M_ExpandTokens(const std::string &str)
162 {
163 if (str.empty()) {
164 return std::string();
165 }
166
167 std::ostringstream buffer;
168
169 for (size_t i = 0;i < str.size();i++) {
170 // End of the string. Just copy the last character
171 // and end the loop.
172 if (i == str.size() - 1) {
173 buffer << str[i];
174 break;
175 }
176
177 // If it's not a formatting token, copy it and move on.
178 if (str[i] != '%') {
179 buffer << str[i];
180 continue;
181 }
182
183 switch (str[i + 1])
184 {
185 case 'd':
186 {
187 // Date
188 time_t now = time(NULL);
189 char date[11] = {0};
190 strftime(date, sizeof(date), "%Y%m%d", localtime(&now));
191 buffer << date;
192 break;
193 }
194 case 't':
195 {
196 // Time
197 time_t now = time(NULL);
198 char date[9] = {0};
199 strftime(date, sizeof(date), "%H%M%S", localtime(&now));
200 buffer << date;
201 break;
202 }
203 case 'n':
204 buffer << cl_name.cstring();
205 break;
206 case 'g':
207 {
208 switch (sv_gametype.asInt())
209 {
210 case (int)(GM_COOP):
211 if (!multiplayer)
212 buffer << "SOLO";
213 else
214 buffer << "COOP";
215 break;
216 case (int)(GM_DM):
217 if (sv_maxplayers == 2)
218 buffer << "DUEL";
219 else
220 buffer << "DM";
221 break;
222 case (int)(GM_TEAMDM):
223 buffer << "TDM";
224 break;
225 case (int)(GM_CTF):
226 buffer << "CTF";
227 break;
228 }
229
230 break;
231 }
232 case 'w':
233 if (wadfiles.size() == 2) {
234 // We're playing an IWAD map
235 buffer << M_ExtractFileName(wadfiles[1]);
236 } else if (wadfiles.size() > 2) {
237 // We're playing a PWAD map
238 buffer << M_ExtractFileName(wadfiles[2]);
239 }
240 break;
241 case 'm':
242 buffer << level.mapname;
243 break;
244 case 'r':
245 buffer << "r" << last_revision;
246 break;
247 case '%':
248 // Literal percent
249 buffer << '%';
250 break;
251 }
252 // Skip format character
253 i++;
254 }
255
256 return buffer.str();
257 }
258
259 // Find a free filename that isn't taken
M_FindFreeName(std::string & filename,const std::string & extension)260 bool M_FindFreeName(std::string &filename, const std::string &extension)
261 {
262 std::string unmodified = filename + '.' + extension;
263 if (!M_FileExists(unmodified)) {
264 // Name requires no modification.
265 filename = unmodified;
266 return true;
267 }
268
269 int i;
270
271 for (i=1; i <= 9999;i++) {
272 std::ostringstream buffer;
273 buffer << filename << '.' << i << "." << extension;
274 if (!M_FileExists(buffer.str())) {
275 // File doesn't exist.
276 filename = buffer.str();
277 break;
278 }
279 }
280
281 if (i == 10000)
282 return false;
283 else
284 return true;
285 }
286
287 VERSION_CONTROL (m_misc_cpp, "$Id: m_misc.cpp 4469 2014-01-03 23:38:29Z dr_sean $")
288
289
290
291