1 // Emacs style mode select   -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: i_system.c 1542 2020-08-22 02:35:24Z wesleyjohnson $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Portions Copyright (C) 1998-2015 by DooM Legacy 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 //
20 // $Log: i_system.c,v $
21 // Revision 1.18  2002/07/26 15:23:01  hurdler
22 // near RC release
23 //
24 // Revision 1.17  2002/01/03 19:20:07  bock
25 // Add FreeBSD code to I_GetFreeMem.
26 // Modified Files:
27 //     makefile linux_x/i_system.c sdl/i_system.c
28 //
29 // Revision 1.16  2001/05/16 22:33:35  bock
30 // Initial FreeBSD support.
31 //
32 // Revision 1.15  2001/03/12 21:03:10  metzgermeister
33 //   * new symbols for rendererlib added in SDL
34 //   * console printout fixed for Linux&SDL
35 //   * Crash fixed in Linux SW renderer initialization
36 //
37 // Revision 1.14  2000/10/21 08:43:32  bpereira
38 // no message
39 //
40 // Revision 1.13  2000/10/16 07:53:57  metzgermeister
41 // fixed I_GetFreeMem
42 //
43 // Revision 1.12  2000/10/09 16:22:42  metzgermeister
44 // implemented GetFreeMem
45 //
46 // Revision 1.11  2000/10/02 18:25:47  bpereira
47 // no message
48 //
49 // Revision 1.10  2000/09/10 10:50:21  metzgermeister
50 // make it work again
51 //
52 // Revision 1.9  2000/08/11 19:11:07  metzgermeister
53 // *** empty log message ***
54 //
55 // Revision 1.8  2000/04/25 19:49:46  metzgermeister
56 // support for automatic wad search
57 //
58 // Revision 1.7  2000/04/16 18:38:07  bpereira
59 // no message
60 //
61 // Revision 1.6  2000/04/12 19:31:37  metzgermeister
62 // added use_mouse to menu
63 //
64 // Revision 1.5  2000/04/07 23:12:38  metzgermeister
65 // fixed some minor bugs
66 //
67 // Revision 1.4  2000/03/22 18:52:56  metzgermeister
68 // added I_ShutdownCD to I_Quit
69 //
70 // Revision 1.3  2000/03/06 15:19:58  hurdler
71 // Add Bell Kin's changes
72 //
73 // Revision 1.2  2000/02/27 00:42:11  hurdler
74 // fix CR+LF problem
75 //
76 // Revision 1.1.1.1  2000/02/22 20:32:33  hurdler
77 // Initial import into CVS (v1.29 pr3)
78 //
79 //
80 // DESCRIPTION:
81 //
82 //-----------------------------------------------------------------------------
83 
84 #include "doomincl.h"
85 
86 #include <stdio.h>
87 #include <stdlib.h>
88 #include <sys/types.h>
89 #include <sys/uio.h>
90 #include <unistd.h>
91 #include <fcntl.h>
92 #include <signal.h>
93 #include <string.h>
94 #include <libgen.h>
95   // dirname
96 
97 #include <stdarg.h>
98 #include <sys/time.h>
99 #ifdef LMOUSE2
100 #include <termios.h>
101 #endif
102 // statfs()
103 #ifndef FREEBSD
104 #include <sys/vfs.h>
105 #else
106 #include <sys/param.h>
107 #include <sys/mount.h>
108 /*For meminfo*/
109 #include <sys/types.h>
110 #include <sys/sysctl.h>
111 #endif
112 
113 #ifdef LJOYSTICK // linux joystick 1.x
114 #include <sys/types.h>
115 #include <sys/stat.h>
116 #include <sys/ioctl.h>
117 #include <fcntl.h>
118 #include <linux/joystick.h>
119 #endif
120 
121 #include "m_misc.h"
122 #include "i_video.h"
123 #include "i_sound.h"
124 
125 #include "d_net.h"
126 #include "g_game.h"
127 #include "g_input.h"
128 
129 #ifdef __GNUG__
130 #pragma implementation "i_system.h"
131 #endif
132 #include "i_system.h"
133 #include "i_joy.h"
134 #include "m_argv.h"
135 
136 extern void D_PostEvent(event_t*);
137 
138 extern event_t         events[MAXEVENTS];
139 extern int             eventhead;
140 extern int             eventtail;
141 
142 #if 0
143 // Locations for searching the legacy.dat
144 #define DEFAULTWADLOCATION1 "/usr/local/games/legacy"
145 #define DEFAULTWADLOCATION2 "/usr/games/legacy"
146 #define DEFAULTSEARCHPATH1 "/usr/local"
147 #define DEFAULTSEARCHPATH2 "/usr/games"
148 #define WADKEYWORD "legacy.dat"
149 
150 // holds wad path
151 static char returnWadPath[256];
152 #endif
153 
154 #ifdef LJOYSTICK
155 
156 #define MAX_JOYAXES 3
157 typedef struct {
158   int fd = -1;
159   int numaxes = 0;
160   uint16_t axis[MAX_JOYAXES];
161 } joystick_t;
162 
163 #define MAX_JOYSTICK 4
164 joystick_t  joystk[ MAX_JOYSTICK ];
165 
166 int joystick_started = 0;
167 
168 #define NUM_JOYSTICKDEV 4
169 const char * joystick_dev[NUM_JOYSTICKDEV] =
170 {
171 "/dev/input/js0",
172 "/dev/input/js1",
173 "/dev/input/js2",
174 "/dev/input/js3",
175 };
176 
177 #endif
178 //JoyType_t Joystick;
179 // must exist, even when LJOYSTICK off
180 int num_joysticks = 0;
181 
182 #ifdef LMOUSE2
183 int fdmouse2 = -1;
184 int mouse2_started = 0;
185 #endif
186 
187 // dummy 19990119 by Kin
188 byte keyboard_started = 0;
189 // current modifier key status
190 boolean shiftdown = false;
191 boolean altdown = false;
192 
I_StartupKeyboard(void)193 void I_StartupKeyboard (void) {}
I_StartupTimer(void)194 void I_StartupTimer (void) {}
195 
I_OutputMsg(char * fmt,...)196 void I_OutputMsg (char *fmt, ...)
197 {
198     va_list     argptr;
199 
200     va_start (argptr,fmt);
201     vfprintf (stderr,fmt,argptr);
202     va_end (argptr);
203 }
204 
I_GetKey(void)205 int I_GetKey (void)
206 {
207     // Warning: I_GetKey empties the event queue till next keypress
208     event_t*    ev;
209     int rc=0;
210 
211     // return the first keypress from the event queue
212     for ( ; eventtail != eventhead ;  )
213     {
214         ev = &events[eventtail];
215         if(ev->type == ev_keydown)
216         {
217             rc = ev->data1;
218         }
219 
220         eventtail++;
221         eventtail = eventtail & (MAXEVENTS-1);
222     }
223 
224     return rc;
225 }
226 
227 #ifdef LJOYSTICK
228 
229 #if 0
230 // [WDJ] Old joystick code, scale is now handled in g_game.c
231 int joy_scale = 1;
232 void I_JoyScale(void)
233 {
234   joy_scale = (cv_joyscale.value==0)?1:cv_joyscale.value;
235 }
236 #endif
237 
I_GetJoyEvent(void)238 void I_GetJoyEvent(void)
239 {
240   struct js_event jdata;
241   static event_t event = {0,0,0,0};
242   static int buttons = 0;
243   int i;
244   if(!joystick_started) return;
245   for(i=0; i<num_joysticks; i++)  // all joysticks found
246   {
247    while(read( joystk[i].fd, &jdata, sizeof(jdata)) != -1) {
248     switch(jdata.type) {
249     case JS_EVENT_AXIS:
250 #if 1
251       // [WDJ] Polled joystick
252       // Save for later polling
253       if( jdata.number < joystk[i].numaxes ) {
254           joystk[i].axis[jdata.number] = jdata.value >> 5;
255       }
256 #else
257       // [WDJ] Old event driven joystick position, it now is polled
258       event.type = ev_joystick;
259       event.data1 = 0;
260       switch(jdata.number) {
261       case 0:
262         event.data2 = ((jdata.value >> 5)/joy_scale)*joy_scale;
263         D_PostEvent(&event);
264         break;
265       case 1:
266         event.data3 = ((jdata.value >> 5)/joy_scale)*joy_scale;
267         D_PostEvent(&event);
268       default:
269         break;
270       }
271       break;
272 #endif
273     case JS_EVENT_BUTTON:
274       if(jdata.number<JOYBUTTONS) {
275         if(jdata.value) {
276           if(!((buttons >> jdata.number)&1)) {
277             buttons |= 1 << jdata.number;
278             event.type = ev_keydown;
279             event.data1 = KEY_JOY0BUT0 + (i*JOYBUTTONS) + jdata.number;
280             D_PostEvent(&event);
281           }
282         } else {
283           if((buttons>>jdata.number)&1) {
284             buttons ^= 1 << jdata.number;
285             event.type = ev_keyup;
286             event.data1 = KEY_JOY0BUT0 + (i*JOYBUTTONS) + jdata.number;
287             D_PostEvent(&event);
288           }
289         }
290       }
291       break;
292     }
293    }
294   }
295 }
296 
I_ShutdownJoystick(void)297 static void I_ShutdownJoystick(void)
298 {
299   int i;
300   for( i=0; i<num_joysticks; i++ )
301   {
302       if(joystk[i].fd != -1)
303          close(joystk[i].fd);
304       joystk[i].fd = -1;
305   }
306   num_joysticks = 0;
307   joystick_started = 0;
308 }
309 
310 // open the next joystick
joy_open(char * fname)311 boolean joy_open(char *fname)
312 {
313 #define JOYNAME_LEN 511
314   char * joyname[JOYNAME_LEN+1];
315   int joyaxes;
316   int joyfd = open(fname, O_RDONLY|O_NONBLOCK);
317 
318   if(joyfd==-1) {
319     CONS_Printf("Error opening %s!\n",fname);
320     return 0;
321   }
322 
323   // Get number of axes
324   ioctl(joyfd,JSIOCGAXES,&joyaxes);
325   if(joyaxes<2) {
326     CONS_Printf("Not enought axes?\n");
327     close(joyfd);
328     return 0;
329   }
330   // Record the joystick
331   if( num_joysticks >= MAX_JOYSTICK )  return 0;
332   joystk[num_joysticks].fd = joyfd;
333   joystk[num_joysticks].numaxes = joyaxes;
334   CONS_Printf(" Properties of joystick %d:\n", num_joysticks);
335   ioctl(joyfd,JSIOCGNAME(JOYNAME_LEN), joyname)
336   CONS_Printf("    %s.\n", joyname );
337   CONS_Printf("    %d axes.\n", joyaxes);
338 //  CONS_Printf("    %d buttons.\n", );
339 //  CONS_Printf("    %d hats.\n", );
340 //  CONS_Printf("    %d trackballs.\n", );
341   num_joysticks++;
342   joystick_started = 1;
343   return 1;
344 }
345 
346 /*int joy_waitb(int fd, int *xpos,int *ypos,int *hxpos,int *hypos) {
347   int i,xps,yps,hxps,hyps;
348   struct js_event jdata;
349   for(i=0;i<1000;i++) {
350     while(read(fd,&jdata,sizeof(jdata))!=-1) {
351       switch(jdata.type) {
352       case JS_EVENT_AXIS:
353         switch(jdata.number) {
354         case 0: // x
355           xps = jdata.value;
356           break;
357         case 1: // y
358           yps = jdata.value;
359           break;
360         case 3: // hat x
361           hxps = jdata.value;
362           break;
363         case 4: // hat y
364           hyps = jdata.value;
365         default:
366           break;
367         }
368         break;
369       case JS_EVENT_BUTTON:
370         break;
371       }
372     }
373   }
374   }*/
375 #endif
376 
I_InitJoystick(void)377 void I_InitJoystick (void)
378 {
379 #ifdef LJOYSTICK
380   int i;
381 
382   I_ShutdownJoystick();
383   if(!strcmp(cv_usejoystick.string,"0"))
384     return;
385 
386   joy_open(cv_joyport.string);  // primary port
387   for(i=0; i<NUM_JOYSTICKDEV; i++ )  // other js ports
388   {
389       joy_open( joystick_dev[i] );
390   }
391   return;
392 #endif
393 }
394 
I_JoystickNumAxes(int joynum)395 int I_JoystickNumAxes (int joynum)
396 {
397 #ifdef LJOYSTICK
398     if(joynum < num_joysticks )   return joystk[joynum].joyaxes;
399 #endif
400     return 0;
401 }
402 
403 // Polling by G_BuildTiccmd
404 // Caller has individual scale conversion.
I_JoystickGetAxis(int joynum,int axisnum)405 int I_JoystickGetAxis (int joynum, int axisnum )
406 {
407 #ifdef LJOYSTICK
408     if(joynum < num_joysticks ) {
409        if( axisnum < joystk[joynum].numaxes ) {
410           return joystk[joynum].axis[axisnum];
411        }
412     }
413 #endif
414     return 0;
415 }
416 
417 
418 #ifdef LMOUSE2
I_GetMouse2Event(void)419 void I_GetMouse2Event(void)
420 {
421   static unsigned char mdata[5];
422   static int i = 0,om2b = 0;
423   int di,j,mlp,button;
424   event_t event;
425   const int mswap[8] = {0,4,1,5,2,6,3,7};
426   if(!mouse2_started) return;
427   for(mlp=0;mlp<20;mlp++) {
428     for(;i<5;i++) {
429       di = read(fdmouse2,mdata+i,1);
430       if(di==-1) return;
431     }
432     if((mdata[0]&0xf8)!=0x80) {
433       for(j=1;j<5;j++) {
434         if((mdata[j]&0xf8)==0x80) {
435           for(i=0;i<5-j;i++) { // shift
436             mdata[i] = mdata[i+j];
437           }
438         }
439       }
440       if(i<5) continue;
441     } else {
442       button = mswap[~mdata[0]&0x07];
443       for(j=0;j<MOUSEBUTTONS;j++) {
444         if(om2b&(1<<j)) {
445           if(!(button&(1<<j))) { //keyup
446             event.type = ev_keyup;
447             event.data1 = KEY_MOUSE2+j;
448             D_PostEvent(&event);
449             om2b ^= 1 << j;
450           }
451         } else {
452           if(button&(1<<j)) {
453             event.type = ev_keydown;
454             event.data1 = KEY_MOUSE2+j;
455             D_PostEvent(&event);
456             om2b ^= 1 << j;
457           }
458         }
459       }
460       event.data2 = ((signed char)mdata[1])+((signed char)mdata[3]);
461       event.data3 = ((signed char)mdata[2])+((signed char)mdata[4]);
462       if(event.data2&&event.data3) {
463         event.type = ev_mouse2;
464         event.data1 = 0;
465         D_PostEvent(&event);
466       }
467     }
468     i = 0;
469   }
470 }
471 
I_ShutdownMouse2(void)472 void I_ShutdownMouse2(void)
473 {
474   if(fdmouse2!=-1) close(fdmouse2);
475   mouse2_started = 0;
476 }
477 
478 #endif
479 
I_StartupMouse2(void)480 void I_StartupMouse2 (void)
481 {
482 #ifdef LMOUSE2
483   struct termios m2tio;
484   int i,dtr,rts;
485   I_ShutdownMouse2();
486   if(cv_usemouse2.value == 0) return;
487   if((fdmouse2 = open(cv_mouse2port.string,O_RDONLY|O_NONBLOCK|O_NOCTTY))==-1) {
488     CONS_Printf("Error opening %s!\n",cv_mouse2port.string);
489     return;
490   }
491   tcflush(fdmouse2, TCIOFLUSH);
492   m2tio.c_iflag = IGNBRK;
493   m2tio.c_oflag = 0;
494   m2tio.c_cflag = CREAD|CLOCAL|HUPCL|CS8|CSTOPB|B1200;
495   m2tio.c_lflag = 0;
496   m2tio.c_cc[VTIME] = 0;
497   m2tio.c_cc[VMIN] = 1;
498   tcsetattr(fdmouse2, TCSANOW, &m2tio);
499   strupr(cv_mouse2opt.string);
500   for(i=0,rts = dtr = -1;i<strlen(cv_mouse2opt.string);i++) {
501     if(cv_mouse2opt.string[i]=='D') {
502       if(cv_mouse2opt.string[i+1]=='-') {
503         dtr = 0;
504       } else {
505         dtr = 1;
506       }
507     }
508     if(cv_mouse2opt.string[i]=='R') {
509       if(cv_mouse2opt.string[i+1]=='-') {
510         rts = 0;
511       } else {
512         rts = 1;
513       }
514     }
515   }
516   if((dtr!=-1)||(rts!=-1)) {
517     if(!ioctl(fdmouse2, TIOCMGET, &i)) {
518       if(!dtr) {
519         i &= ~TIOCM_DTR;
520       } else {
521         if(dtr>0) i |= TIOCM_DTR;
522       }
523       if(!rts) {
524         i &= ~TIOCM_RTS;
525       } else {
526         if(rts>0) i |= TIOCM_RTS;
527       }
528       ioctl(fdmouse2, TIOCMSET, &i);
529     }
530   }
531   mouse2_started = 1;
532 #endif
533 }
534 
535 // return free and total physical memory in the system
536 
537 #define MEMINFO_FILE "/proc/meminfo"
538 #define MEMTOTAL "MemTotal:"
539 #define MEMFREE "MemFree:"
540 
I_GetFreeMem(uint64_t * total)541 uint64_t I_GetFreeMem(uint64_t *total)
542 {
543 #ifdef FREEBSD
544     unsigned page_count, free_count, pagesize;
545     size_t len = sizeof(unsigned);
546     if (sysctlbyname("vm.stats.vm.v_page_count", &page_count, &len, NULL, 0))
547       goto guess;
548     if (sysctlbyname("vm.stats.vm.v_free_count", &free_count, &len, NULL, 0))
549       goto guess;
550     if (sysctlbyname("hw.pagesize", &pagesize, &len, NULL, 0))
551       goto guess;
552     *total = (uint64_t)page_count * pagesize;
553     return (uint64_t)free_count * pagesize;
554 #else
555     char buf[1024];
556     char *memTag;
557     uint64_t freeKBytes;
558     uint64_t totalKBytes;
559     int n;
560     int meminfo_fd = -1;
561 
562     meminfo_fd = open(MEMINFO_FILE, O_RDONLY);
563     n = read(meminfo_fd, buf, 1023);
564     close(meminfo_fd);
565 
566     if(n<0)
567         goto guess;
568 
569     buf[n] = '\0';
570     if(NULL == (memTag = strstr(buf, MEMTOTAL)))
571         goto guess;
572 
573     memTag += sizeof(MEMTOTAL);
574     totalKBytes = atoi(memTag);
575 
576     if(NULL == (memTag = strstr(buf, MEMFREE)))
577         goto guess;
578 
579     memTag += sizeof(MEMFREE);
580     freeKBytes = atoi(memTag);
581 
582     *total = totalKBytes << 10;
583     return freeKBytes << 10;
584 
585  guess:
586     // make a conservative guess
587     *total = (32 << 20) + 0x01;  // guess indicator
588     return   0;
589 #endif
590 }
591 
592 
I_Tactile(int on,int off,int total)593 void I_Tactile( int   on,
594                 int   off,
595                 int   total )
596 {
597   // UNUSED.
598   on = off = total = 0;
599 }
600 
601 ticcmd_t        emptycmd;
I_BaseTiccmd(void)602 ticcmd_t*       I_BaseTiccmd(void)
603 {
604     return &emptycmd;
605 }
606 
607 //
608 // I_GetTime
609 // returns time in 1/TICRATE second tics
610 //
I_GetTime(void)611 tic_t  I_GetTime (void)
612 {
613     struct timeval      tp;
614     struct timezone     tzp;
615     int                 newtics;
616     static int          oldtics=0;
617     static int          basetime=0;
618 
619 again:
620     gettimeofday(&tp, &tzp);
621     if (!basetime)
622         basetime = tp.tv_sec;
623 
624     // On systems with RTC drift correction or NTP we need to take
625     // care about the system clock running backwards sometimes. Make
626     // sure the new tic is later then the last one.
627     newtics = (tp.tv_sec-basetime)*TICRATE + tp.tv_usec*TICRATE/1000000;
628     if (oldtics && (newtics < oldtics))
629     {
630         usleep(1);
631         goto again;
632     }
633     oldtics = newtics;
634     return newtics;
635 }
636 
637 
638 // sleeps for the given amount of milliseconds
I_Sleep(unsigned int ms)639 void I_Sleep(unsigned int ms)
640 {
641     usleep( ms * 1000 );
642 #if 0
643 #ifdef SGI
644     sginap(1);
645 #else
646 #ifdef SUN
647     sleep(0);
648 #else
649     usleep (count * (1000000/70) );
650 #endif
651 #endif
652 #endif
653 }
654 
655 #ifdef LOADING_DISK_ICON
I_BeginRead(void)656 void I_BeginRead(void)
657 {
658 }
659 
I_EndRead(void)660 void I_EndRead(void)
661 {
662 }
663 #endif
664 
665 #if 0
666 // Unused
667 byte*   I_AllocLow(int length)
668 {
669     byte*       mem;
670 
671     mem = (byte *)malloc (length);
672     memset (mem,0,length);
673     return mem;
674 }
675 #endif
676 
677 //
678 // I_Error
679 //
I_Error(const char * error,...)680 void I_Error (const char *error, ...)
681 {
682     va_list     argptr;
683 
684     // Message first.
685     va_start (argptr,error);
686     fprintf (stderr, "Error: ");
687     vfprintf (stderr,error,argptr);
688     fprintf (stderr, "\n");
689     va_end (argptr);
690 
691     fflush( stderr );
692 
693     D_Quit_Save( QUIT_panic );  // No save, safe shutdown
694 
695     exit(-1);
696 }
697 
698 // The final part of I_Quit, system dependent.
I_Quit_System(void)699 void I_Quit_System (void)
700 {
701     exit(0);
702 }
703 
704 
705 
706 #define MAX_QUIT_FUNCS     16
707 typedef void (*quitfuncptr)();
708 static quitfuncptr quit_funcs[MAX_QUIT_FUNCS] =
709                { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
710                  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
711                };
712 //
713 //  Adds a function to the list that need to be called by I_SystemShutdown().
714 //
I_AddExitFunc(void (* func)())715 void I_AddExitFunc(void (*func)())
716 {
717    int c;
718 
719    for (c=0; c<MAX_QUIT_FUNCS; c++) {
720       if (!quit_funcs[c]) {
721          quit_funcs[c] = func;
722          break;
723       }
724    }
725 }
726 
727 
728 #if 0
729 // Unused
730 //
731 //  Removes a function from the list that need to be called by
732 //   I_SystemShutdown().
733 //
734 void I_RemoveExitFunc(void (*func)())
735 {
736    int c;
737 
738    for (c=0; c<MAX_QUIT_FUNCS; c++) {
739       if (quit_funcs[c] == func) {
740          while (c<MAX_QUIT_FUNCS-1) {
741             quit_funcs[c] = quit_funcs[c+1];
742             c++;
743          }
744          quit_funcs[MAX_QUIT_FUNCS-1] = NULL;
745          break;
746       }
747    }
748 }
749 #endif
750 
751 // Shutdown joystick and other interfaces, before I_ShutdownGraphics.
I_Shutdown_IO(void)752 void I_Shutdown_IO(void)
753 {
754 #ifdef LJOYSTICK
755     I_ShutdownJoystick();
756 #endif
757 }
758 
759 //
760 //  Closes down everything. This includes restoring the initial
761 //  pallete and video mode, and removing whatever mouse, keyboard, and
762 //  timer routines have been installed.
763 //
764 //  NOTE : Shutdown user funcs. are effectively called in reverse order.
765 //
I_ShutdownSystem(void)766 void I_ShutdownSystem(void)
767 {
768    int c;
769 
770    for (c=MAX_QUIT_FUNCS-1; c>=0; c--)
771    {
772       if (quit_funcs[c])
773          (*quit_funcs[c])();
774    }
775 }
776 
I_GetDiskFreeSpace(void)777 uint64_t I_GetDiskFreeSpace(void)
778 {
779   struct statfs stfs;
780   if(statfs(".",&stfs)==-1) {
781     return INT_MAX;
782   }
783   return stfs.f_bavail*stfs.f_bsize;
784 }
785 
I_GetUserName(void)786 char *I_GetUserName(void)
787 {
788   static char username[MAXPLAYERNAME];
789   char  *p;
790   if((p=getenv("USER"))==NULL)
791     if((p=getenv("user"))==NULL)
792       if((p=getenv("USERNAME"))==NULL)
793         if((p=getenv("username"))==NULL)
794           return NULL;
795   strncpy(username,p,MAXPLAYERNAME);
796   if( strcmp(username,"")==0 )
797     return NULL;
798   return username;
799 }
800 
801 
802 // Get the directory of this program.
803 //   dirbuf: a buffer of length MAX_WADPATH,
804 // Return true when success, dirbuf contains the directory.
I_Get_Prog_Dir(char * defdir,char * dirbuf)805 boolean I_Get_Prog_Dir( char * defdir, /*OUT*/ char * dirbuf )
806 {
807     int  len;
808     char * dnp;
809 
810 #ifdef FREEBSD
811     len = readlink( "/proc/curproc/file", dirbuf, MAX_WADPATH-1 );
812     if( len > 1 )
813     {
814         dirbuf[len] = 0;  // readlink does not terminate string
815         goto got_path;
816     }
817 # if 0
818     // Sysctl to get program path.
819     {
820         // FIXME
821         int mib[4];
822         mib[0] = CTL_KERN;
823         mib[1] = KERN_PROC;
824         mib[2] = KERN_PROC_PATHNAME;
825         mib[3] = -1;
826         sysctl(mib, 4, dirbuf, MAX_WADPATH-1, NULL, 0);
827     }
828 # endif
829 #elif defined( SOLARIS )
830     len = readlink( "/proc/self/path/a.out", dirbuf, MAX_WADPATH-1 );
831     if( len > 1 )
832     {
833         dirbuf[len] = 0;  // readlink does not terminate string
834         goto got_path;
835     }
836 #  if 0
837     // [WDJ] Am missing a few details
838     getexecname();
839 #  endif
840 #else
841     // Linux
842     len = readlink( "/proc/self/exe", dirbuf, MAX_WADPATH-1 );
843     if( len > 1 )
844     {
845         dirbuf[len] = 0;  // readlink does not terminate string
846         goto got_path;
847     }
848 #endif
849 
850     // The argv[0] method
851     char * arg0p = myargv[0];
852 //    GenPrintf(EMSG_debug, "argv[0]=%s\n", arg0p );
853     // Linux, FreeBSD, Mac
854     if( arg0p[0] == '/' )
855     {
856         // argv[0] is an absolute path
857         strncpy( dirbuf, arg0p, MAX_WADPATH-1 );
858         dirbuf[MAX_WADPATH-1] = 0;
859         goto got_path;
860     }
861     // Linux, FreeBSD, Mac
862     else if( strchr( arg0p, '/' ) )
863     {
864         // argv[0] is relative to current dir
865         if( defdir )
866         {
867             cat_filename( dirbuf, defdir, arg0p );
868             goto got_path;
869         }
870     }
871     goto failed;
872 
873 got_path:
874     // Get only the directory name
875     dnp = dirname( dirbuf );
876     if( dnp == NULL )  goto failed;
877     if( dnp != dirbuf )
878     {
879         cat_filename( dirbuf, "", dnp );
880     }
881     return true;
882 
883 failed:
884     dirbuf[0] = 0;
885     return false;
886 }
887 
888 
I_mkdir(const char * dirname,int unixright)889 int  I_mkdir(const char *dirname, int unixright)
890 {
891     return mkdir(dirname, unixright);
892 }
893 
894 #if 0
895 // check if legacy.dat exists in the given path
896 static boolean isWadPathOk(char *path)
897 {
898     char wad3path[256];
899 
900     sprintf(wad3path, "%s/%s", path, WADKEYWORD);
901 
902     if(access(wad3path, R_OK)) {
903         return false; // no access
904     }
905 
906     return true;
907 }
908 
909 // search for legacy.dat in the given path
910 static char *searchWad(char *searchDir)
911 {
912     int pipeDescr[2];
913     pid_t childPid;
914     boolean finished;
915 
916     printf("Searching directory '%s' for '%s' ... please wait\n", searchDir, WADKEYWORD);
917 
918     if(pipe(pipeDescr) == -1) {
919         fprintf(stderr, "Unable to open pipe\n");
920         return NULL;
921     }
922 
923     // generate child process
924     childPid = fork();
925 
926     if(childPid == -1) {
927         fprintf(stderr, "Unable to fork\n");
928         return NULL;
929     }
930 
931     if(childPid == 0) { // here comes the child
932         close(pipeDescr[0]);
933 
934         // set stdout to pipe
935         dup2(pipeDescr[1], STDOUT_FILENO);
936 
937         // execute the find command
938         execlp("find", "find", searchDir, "-name", WADKEYWORD, NULL);
939         exit(1); // shouldn't be reached
940     }
941 
942     // parent
943     close(pipeDescr[1]);
944 
945     // now we have to wait for the output of 'find'
946     finished = false;
947 
948     while(!finished) {
949         char *namePtr;
950         int pathLen;
951 
952         pathLen = read(pipeDescr[0], returnWadPath, 256);
953 
954         if(pathLen == 0) { // end of "file" reached
955             return NULL;
956         }
957 
958         if(pathLen == -1) { // should not happen
959             fprintf(stderr, "searchWad: reading in non-blocking mode - please fix me\n");
960             return NULL;
961         }
962 
963         namePtr = strstr(returnWadPath, WADKEYWORD); // check if we read something sensible
964         if(namePtr--) {
965             *namePtr = 0; //terminate string before legacy.dat
966             finished = true;
967         }
968     }
969 
970     // kill child ... oops
971     kill(childPid, SIGKILL);
972 
973     return returnWadPath;
974 }
975 
976 // go through all possible paths and look for legacy.dat
977 static char *locateWad(void)
978 {
979     char *WadPath;
980     char *userhome;
981 
982     // does DOOMWADDIR exist?
983     WadPath = getenv("DOOMWADDIR");
984     if(WadPath) {
985         if(isWadPathOk(WadPath)) {
986             return WadPath;
987         }
988     }
989 
990     // examine current dir
991     strcpy(returnWadPath, ".");
992     if(isWadPathOk(returnWadPath)) {
993         return returnWadPath;
994     }
995 
996     // examine default dirs
997     strcpy(returnWadPath, DEFAULTWADLOCATION1);
998     if(isWadPathOk(returnWadPath)) {
999         return returnWadPath;
1000     }
1001     strcpy(returnWadPath, DEFAULTWADLOCATION2);
1002     if(isWadPathOk(returnWadPath)) {
1003         return returnWadPath;
1004     }
1005 
1006     // find in $HOME
1007     userhome = getenv("HOME");
1008     if(userhome) {
1009         WadPath = searchWad(userhome);
1010         if(WadPath) {
1011             return WadPath;
1012         }
1013     }
1014 
1015     // find in /usr/local
1016     WadPath = searchWad(DEFAULTSEARCHPATH1);
1017     if(WadPath) {
1018         return WadPath;
1019     }
1020     // find in /usr/games
1021     WadPath = searchWad(DEFAULTSEARCHPATH2);
1022     if(WadPath) {
1023         return WadPath;
1024     }
1025 
1026     // if nothing was found
1027     return NULL;
1028 }
1029 
1030 void I_LocateWad(void)
1031 {
1032     char *waddir;
1033 
1034     waddir = locateWad();
1035 
1036     if(waddir) {
1037         chdir(waddir); // change to the directory where we found legacy.dat
1038     }
1039 
1040     return;
1041 }
1042 #endif
1043 
1044 
1045 
I_SysInit(void)1046 void I_SysInit(void)
1047 {
1048   CONS_Printf("Linux X11 system ...\n");
1049 
1050   // Initialize the joystick subsystem.
1051   I_InitJoystick();
1052 
1053   // d_main will next call I_StartupGraphics
1054 }
1055