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-2000 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 // Revision 1.1  2001/04/17 22:23:38  calumr
21 // Revision 1.1  2000/08/21 21:17:32  metzgermeister
22 // Initial import to CVS
23 //
24 // DESCRIPTION:
25 //   Macos system interface
26 //
27 //-----------------------------------------------------------------------------
28 
29 #include <Carbon/Carbon.h>
30 
31 #include "doomincl.h"
32 #include "m_misc.h"
33 #include "i_video.h"
34 #include "i_sound.h"
35 #include "i_system.h"
36 #include "d_net.h"
37 #include "g_game.h"
38 #include "g_input.h"
39 #include "i_joy.h"
40 
41 JoyType_t Joystick;
42 
43 
44 uint16_t scantokey [128] =
45 {
46   '=',  '9',  '7',  '-',  '8',  '0',  ']',  'o',
47   'y',	't',  '1',  '2',  '3',  '4',  '6',  '5',
48   'c',	'v',    0,  'b',  'q',  'w',  'e',  'r',
49   'a',	's',  'd',  'f',  'h',  'g',  'z',  'x',
50   KEY_LSHIFT, KEY_CAPSLOCK, KEY_LALT, KEY_LCTRL, 0, 0, 0, 0,
51   KEY_TAB, KEY_SPACE, KEY_CONSOLE, KEY_BACKSPACE, 0, KEY_ESCAPE, 0, KEY_RALT,
52   'k',	';', '\\',  ',',  '/',  'n',  'm',  '.',
53   'u',	'[',  'i',  'p',  KEY_ENTER,  'l',  'j',  '\'',
54   KEY_KEYPAD6, KEY_KEYPAD7, 0, KEY_KEYPAD8, KEY_KEYPAD9, 0, 0, 0,
55   0, KEY_EQUALS, KEY_KEYPAD0, KEY_KEYPAD1, KEY_KEYPAD2, KEY_KEYPAD3, KEY_KEYPAD4, KEY_KEYPAD5,
56   0, 0, 0, KEY_KPADSLASH, KEY_KPADENTER, 0, KEY_MINUSPAD, 0,
57   '`',  KEY_KPADPERIOD, 0,  '*',  0, KEY_PLUSPAD, 0, KEY_NUMLOCK,
58   KEY_F2, KEY_PGDN, KEY_F1, KEY_LEFTARROW, KEY_RIGHTARROW, KEY_DOWNARROW, KEY_UPARROW, 0,
59   0, 0, KEY_INS, KEY_HOME, KEY_PGUP, KEY_DELETE, KEY_F4, KEY_END,
60   0, 0, 0, 0, 0, KEY_F10, 0, KEY_F12,
61   KEY_F5, KEY_F6, KEY_F7, KEY_F3, KEY_F8, KEY_F9, 0, KEY_F11,
62 };
63 
I_GetKey(void)64 int I_GetKey(void)
65 {
66     KeyMap keymap;
67     byte newBit;
68     int i,n;
69 
70     GetKeys ((unsigned long *) keymap);
71 
72     for (i=0;i<4;i++)
73     {
74         if (keymap[i])
75         {
76             for (n=0;n<32;n++)
77             {
78                 newBit = ((keymap[i] >> n) & 1);
79                 if (newBit)
80                     return scantokey[i*32+n];
81             }
82         }
83     }
84 
85     return 0;
86 }
87 
88 //
89 // I_OutputMsg
90 // Outputs message to log.txt file in Legacy folder.
91 //
92 #include <fcntl.h>
I_OutputMsg(char * error,...)93 void I_OutputMsg (char *error, ...)
94 {
95 #ifdef DEBUG_TO_FILE
96     int handle;
97     static int wipe = 1;
98     va_list     argptr;
99     char        txt[1024];
100 
101     va_start (argptr,error);
102     vsprintf (txt,error,argptr);
103     va_end   (argptr);
104 
105     printf(txt);	// Woohoo! MacOSX command-line output!
106 
107     if (wipe)
108     {
109         handle = open ("log.txt", O_WRONLY | O_APPEND | O_BINARY | O_TRUNC | O_CREAT, 0666);
110         wipe = 0;
111     }
112     else
113         handle = open ("log.txt", O_RDWR | O_APPEND | O_BINARY, 0666);
114 
115     if (handle == -1)
116         return;
117 
118     write(handle, txt, strlen(txt));
119     close(handle);
120 #endif
121 }
122 
123 //----------------------------------------------
124 //----------------------------------------------
125 // cwd (current working directory) does not apply
126 // to mac apps (unless run from terminal). Make
127 // cwd = app directory.
128 
GetApplicationFSSpec(FSSpec * me)129 void GetApplicationFSSpec(FSSpec *me)
130 {
131         ProcessInfoRec info;
132         ProcessSerialNumber psn = { 0,kCurrentProcess };
133         OSErr err;
134 
135         GetCurrentProcess(&psn);
136         memset((char*)&info,0,sizeof(info));
137         info.processInfoLength = sizeof(info);
138         info.processAppSpec = me;
139         err = GetProcessInformation(&psn,&info);
140 }
141 #include <unistd.h>
142 #include <fcntl.h>
I_GetWadDir(void)143 char *I_GetWadDir(void)
144 {
145         FSSpec app_spec;
146         FSSpec app_dir_spec;
147         FSRef app_dir;
148         UInt32 len = 256;
149         char *path;
150         OSErr err;
151 
152         GetApplicationFSSpec(&app_spec);
153 
154         FSMakeFSSpec(app_spec.vRefNum, app_spec.parID, "", &app_dir_spec);
155         FSMakeFSSpec(app_dir_spec.vRefNum, app_dir_spec.parID, "", &app_spec);
156         FSMakeFSSpec(app_spec.vRefNum, app_spec.parID, "", &app_dir_spec);
157         FSMakeFSSpec(app_dir_spec.vRefNum, app_dir_spec.parID, "", &app_spec);
158 
159         err = FSpMakeFSRef(&app_spec, &app_dir);
160 
161         path = malloc(256);
162         err = FSRefMakePath(&app_dir, path, len);
163 
164         I_OutputMsg("You double-clicked me!\n");
165 
166         chdir(path);
167 
168         return path;
169 }
170 
I_GetFreeMem(ULONG * total)171 ULONG I_GetFreeMem(ULONG *total)
172 {
173   // add 0x01 to indicate guess
174         *total = MaxBlock() - 4*1024*1024;
175         return 0;  // no freemem
176 }
177 
178 #if 0
179 static int quiting=0; /* prevent recursive I_Quit() */
180 #endif
181 
I_Tactile(int on,int off,int total)182 void I_Tactile(int on,int off,int total )
183 {
184   // Used for force feedback.
185   on = off = total = 0;
186 }
187 
188 ticcmd_t        emptycmd;
I_BaseTiccmd(void)189 ticcmd_t* I_BaseTiccmd(void)
190 {
191     return &emptycmd;
192 }
193 
194 
I_GetHeapSize(void)195 int  I_GetHeapSize (void)
196 {
197     return MaxBlock() - 4*1024*1024;	//Fix this too.
198 }
199 
I_ZoneBase(int * size)200 byte* I_ZoneBase (int*  size)
201 {
202     return NULL;
203 }
204 
205 //
206 // I_GetTime
207 // returns time in 1/TICRATE second tics
208 //
209 
I_StartupTimer(void)210 void I_StartupTimer (void)
211 {}
212 
I_GetTime(void)213 ULONG  I_GetTime (void)
214 {
215     UnsignedWide ftime;
216     static double baseTicks=0;
217     static UInt32 hiTicks=0;
218     double ticks;
219 
220     Microseconds(&ftime);
221 
222     ticks = ftime.lo/1000000.0f;
223 
224     if (!baseTicks)
225     {
226         baseTicks = ticks;
227         hiTicks = ftime.hi;
228     }
229 
230     if (hiTicks != ftime.hi)
231     {
232         baseTicks = 0;
233     }
234 
235     hiTicks = ftime.hi;
236 
237     return (ticks - baseTicks) * TICRATE;
238 }
239 
240 //
241 // I_Init
242 //
I_Init(void)243 void I_Init (void)
244 {
245     MenuBarHandle menuBar;
246 
247         /*menuBar = GetNewMBar(rMenuBar);
248     SetMenuBar(menuBar);
249         DisposeHandle(menuBar);*/
250 
251     I_StartupSound();
252     I_InitMusic();
253 #if 0
254     quiting = 0;
255 #endif
256 }
257 
258 #if 0
259 // Replaced by D_Quit_Save, I_Quit_System
260 //
261 // I_Quit
262 //
263 void I_Quit (void)
264 {
265     /* prevent recursive I_Quit() */
266     if(quiting)
267         return;
268     quiting = 1;
269     if (demorecording)
270         G_CheckDemoStatus();
271     W_Shutdown();
272     D_Quit_NetGame();
273     I_ShutdownMusic();
274     I_ShutdownSound();
275 #ifdef CDMUS
276     I_ShutdownCD();
277 #endif
278     M_SaveConfig (NULL);
279     I_ShutdownGraphics();
280     I_ShutdownInput();
281     I_OutputMsg("Nice knowing you...\n");
282     ExitToShell();
283 }
284 #endif
285 
286 // sleeps for the given amount of milliseconds
I_Sleep(unsigned int ms)287 void I_Sleep(unsigned int ms)
288 {
289     usleep( ms * 1000 );
290 }
291 
292 #ifdef LOADING_DISK_ICON
I_BeginRead(void)293 void I_BeginRead(void)
294 {
295       //can be used to show a "loading..." thing
296       //but it would appear for only a fraction of a second.
297 }
298 
I_EndRead(void)299 void I_EndRead(void)
300 {}
301 #endif
302 
303 
304 //
305 // I_Error
306 //
307 extern boolean demorecording;
308 
I_Error(char * error,...)309 void I_Error (char *error, ...)
310 {
311     va_list     argptr;
312     char        txt[1024];
313 
314     va_start (argptr,error);
315     vsprintf (txt,error,argptr);
316     va_end   (argptr);
317 
318     {
319         SInt16 res;
320         c2pstr(txt);
321 
322         StandardAlert(kAlertStopAlert,"\pError:",(ConstStr255Param)txt,NULL,&res);
323     }
324 
325 #if 1
326     D_Quit_Save( QUIT_panic );  // No save, safe shutdown
327 #else
328     // Shutdown. Here might be other errors.
329     if (demorecording)
330         G_CheckDemoStatus();
331     W_Shutdown();
332     D_Quit_NetGame();
333     I_ShutdownMusic();
334     I_ShutdownSound();
335     I_Sleep( 3000 );  // to see some messages
336     I_ShutdownGraphics();
337     I_ShutdownInput();
338 
339     I_OutputMsg("Error: %s. \n",txt);
340     ExitToShell();
341 #endif
342 }
343 
344 // The final part of I_Quit, system dependent.
I_Quit_System(void)345 void I_Quit_System (void)
346 {
347     ExitToShell();
348 }
349 
350 // Shutdown joystick and other interfaces, before I_ShutdownGraphics.
I_Shutdown_IO(void)351 void I_Shutdown_IO(void)
352 {
353 #ifdef LJOYSTICK
354     I_ShutdownJoystick();
355 #endif
356 }
357 
I_ShutdownSystem(void)358 void I_ShutdownSystem(void)
359 {
360 }
361 
362 
I_GetDiskFreeSpace(long long * freespace)363 void I_GetDiskFreeSpace(long long *freespace) {
364     // 10MB should be enough
365     *freespace = 10*1024*1024;
366 }
367 
I_GetUserName(void)368 char *I_GetUserName(void)
369 {
370     return getenv("USER");
371 }
372 
373 
374 // Get the directory of this program.
375 //   defdir: the current directory
376 //   dirbuf: a buffer of length MAX_WADPATH,
377 // Return true when success, dirbuf contains the directory.
I_Get_Prog_Dir(char * defdir,char * dirbuf)378 boolean I_Get_Prog_Dir( char * defdir, /*OUT*/ char * dirbuf )
379 {
380     char * dnp;
381 
382 #ifdef __MACH__
383     // FIXME
384 #  if 0
385     uint32_t  bufsize = MAX_WADPATH-1;
386     // [WDJ] Am missing a few details
387     if( _NSGetExecutablePath( dirbuf, & bufsize ) == 0 )   goto got_path;
388 #  endif
389 #endif
390 
391     // The argv[0] method
392     char * arg0p = myargv[0];
393 //    GenPrintf(EMSG_debug, "argv[0]=%s\n", arg0p );
394     // Linux, FreeBSD, Mac
395     if( arg0p[0] == '/' )
396     {
397         // argv[0] is an absolute path
398         strncpy( dirbuf, arg0p, MAX_WADPATH-1 );
399         dirbuf[MAX_WADPATH-1] = 0;
400         goto got_path;
401     }
402     // Linux, FreeBSD, Mac
403     else if( strchr( arg0p, '/' ) )
404     {
405         // argv[0] is relative to current dir
406         if( defdir )
407         {
408             cat_filename( dirbuf, defdir, arg0p );
409             goto got_path;
410         }
411     }
412     goto failed;
413 
414 got_path:
415     // Get only the directory name
416     dnp = dirname( dirbuf );
417     if( dnp == NULL )  goto failed;
418     if( dnp != dirbuf )
419     {
420         cat_filename( dirbuf, "", dnp );
421     }
422     return true;
423 
424 failed:
425     dirbuf[0] = 0;
426     return false;
427 }
428 
429 
I_mkdir(const char * dirname,int unixright)430 int  I_mkdir(const char *dirname, int unixright)
431 {
432     return mkdir(dirname, unixright);
433 }
434 
I_LocateWad(void)435 void I_LocateWad(void)
436 {
437 }
438 
439 
440 // [WDJ] Copied from sdl/filesrch.c, but not tested.
441 #include <stdio.h>
442 #include <dirent.h>
443 #include <fcntl.h>
444 #include <sys/stat.h>
445 #include <unistd.h>
446 #include <string.h>
447 #include <stdlib.h>
448 
449 #include "d_netfil.h"
450 
451 #define MAX_SRCHPATH (MAX_WADPATH * 2)
452 
453 //
454 // sys_filesearch:
455 //
456 //  filename : the filename to be found
457 //  wantedmd5sum : NULL for no md5 check
458 //  completepath : when not NULL, return the full path and name
459 //      must be a buffer of MAX_WADPATH
460 //  maxsearchdepth : dir depth, when 0 only search given directory
461 // return FS_NOTFOUND
462 //        FS_MD5SUMBAD
463 //        FS_FOUND
464 
sys_filesearch(const char * filename,const char * startpath,const byte * wantedmd5sum,int maxsearchdepth,char * completepath)465 filestatus_e  sys_filesearch( const char * filename, const char * startpath,
466                               const byte * wantedmd5sum, int maxsearchdepth,
467                               /*OUT*/ char * completepath )
468 {
469     filestatus_e retval = FS_NOTFOUND;
470     DIR ** dirhandle_stack;  // (malloc)
471     DIR * dirhandle;
472     int * index_stack;  // each directory in the searchpath  (malloc)
473     int depth=0;
474     struct dirent *dent;
475     struct stat fstat;
476     int cur_index, remspace;  // searchpath
477     char searchpath[MAX_SRCHPATH];
478 
479     if( maxsearchdepth < 1 )
480        maxsearchdepth = 0;
481     dirhandle_stack = (DIR**) malloc( (maxsearchdepth+1) * sizeof( DIR*));
482     if( dirhandle_stack == NULL )   goto error1_exit;
483     index_stack = (int*) malloc( (maxsearchdepth+1) * sizeof(int));
484     if( index_stack == NULL )   goto error2_exit;
485 
486     strncpy( searchpath, startpath, MAX_SRCHPATH-1 );
487     searchpath[MAX_SRCHPATH-1] = '\0';
488     cur_index = strlen( searchpath) + 1;
489 
490     dirhandle = opendir( searchpath);
491     if( dirhandle == NULL )  goto error3_exit;
492 
493     // Initial stack
494     index_stack[0] = cur_index;
495     dirhandle_stack[0] = dirhandle;
496 
497     if(searchpath[cur_index-2] != '/')
498     {
499         searchpath[cur_index-1] = '/';
500         searchpath[cur_index] = 0;
501     }
502     else
503     {
504         cur_index--;
505     }
506 
507     for(;;)
508     {
509         searchpath[cur_index]=0;
510         dent = readdir( dirhandle );  // next dir entry
511         if( !dent)  // done with dir
512         {
513             closedir( dirhandle );
514             // Pop stack to previous directory.
515 	    if( depth == 0 )  break;  // done
516             cur_index = index_stack[--depth];
517             dirhandle = dirhandle_stack[depth];
518             continue;
519         }
520         if( dent->d_name[0]=='.' )
521         {
522             // ignore the "." and ".." entries, we don't want to scan uptree
523             if( dent->d_name[1]=='\0' )  continue;
524             if( dent->d_name[1]=='.' && dent->d_name[2]=='\0' )  continue;
525         }
526 
527         // Form file name for stat.
528         remspace = (MAX_SRCHPATH - 1) - cur_index;
529         strncpy(&searchpath[cur_index], dent->d_name, remspace);
530 
531         if( stat(searchpath,&fstat) < 0) // do we want to follow symlinks? if not: change it to lstat
532         {
533             // was the file (re)moved? can't stat it
534             continue;
535         }
536 
537         if( S_ISDIR(fstat.st_mode) )
538         {
539             if( depth >= maxsearchdepth )  continue;  // depth limited
540 
541             dirhandle = opendir(searchpath);
542             if( dirhandle == NULL )
543             {
544                 // can't open it... maybe no read-permissions
545                 // go back to previous dir
546                 cur_index = index_stack[depth];
547                 dirhandle = dirhandle_stack[depth];
548                 continue;
549             }
550 
551             // Push new directory to stack.
552             cur_index = strlen(searchpath) + 1;
553             index_stack[++depth] = cur_index;
554             dirhandle_stack[depth] = dirhandle;
555 
556             searchpath[cur_index-1]='/';
557             searchpath[cur_index]=0;
558         }
559         else if ( strcasecmp(filename, dent->d_name) == 0 )
560         {
561             // Found the filename.
562             retval = checkfile_md5(searchpath, wantedmd5sum);
563             if( retval != FS_FOUND )  continue;
564 
565             // FS_FOUND, Return the found file.
566 	    if(completepath)
567             {
568                 strncpy(completepath, searchpath, MAX_WADPATH-1);
569                 completepath[MAX_WADPATH-1] = '\0';
570             }
571             // Close the open directories.
572             for(; depth >= 0; closedir(dirhandle_stack[depth--]));
573             break;
574         }
575     }
576 
577 error3_exit:
578     free(index_stack);
579 error2_exit:
580     free(dirhandle_stack);
581 error1_exit:
582 
583     return retval;
584 }
585