1 /* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Misc system stuff needed by Doom, implemented for Linux.
31 * Mainly timer handling, and ENDOOM/ENDBOOM.
32 *
33 *-----------------------------------------------------------------------------
34 */
35
36 #ifdef _WIN32
37 #define WIN32_LEAN_AND_MEAN
38 #include <windows.h>
39 #endif
40
41 #include <stdio.h>
42
43 #include <stdarg.h>
44 #include <stdlib.h>
45 #include <ctype.h>
46 #include <signal.h>
47 #ifdef _MSC_VER
48 #define F_OK 0 /* Check for file existence */
49 #define W_OK 2 /* Check for write permission */
50 #define R_OK 4 /* Check for read permission */
51 #include <io.h>
52 #include <direct.h>
53 #else
54 #include <unistd.h>
55 #endif
56 #include <sys/stat.h>
57
58 #include "SDL.h"
59
60 #ifdef HAVE_CONFIG_H
61 #include "config.h"
62 #endif
63 #ifdef HAVE_UNISTD_H
64 #include <unistd.h>
65 #endif
66 #ifdef _MSC_VER
67 #include <io.h>
68 #endif
69 #include <fcntl.h>
70 #include <sys/stat.h>
71 #include <errno.h>
72
73 #ifndef PRBOOM_SERVER
74 #include "m_argv.h"
75 #endif
76 #include "lprintf.h"
77 #include "doomtype.h"
78 #include "doomdef.h"
79 #include "lprintf.h"
80 #ifndef PRBOOM_SERVER
81 #include "d_player.h"
82 #include "m_fixed.h"
83 #include "r_fps.h"
84 #include "e6y.h"
85 #endif
86 #include "i_system.h"
87
88 #ifdef __GNUG__
89 #pragma implementation "i_system.h"
90 #endif
91 #include "i_system.h"
92
93 #ifdef HAVE_CONFIG_H
94 #include "config.h"
95 #endif
96
97 #include "z_zone.h"
98
I_uSleep(unsigned long usecs)99 void I_uSleep(unsigned long usecs)
100 {
101 SDL_Delay(usecs/1000);
102 }
103
104 int ms_to_next_tick;
105
106 static int basetime = 0;
I_GetTime_RealTime(void)107 int I_GetTime_RealTime (void)
108 {
109 int i;
110 int t = SDL_GetTicks();
111
112 //e6y: removing startup delay
113 if (basetime == 0)
114 basetime = t;
115 t -= basetime;
116
117 i = t*(TICRATE/5)/200;
118 ms_to_next_tick = (i+1)*200/(TICRATE/5) - t;
119 if (ms_to_next_tick > 1000/TICRATE || ms_to_next_tick<1) ms_to_next_tick = 1;
120 return i;
121 }
122
123 #ifndef PRBOOM_SERVER
124 static unsigned int start_displaytime;
125 static unsigned int displaytime;
126 static dboolean InDisplay = false;
127 static int saved_gametic = -1;
128 dboolean realframe = false;
129
I_StartDisplay(void)130 dboolean I_StartDisplay(void)
131 {
132 if (InDisplay)
133 return false;
134
135 realframe = (!movement_smooth) || (gametic > saved_gametic);
136
137 if (realframe)
138 saved_gametic = gametic;
139
140 start_displaytime = SDL_GetTicks();
141 InDisplay = true;
142 return true;
143 }
144
I_EndDisplay(void)145 void I_EndDisplay(void)
146 {
147 displaytime = SDL_GetTicks() - start_displaytime;
148 InDisplay = false;
149 }
150
151 static int subframe = 0;
152 static int prevsubframe = 0;
153 int interpolation_method;
I_GetTimeFrac(void)154 fixed_t I_GetTimeFrac (void)
155 {
156 unsigned long now;
157 fixed_t frac;
158
159 now = SDL_GetTicks();
160
161 subframe++;
162
163 if (tic_vars.step == 0)
164 {
165 frac = FRACUNIT;
166 }
167 else
168 {
169 extern int renderer_fps;
170 if ((interpolation_method == 0) || (prevsubframe <= 0) || (renderer_fps <= 0))
171 {
172 frac = (fixed_t)((now - tic_vars.start + displaytime) * FRACUNIT / tic_vars.step);
173 }
174 else
175 {
176 frac = (fixed_t)((now - tic_vars.start) * FRACUNIT / tic_vars.step);
177 frac = (unsigned int)((float)FRACUNIT * TICRATE * subframe / renderer_fps);
178 }
179 frac = BETWEEN(0, FRACUNIT, frac);
180 }
181
182 return frac;
183 }
184
I_GetTime_SaveMS(void)185 void I_GetTime_SaveMS(void)
186 {
187 if (!movement_smooth)
188 return;
189
190 tic_vars.start = SDL_GetTicks();
191 tic_vars.next = (unsigned int) ((tic_vars.start * tic_vars.msec + 1.0f) / tic_vars.msec);
192 tic_vars.step = tic_vars.next - tic_vars.start;
193 prevsubframe = subframe;
194 subframe = 0;
195 }
196 #endif
197
198 /*
199 * I_GetRandomTimeSeed
200 *
201 * CPhipps - extracted from G_ReloadDefaults because it is O/S based
202 */
I_GetRandomTimeSeed(void)203 unsigned long I_GetRandomTimeSeed(void)
204 {
205 /* This isnt very random */
206 return(SDL_GetTicks());
207 }
208
209 /* cphipps - I_GetVersionString
210 * Returns a version string in the given buffer
211 */
I_GetVersionString(char * buf,size_t sz)212 const char* I_GetVersionString(char* buf, size_t sz)
213 {
214 #ifdef HAVE_SNPRINTF
215 snprintf(buf,sz,"%s v%s (http://prboom-plus.sourceforge.net/)",PACKAGE,VERSION);
216 #else
217 sprintf(buf,"%s v%s (http://prboom-plus.sourceforge.net/)",PACKAGE,VERSION);
218 #endif
219 return buf;
220 }
221
222 /* cphipps - I_SigString
223 * Returns a string describing a signal number
224 */
I_SigString(char * buf,size_t sz,int signum)225 const char* I_SigString(char* buf, size_t sz, int signum)
226 {
227 #if HAVE_DECL_SYS_SIGLIST // NSM: automake defines this symbol as 0 or 1
228 if (strlen(sys_siglist[signum]) < sz)
229 strcpy(buf,sys_siglist[signum]);
230 else
231 #endif
232 #ifdef HAVE_SNPRINTF
233 snprintf(buf,sz,"signal %d",signum);
234 #else
235 sprintf(buf,"signal %d",signum);
236 #endif
237 return buf;
238 }
239
240 #ifndef PRBOOM_SERVER
I_FileToBuffer(const char * filename,byte ** data,int * size)241 dboolean I_FileToBuffer(const char *filename, byte **data, int *size)
242 {
243 FILE *hfile;
244
245 dboolean result = false;
246 byte *buffer = NULL;
247 size_t filesize = 0;
248
249 hfile = fopen(filename, "rb");
250 if (hfile)
251 {
252 fseek(hfile, 0, SEEK_END);
253 filesize = ftell(hfile);
254 fseek(hfile, 0, SEEK_SET);
255
256 buffer = malloc(filesize);
257 if (buffer)
258 {
259 if (fread(buffer, filesize, 1, hfile) == 1)
260 {
261 result = true;
262
263 if (data)
264 {
265 *data = buffer;
266 }
267
268 if (size)
269 {
270 *size = filesize;
271 }
272 }
273 }
274
275 fclose(hfile);
276 }
277
278 if (!result)
279 {
280 free(buffer);
281 buffer = NULL;
282 }
283
284 return result;
285 }
286 #endif // PRBOOM_SERVER
287
288 /*
289 * I_Read
290 *
291 * cph 2001/11/18 - wrapper for read(2) which handles partial reads and aborts
292 * on error.
293 */
I_Read(int fd,void * vbuf,size_t sz)294 void I_Read(int fd, void* vbuf, size_t sz)
295 {
296 unsigned char* buf = vbuf;
297
298 while (sz) {
299 int rc = read(fd,buf,sz);
300 if (rc <= 0) {
301 I_Error("I_Read: read failed: %s", rc ? strerror(errno) : "EOF");
302 }
303 sz -= rc; buf += rc;
304 }
305 }
306
307 /*
308 * I_Filelength
309 *
310 * Return length of an open file.
311 */
312
I_Filelength(int handle)313 int I_Filelength(int handle)
314 {
315 struct stat fileinfo;
316 if (fstat(handle,&fileinfo) == -1)
317 I_Error("I_Filelength: %s",strerror(errno));
318 return fileinfo.st_size;
319 }
320
321 #ifndef PRBOOM_SERVER
322
323 // Return the path where the executable lies -- Lee Killough
324 // proff_fs 2002-07-04 - moved to i_system
325 #ifdef _WIN32
326
I_SwitchToWindow(HWND hwnd)327 void I_SwitchToWindow(HWND hwnd)
328 {
329 typedef BOOL (WINAPI *TSwitchToThisWindow) (HWND wnd, BOOL restore);
330 static TSwitchToThisWindow SwitchToThisWindow = NULL;
331
332 if (!SwitchToThisWindow)
333 SwitchToThisWindow = (TSwitchToThisWindow)GetProcAddress(GetModuleHandle("user32.dll"), "SwitchToThisWindow");
334
335 if (SwitchToThisWindow)
336 {
337 HWND hwndLastActive = GetLastActivePopup(hwnd);
338
339 if (IsWindowVisible(hwndLastActive))
340 hwnd = hwndLastActive;
341
342 SetForegroundWindow(hwnd);
343 Sleep(100);
344 SwitchToThisWindow(hwnd, TRUE);
345 }
346 }
347
I_DoomExeDir(void)348 const char *I_DoomExeDir(void)
349 {
350 static const char current_dir_dummy[] = {"."}; // proff - rem extra slash 8/21/03
351 static char *base;
352 if (!base) // cache multiple requests
353 {
354 size_t len = strlen(*myargv);
355 char *p = (base = malloc(len+1)) + len - 1;
356 strcpy(base,*myargv);
357 while (p > base && *p!='/' && *p!='\\')
358 *p--=0;
359 if (*p=='/' || *p=='\\')
360 *p--=0;
361 if (strlen(base)<2)
362 {
363 free(base);
364 base = malloc(1024);
365 if (!getcwd(base,1024))
366 strcpy(base, current_dir_dummy);
367 }
368 }
369 return base;
370 }
371
I_GetTempDir(void)372 const char* I_GetTempDir(void)
373 {
374 static char tmp_path[PATH_MAX] = {0};
375
376 if (tmp_path[0] == 0)
377 {
378 GetTempPath(sizeof(tmp_path), tmp_path);
379 }
380
381 return tmp_path;
382 }
383
384 #elif defined(AMIGA)
385
I_DoomExeDir(void)386 const char *I_DoomExeDir(void)
387 {
388 return "PROGDIR:";
389 }
390
I_GetTempDir(void)391 const char* I_GetTempDir(void)
392 {
393 return "PROGDIR:";
394 }
395
396 #elif defined(MACOSX)
397
398 /* Defined elsewhere */
399
400 #else
401 // cph - V.Aguilar (5/30/99) suggested return ~/.lxdoom/, creating
402 // if non-existant
403 // cph 2006/07/23 - give prboom+ its own dir
404 static const char prboom_dir[] = {"/.prboom-plus"}; // Mead rem extra slash 8/21/03
405
I_DoomExeDir(void)406 const char *I_DoomExeDir(void)
407 {
408 static char *base;
409 if (!base) // cache multiple requests
410 {
411 char *home = getenv("HOME");
412 size_t len = strlen(home);
413
414 base = malloc(len + strlen(prboom_dir) + 1);
415 strcpy(base, home);
416 // I've had trouble with trailing slashes before...
417 if (base[len-1] == '/') base[len-1] = 0;
418 strcat(base, prboom_dir);
419 mkdir(base, S_IRUSR | S_IWUSR | S_IXUSR); // Make sure it exists
420 }
421 return base;
422 }
423
I_GetTempDir(void)424 const char *I_GetTempDir(void)
425 {
426 return "/tmp";
427 }
428
429 #endif
430
431 /*
432 * HasTrailingSlash
433 *
434 * cphipps - simple test for trailing slash on dir names
435 */
436
HasTrailingSlash(const char * dn)437 dboolean HasTrailingSlash(const char* dn)
438 {
439 return ( (dn[strlen(dn)-1] == '/')
440 #if defined(_WIN32)
441 || (dn[strlen(dn)-1] == '\\')
442 #endif
443 #if defined(AMIGA)
444 || (dn[strlen(dn)-1] == ':')
445 #endif
446 );
447 }
448
449 /*
450 * I_FindFile
451 *
452 * proff_fs 2002-07-04 - moved to i_system
453 *
454 * cphipps 19/1999 - writen to unify the logic in FindIWADFile and the WAD
455 * autoloading code.
456 * Searches the standard dirs for a named WAD file
457 * The dirs are listed at the start of the function
458 */
459
460 #ifndef MACOSX /* OSX defines its search paths elsewhere. */
461
I_FindFileInternal(const char * wfname,const char * ext,dboolean isStatic)462 char* I_FindFileInternal(const char* wfname, const char* ext, dboolean isStatic)
463 {
464 // lookup table of directories to search
465 static const struct {
466 const char *dir; // directory
467 const char *sub; // subdirectory
468 const char *env; // environment variable
469 const char *(*func)(void); // for I_DoomExeDir
470 } search[] = {
471 {NULL, NULL, NULL, I_DoomExeDir}, // config directory
472 {NULL}, // current working directory
473 {NULL, NULL, "DOOMWADDIR"}, // run-time $DOOMWADDIR
474 {DOOMWADDIR}, // build-time configured DOOMWADDIR
475 {NULL, "doom", "HOME"}, // ~/doom
476 {NULL, NULL, "HOME"}, // ~
477 {"/usr/local/share/games/doom"},
478 {"/usr/share/games/doom"},
479 {"/usr/local/share/doom"},
480 {"/usr/share/doom"},
481 };
482
483 size_t i;
484 size_t pl;
485
486 char static_p[PATH_MAX];
487 char * dinamic_p = NULL;
488 char *p = (isStatic ? static_p : dinamic_p);
489
490 if (!wfname)
491 return NULL;
492
493 /* Precalculate a length we will need in the loop */
494 pl = strlen(wfname) + (ext ? strlen(ext) : 0) + 4;
495
496 for (i = 0; i < sizeof(search)/sizeof(*search); i++) {
497 const char * d = NULL;
498 const char * s = NULL;
499 /* Each entry in the switch sets d to the directory to look in,
500 * and optionally s to a subdirectory of d */
501 // switch replaced with lookup table
502 if (search[i].env) {
503 if (!(d = getenv(search[i].env)))
504 continue;
505 } else if (search[i].func)
506 d = search[i].func();
507 else
508 d = search[i].dir;
509 s = search[i].sub;
510
511 if (!isStatic)
512 p = malloc((d ? strlen(d) : 0) + (s ? strlen(s) : 0) + pl);
513 sprintf(p, "%s%s%s%s%s", d ? d : "", (d && !HasTrailingSlash(d)) ? "/" : "",
514 s ? s : "", (s && !HasTrailingSlash(s)) ? "/" : "",
515 wfname);
516
517 if (ext && access(p,F_OK))
518 strcat(p, ext);
519 if (!access(p,F_OK)) {
520 if (!isStatic)
521 lprintf(LO_INFO, " found %s\n", p);
522 return p;
523 }
524 if (!isStatic)
525 free(p);
526 }
527 return NULL;
528 }
529
I_FindFile(const char * wfname,const char * ext)530 char* I_FindFile(const char* wfname, const char* ext)
531 {
532 return I_FindFileInternal(wfname, ext, false);
533 }
534
I_FindFile2(const char * wfname,const char * ext)535 const char* I_FindFile2(const char* wfname, const char* ext)
536 {
537 return (const char*) I_FindFileInternal(wfname, ext, true);
538 }
539
540 #endif
541
542 #endif // PRBOOM_SERVER
543