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