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