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