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