fix more warnings in mingw
[divverent/darkplaces.git] / sys_shared.c
1 #include "quakedef.h"
2
3 #define SUPPORTDLL
4
5 #ifdef WIN32
6 # include <windows.h>
7 # include <mmsystem.h> // timeGetTime
8 # include <time.h> // localtime
9 #ifdef _MSC_VER
10 #pragma comment(lib, "winmm.lib")
11 #endif
12 #else
13 # include <unistd.h>
14 # include <fcntl.h>
15 # include <sys/time.h>
16 # include <time.h>
17 # ifdef SUPPORTDLL
18 #  include <dlfcn.h>
19 # endif
20 #endif
21
22 static char sys_timestring[128];
23 char *Sys_TimeString(const char *timeformat)
24 {
25         time_t mytime = time(NULL);
26 #if _MSC_VER >= 1400
27         struct tm mytm;
28         localtime_s(&mytm, &mytime);
29         strftime(sys_timestring, sizeof(sys_timestring), timeformat, &mytm);
30 #else
31         strftime(sys_timestring, sizeof(sys_timestring), timeformat, localtime(&mytime));
32 #endif
33         return sys_timestring;
34 }
35
36
37 extern qboolean host_shuttingdown;
38 void Sys_Quit (int returnvalue)
39 {
40         if (COM_CheckParm("-profilegameonly"))
41                 Sys_AllowProfiling(false);
42         host_shuttingdown = true;
43         Host_Shutdown();
44         exit(returnvalue);
45 }
46
47 #if defined(__linux__) || defined(__FreeBSD__)
48 #ifdef __cplusplus
49 extern "C"
50 #endif
51 int moncontrol(int);
52 #endif
53
54 void Sys_AllowProfiling(qboolean enable)
55 {
56 #if defined(__linux__) || defined(__FreeBSD__)
57         moncontrol(enable);
58 #endif
59 }
60
61
62 /*
63 ===============================================================================
64
65 DLL MANAGEMENT
66
67 ===============================================================================
68 */
69
70 qboolean Sys_LoadLibrary (const char** dllnames, dllhandle_t* handle, const dllfunction_t *fcts)
71 {
72 #ifdef SUPPORTDLL
73         const dllfunction_t *func;
74         dllhandle_t dllhandle = 0;
75         unsigned int i;
76
77         if (handle == NULL)
78                 return false;
79
80 #ifndef WIN32
81 #ifdef PREFER_PRELOAD
82         dllhandle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
83         if(dllhandle)
84         {
85                 for (func = fcts; func && func->name != NULL; func++)
86                         if (!(*func->funcvariable = (void *) Sys_GetProcAddress (dllhandle, func->name)))
87                         {
88                                 dlclose(dllhandle);
89                                 goto notfound;
90                         }
91                 Con_DPrintf ("All of %s's functions were already linked in! Not loading dynamically...\n", dllnames[0]);
92                 *handle = dllhandle;
93                 return true;
94         }
95 notfound:
96 #endif
97 #endif
98
99         // Initializations
100         for (func = fcts; func && func->name != NULL; func++)
101                 *func->funcvariable = NULL;
102
103         // Try every possible name
104         Con_DPrintf ("Trying to load library...");
105         for (i = 0; dllnames[i] != NULL; i++)
106         {
107                 Con_DPrintf (" \"%s\"", dllnames[i]);
108 #ifdef WIN32
109                 dllhandle = LoadLibrary (dllnames[i]);
110 #else
111                 dllhandle = dlopen (dllnames[i], RTLD_LAZY | RTLD_GLOBAL);
112 #endif
113                 if (dllhandle)
114                         break;
115         }
116
117         // see if the names can be loaded relative to the executable path
118         // (this is for Mac OSX which does not check next to the executable)
119         if (!dllhandle && strrchr(com_argv[0], '/'))
120         {
121                 char path[MAX_OSPATH];
122                 strlcpy(path, com_argv[0], sizeof(path));
123                 strrchr(path, '/')[1] = 0;
124                 for (i = 0; dllnames[i] != NULL; i++)
125                 {
126                         char temp[MAX_OSPATH];
127                         strlcpy(temp, path, sizeof(temp));
128                         strlcat(temp, dllnames[i], sizeof(temp));
129                         Con_DPrintf (" \"%s\"", temp);
130 #ifdef WIN32
131                         dllhandle = LoadLibrary (temp);
132 #else
133                         dllhandle = dlopen (temp, RTLD_LAZY | RTLD_GLOBAL);
134 #endif
135                         if (dllhandle)
136                                 break;
137                 }
138         }
139
140         // No DLL found
141         if (! dllhandle)
142         {
143                 Con_DPrintf(" - failed.\n");
144                 return false;
145         }
146
147         Con_DPrintf(" - loaded.\n");
148
149         // Get the function adresses
150         for (func = fcts; func && func->name != NULL; func++)
151                 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (dllhandle, func->name)))
152                 {
153                         Con_DPrintf ("Missing function \"%s\" - broken library!\n", func->name);
154                         Sys_UnloadLibrary (&dllhandle);
155                         return false;
156                 }
157
158         *handle = dllhandle;
159         return true;
160 #else
161         return false;
162 #endif
163 }
164
165 void Sys_UnloadLibrary (dllhandle_t* handle)
166 {
167 #ifdef SUPPORTDLL
168         if (handle == NULL || *handle == NULL)
169                 return;
170
171 #ifdef WIN32
172         FreeLibrary (*handle);
173 #else
174         dlclose (*handle);
175 #endif
176
177         *handle = NULL;
178 #endif
179 }
180
181 void* Sys_GetProcAddress (dllhandle_t handle, const char* name)
182 {
183 #ifdef SUPPORTDLL
184 #ifdef WIN32
185         return (void *)GetProcAddress (handle, name);
186 #else
187         return (void *)dlsym (handle, name);
188 #endif
189 #else
190         return NULL;
191 #endif
192 }
193
194 #ifdef WIN32
195 # define HAVE_TIMEGETTIME 1
196 # define HAVE_QUERYPERFORMANCECOUNTER 1
197 # define HAVE_Sleep 1
198 #endif
199
200 #if defined(CLOCK_MONOTONIC) || defined(CLOCK_HIRES)
201 # define HAVE_CLOCKGETTIME 1
202 #endif
203
204 #ifndef WIN32
205 // FIXME improve this check, manpage hints to DST_NONE
206 # define HAVE_GETTIMEOFDAY 1
207 #endif
208
209 #ifdef FD_SET
210 # define HAVE_SELECT 1
211 #endif
212
213 #ifndef WIN32
214 // FIXME improve this check
215 # define HAVE_USLEEP 1
216 #endif
217
218 // this one is referenced elsewhere
219 cvar_t sys_usenoclockbutbenchmark = {CVAR_SAVE, "sys_usenoclockbutbenchmark", "0", "don't use ANY real timing, and simulate a clock (for benchmarking); the game then runs as fast as possible. Run a QC mod with bots that does some stuff, then does a quit at the end, to benchmark a server. NEVER do this on a public server."};
220
221 // these are not
222 static cvar_t sys_debugsleep = {0, "sys_debugsleep", "0", "write requested and attained sleep times to standard output, to be used with gnuplot"};
223 static cvar_t sys_usesdlgetticks = {CVAR_SAVE, "sys_usesdlgetticks", "0", "use SDL_GetTicks() timer (less accurate, for debugging)"};
224 static cvar_t sys_usesdldelay = {CVAR_SAVE, "sys_usesdldelay", "0", "use SDL_Delay() (less accurate, for debugging)"};
225 #if HAVE_QUERYPERFORMANCECOUNTER
226 static cvar_t sys_usequeryperformancecounter = {CVAR_SAVE, "sys_usequeryperformancecounter", "0", "use windows QueryPerformanceCounter timer (which has issues on multicore/multiprocessor machines and processors which are designed to conserve power) for timing rather than timeGetTime function (which has issues on some motherboards)"};
227 #endif
228 #if HAVE_CLOCKGETTIME
229 static cvar_t sys_useclockgettime = {CVAR_SAVE, "sys_useclockgettime", "0", "use POSIX clock_gettime function (which has issues if the system clock speed is far off, as it can't get fixed by NTP) for timing rather than gettimeofday (which has issues if the system time is stepped by ntpdate, or apparently on some Xen installations)"};
230 #endif
231
232 static unsigned long benchmark_time;
233
234 void Sys_Init_Commands (void)
235 {
236         Cvar_RegisterVariable(&sys_debugsleep);
237         Cvar_RegisterVariable(&sys_usenoclockbutbenchmark);
238 #if HAVE_TIMEGETTIME || HAVE_QUERYPERFORMANCECOUNTER || HAVE_CLOCKGETTIME || HAVE_GETTIMEOFDAY
239         if(sys_supportsdlgetticks)
240         {
241                 Cvar_RegisterVariable(&sys_usesdlgetticks);
242                 Cvar_RegisterVariable(&sys_usesdldelay);
243         }
244 #endif
245 #if HAVE_QUERYPERFORMANCECOUNTER
246         Cvar_RegisterVariable(&sys_usequeryperformancecounter);
247 #endif
248 #if HAVE_CLOCKGETTIME
249         Cvar_RegisterVariable(&sys_useclockgettime);
250 #endif
251 }
252
253 double Sys_DoubleTime(void)
254 {
255         static int first = true;
256         static double oldtime = 0.0, curtime = 0.0;
257         double newtime;
258         if(sys_usenoclockbutbenchmark.integer)
259         {
260                 benchmark_time += 1;
261                 return ((double) benchmark_time) / 1e6;
262         }
263
264         // first all the OPTIONAL timers
265
266 #if HAVE_QUERYPERFORMANCECOUNTER
267         else if (sys_usequeryperformancecounter.integer)
268         {
269                 // LordHavoc: note to people modifying this code, DWORD is specifically defined as an unsigned 32bit number, therefore the 65536.0 * 65536.0 is fine.
270                 // QueryPerformanceCounter
271                 // platform:
272                 // Windows 95/98/ME/NT/2000/XP
273                 // features:
274                 // very accurate (CPU cycles)
275                 // known issues:
276                 // does not necessarily match realtime too well (tends to get faster and faster in win98)
277                 // wraps around occasionally on some platforms (depends on CPU speed and probably other unknown factors)
278                 double timescale;
279                 LARGE_INTEGER PerformanceFreq;
280                 LARGE_INTEGER PerformanceCount;
281
282                 if (!QueryPerformanceFrequency (&PerformanceFreq))
283                 {
284                         Con_Printf ("No hardware timer available\n");
285                         // fall back to timeGetTime
286                         Cvar_SetValueQuick(&sys_usequeryperformancecounter, false);
287                         return Sys_DoubleTime();
288                 }
289                 QueryPerformanceCounter (&PerformanceCount);
290
291                 #ifdef __BORLANDC__
292                 timescale = 1.0 / ((double) PerformanceFreq.u.LowPart + (double) PerformanceFreq.u.HighPart * 65536.0 * 65536.0);
293                 newtime = ((double) PerformanceCount.u.LowPart + (double) PerformanceCount.u.HighPart * 65536.0 * 65536.0) * timescale;
294                 #else
295                 timescale = 1.0 / ((double) PerformanceFreq.LowPart + (double) PerformanceFreq.HighPart * 65536.0 * 65536.0);
296                 newtime = ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale;
297                 #endif
298         }
299 #endif
300
301 #if HAVE_CLOCKGETTIME
302         else if (sys_useclockgettime.integer)
303         {
304                 struct timespec ts;
305 #  ifdef CLOCK_MONOTONIC
306                 // linux
307                 clock_gettime(CLOCK_MONOTONIC, &ts);
308 #  else
309                 // sunos
310                 clock_gettime(CLOCK_HIGHRES, &ts);
311 #  endif
312                 newtime = (double) ts.tv_sec + ts.tv_nsec / 1000000000.0;
313         }
314 #endif
315
316         // now all the FALLBACK timers
317         else if(sys_supportsdlgetticks && sys_usesdlgetticks.integer)
318         {
319                 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
320         }
321 #if HAVE_GETTIMEOFDAY
322         else
323         {
324                 struct timeval tp;
325                 gettimeofday(&tp, NULL);
326                 newtime = (double) tp.tv_sec + tp.tv_usec / 1000000.0;
327         }
328 #elif HAVE_TIMEGETTIME
329         else
330         {
331                 static int firsttimegettime = true;
332                 // timeGetTime
333                 // platform:
334                 // Windows 95/98/ME/NT/2000/XP
335                 // features:
336                 // reasonable accuracy (millisecond)
337                 // issues:
338                 // wraps around every 47 days or so (but this is non-fatal to us, odd times are rejected, only causes a one frame stutter)
339
340                 // make sure the timer is high precision, otherwise different versions of windows have varying accuracy
341                 if (firsttimegettime)
342                 {
343                         timeBeginPeriod (1);
344                         firsttimegettime = false;
345                 }
346
347                 newtime = (double) timeGetTime () / 1000.0;
348         }
349 #else
350         // fallback for using the SDL timer if no other timer is available
351         else
352         {
353                 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
354                 // this calls Sys_Error() if not linking against SDL
355         }
356 #endif
357
358         if (first)
359         {
360                 first = false;
361                 oldtime = newtime;
362         }
363
364         if (newtime < oldtime)
365         {
366                 // warn if it's significant
367                 if (newtime - oldtime < -0.01)
368                         Con_Printf("Sys_DoubleTime: time stepped backwards (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
369         }
370         else if (newtime > oldtime + 1800)
371         {
372                 Con_Printf("Sys_DoubleTime: time stepped forward (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
373         }
374         else
375                 curtime += newtime - oldtime;
376         oldtime = newtime;
377
378         return curtime;
379 }
380
381 void Sys_Sleep(int microseconds)
382 {
383         double t = 0;
384         if(sys_usenoclockbutbenchmark.integer)
385         {
386                 benchmark_time += microseconds;
387                 return;
388         }
389         if(sys_debugsleep.integer)
390         {
391                 t = Sys_DoubleTime();
392         }
393         if(sys_supportsdlgetticks && sys_usesdldelay.integer)
394         {
395                 Sys_SDL_Delay(microseconds / 1000);
396         }
397 #if HAVE_SELECT
398         else
399         {
400                 struct timeval tv;
401                 tv.tv_sec = microseconds / 1000000;
402                 tv.tv_usec = microseconds % 1000000;
403                 select(0, NULL, NULL, NULL, &tv);
404         }
405 #elif HAVE_USLEEP
406         else
407         {
408                 usleep(microseconds);
409         }
410 #elif HAVE_Sleep
411         else
412         {
413                 Sleep(microseconds / 1000);
414         }
415 #else
416         else
417         {
418                 Sys_SDL_Delay(microseconds / 1000);
419         }
420 #endif
421         if(sys_debugsleep.integer)
422         {
423                 t = Sys_DoubleTime() - t;
424                 printf("%d %d # debugsleep\n", microseconds, (unsigned int)(t * 1000000));
425         }
426 }
427
428 const char *Sys_FindInPATH(const char *name, char namesep, const char *PATH, char pathsep, char *buf, size_t bufsize)
429 {
430         const char *p = PATH;
431         const char *q;
432         if(p && name)
433         {
434                 while((q = strchr(p, ':')))
435                 {
436                         dpsnprintf(buf, bufsize, "%.*s%c%s", (int)(q-p), p, namesep, name);
437                         if(FS_SysFileExists(buf))
438                                 return buf;
439                         p = q + 1;
440                 }
441                 if(!q) // none found - try the last item
442                 {
443                         dpsnprintf(buf, bufsize, "%s%c%s", p, namesep, name);
444                         if(FS_SysFileExists(buf))
445                                 return buf;
446                 }
447         }
448         return name;
449 }
450
451 const char *Sys_FindExecutableName(void)
452 {
453 #if defined(WIN32)
454         return com_argv[0];
455 #else
456         static char exenamebuf[MAX_OSPATH+1];
457         ssize_t n = -1;
458 #if defined(__FreeBSD__)
459         n = readlink("/proc/curproc/file", exenamebuf, sizeof(exenamebuf)-1);
460 #elif defined(__linux__)
461         n = readlink("/proc/self/exe", exenamebuf, sizeof(exenamebuf)-1);
462 #endif
463         if(n > 0 && (size_t)(n) < sizeof(exenamebuf))
464         {
465                 exenamebuf[n] = 0;
466                 return exenamebuf;
467         }
468         if(strchr(com_argv[0], '/'))
469                 return com_argv[0]; // possibly a relative path
470         else
471                 return Sys_FindInPATH(com_argv[0], '/', getenv("PATH"), ':', exenamebuf, sizeof(exenamebuf));
472 #endif
473 }
474
475 void Sys_ProvideSelfFD(void)
476 {
477         if(com_selffd != -1)
478                 return;
479         com_selffd = FS_SysOpenFD(Sys_FindExecutableName(), "rb", false);
480 }