1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: i_main.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 // Main program, simply calls D_DoomMain high level loop.
21 //
22 //-----------------------------------------------------------------------------
23
24 #include <stack>
25 #include <iostream>
26 #include <map>
27 #include <string>
28
29 #include "win32inc.h"
30 #ifdef _WIN32
31 #include "resource.h"
32 #include "mmsystem.h"
33 #endif
34
35 #ifdef UNIX
36 #include <unistd.h>
37 #include <sys/types.h>
38 #include <signal.h>
39 #endif
40
41 #include <stdlib.h>
42 #include <stdio.h>
43 #include <stdarg.h>
44 #include <math.h>
45 #include <time.h>
46
47 #include "m_argv.h"
48 #include "d_main.h"
49 #include "i_system.h"
50 #include "c_console.h"
51 #include "z_zone.h"
52 #include "errors.h"
53 #include "i_net.h"
54 #include "sv_main.h"
55 #include "m_ostring.h"
56
57 using namespace std;
58
59 void AddCommandString(std::string cmd);
60
61 DArgs Args;
62
63 #ifdef _WIN32
64 extern UINT TimerPeriod;
65 #endif
66
67 // functions to be called at shutdown are stored in this stack
68 typedef void (STACK_ARGS *term_func_t)(void);
69 std::stack< std::pair<term_func_t, std::string> > TermFuncs;
70
addterm(void (STACK_ARGS * func)(),const char * name)71 void addterm (void (STACK_ARGS *func) (), const char *name)
72 {
73 TermFuncs.push(std::pair<term_func_t, std::string>(func, name));
74 }
75
call_terms(void)76 void STACK_ARGS call_terms (void)
77 {
78 while (!TermFuncs.empty())
79 TermFuncs.top().first(), TermFuncs.pop();
80 }
81
PrintString(int printlevel,char const * outline)82 int PrintString (int printlevel, char const *outline)
83 {
84 int ret = printf("%s", outline);
85 fflush(stdout);
86 return ret;
87 }
88
89 #ifdef _WIN32
90 static HANDLE hEvent;
91
ShutdownNow()92 int ShutdownNow()
93 {
94 return (WaitForSingleObject(hEvent, 1) == WAIT_OBJECT_0);
95 }
96
ConsoleHandlerRoutine(DWORD dwCtrlType)97 BOOL WINAPI ConsoleHandlerRoutine(DWORD dwCtrlType)
98 {
99 SetEvent(hEvent);
100 return TRUE;
101 }
102
main(int argc,char * argv[])103 int __cdecl main(int argc, char *argv[])
104 {
105 try
106 {
107 // Handle ctrl-c, close box, shutdown and logoff events
108 if (!SetConsoleCtrlHandler(ConsoleHandlerRoutine, TRUE))
109 throw CDoomError("Could not set console control handler!\n");
110
111 if (!(hEvent = CreateEvent(NULL, FALSE, FALSE, NULL)))
112 throw CDoomError("Could not create console control event!\n");
113
114 #ifdef _WIN32
115 // Fixes icon not showing in titlebar and alt-tab menu under windows 7
116 HANDLE hIcon;
117
118 hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1));
119
120 if(hIcon)
121 {
122 SendMessage(GetConsoleWindow(), WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
123 SendMessage(GetConsoleWindow(), WM_SETICON, ICON_BIG, (LPARAM)hIcon);
124 }
125 #endif
126
127 // [ML] 2007/9/3: From Eternity (originally chocolate Doom) Thanks SoM & fraggle!
128 Args.SetArgs (argc, argv);
129
130 const char *CON_FILE = Args.CheckValue("-confile");
131 if(CON_FILE)CON.open(CON_FILE, std::ios::in);
132
133 // Set the timer to be as accurate as possible
134 TIMECAPS tc;
135 if (timeGetDevCaps (&tc, sizeof(tc) != TIMERR_NOERROR))
136 TimerPeriod = 1; // Assume minimum resolution of 1 ms
137 else
138 TimerPeriod = tc.wPeriodMin;
139
140 timeBeginPeriod (TimerPeriod);
141
142 // Don't call this on windows!
143 //atexit (call_terms);
144
145 Z_Init();
146
147 atterm (I_Quit);
148 atterm (DObject::StaticShutdown);
149
150 progdir = I_GetBinaryDir();
151 startdir = I_GetCWD();
152
153 C_InitConsole (80*8, 25*8, false);
154
155 D_DoomMain ();
156 }
157 catch (CDoomError &error)
158 {
159 if (LOG.is_open())
160 {
161 LOG << error.GetMsg() << std::endl;
162 LOG << std::endl;
163 }
164 else
165 {
166 MessageBox(NULL, error.GetMsg().c_str(), "Odasrv Error", MB_OK);
167 }
168
169 exit(EXIT_FAILURE);
170 }
171 catch (...)
172 {
173 call_terms ();
174 throw;
175 }
176 return 0;
177 }
178 #else
179
180 // cleanup handling -- killough:
handler(int s)181 static void handler (int s)
182 {
183 char buf[64];
184
185 signal(s,SIG_IGN); // Ignore future instances of this signal.
186
187 strcpy(buf,
188 s==SIGSEGV ? "Segmentation Violation" :
189 s==SIGINT ? "Interrupted by User" :
190 s==SIGILL ? "Illegal Instruction" :
191 s==SIGFPE ? "Floating Point Exception" :
192 s==SIGTERM ? "Killed" : "Terminated by signal %s");
193
194 I_FatalError (buf, s);
195 }
196
197 //
198 // daemon_init
199 //
daemon_init(void)200 void daemon_init(void)
201 {
202 int pid;
203 FILE *fpid;
204 string pidfile;
205
206 Printf(PRINT_HIGH, "Launched into the background\n");
207
208 if ((pid = fork()) != 0)
209 {
210 call_terms();
211 exit(EXIT_SUCCESS);
212 }
213
214 const char *forkargs = Args.CheckValue("-fork");
215 if (forkargs)
216 pidfile = string(forkargs);
217
218 if(!pidfile.size() || pidfile[0] == '-')
219 pidfile = "doomsv.pid";
220
221 pid = getpid();
222 fpid = fopen(pidfile.c_str(), "w");
223 fprintf(fpid, "%d\n", pid);
224 fclose(fpid);
225 }
226
main(int argc,char ** argv)227 int main (int argc, char **argv)
228 {
229 try
230 {
231 if(!getuid() || !geteuid())
232 I_FatalError("root user detected, quitting odamex immediately");
233
234 seteuid (getuid ());
235
236 // ensure OString's string table is properly initialized and shutdown
237 OString::startup();
238 atterm(OString::shutdown);
239
240 Args.SetArgs (argc, argv);
241
242 const char *CON_FILE = Args.CheckValue("-confile");
243 if(CON_FILE)CON.open(CON_FILE, std::ios::in);
244
245 /*
246 killough 1/98:
247
248 This fixes some problems with exit handling
249 during abnormal situations.
250
251 The old code called I_Quit() to end program,
252 while now I_Quit() is installed as an exit
253 handler and exit() is called to exit, either
254 normally or abnormally. Seg faults are caught
255 and the error handler is used, to prevent
256 being left in graphics mode or having very
257 loud SFX noise because the sound card is
258 left in an unstable state.
259 */
260
261 // Don't use this on other platforms either
262 //atexit (call_terms);
263 Z_Init(); // 1/18/98 killough: start up memory stuff first
264
265 atterm (I_Quit);
266 atterm (DObject::StaticShutdown);
267
268 signal(SIGSEGV, handler);
269 signal(SIGTERM, handler);
270 signal(SIGILL, handler);
271 signal(SIGFPE, handler);
272 signal(SIGINT, handler); // killough 3/6/98: allow CTRL-BRK during init
273 signal(SIGABRT, handler);
274
275 progdir = I_GetBinaryDir();
276
277 C_InitConsole (80*8, 25*8, false);
278
279 D_DoomMain ();
280 }
281 catch (CDoomError &error)
282 {
283 fprintf (stderr, "%s\n", error.GetMsg().c_str());
284
285 if (LOG.is_open())
286 {
287 LOG << error.GetMsg() << std::endl;
288 LOG << std::endl;
289 }
290
291 call_terms();
292 exit(EXIT_FAILURE);
293 }
294 catch (...)
295 {
296 call_terms ();
297 throw;
298 }
299 return 0;
300 }
301
302 #endif
303
304 VERSION_CONTROL (i_main_cpp, "$Id: i_main.cpp 4469 2014-01-03 23:38:29Z dr_sean $")
305
306