Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
emutools.c
Go to the documentation of this file.
1 /* Xemu - emulation (running on Linux/Unix/Windows/OSX, utilizing SDL2) of some
2  8 bit machines, including the Commodore LCD and Commodore 65 and MEGA65 as well.
3  Copyright (C)2016-2022 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
18 
19 #include "xemu/emutools.h"
20 
21 #include <string.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <sys/time.h>
28 #include <time.h>
29 #include <limits.h>
30 #include <errno.h>
31 #ifdef XEMU_ARCH_UNIX
32 # include <signal.h>
33 # include <sys/utsname.h>
34 #endif
35 
36 #ifdef XEMU_MISSING_BIGGEST_ALIGNMENT_WORKAROUND
37 # warning "System did not define __BIGGEST_ALIGNMENT__ Xemu assumes some default value."
38 #endif
39 #ifdef XEMU_OVERSIZED_BIGGEST_ALIGNMENT_WORKAROUND
40 # warning "System deifned __BIGGEST_ALIGNMENT__ just too big Xemu will use a smaller default."
41 #endif
42 #ifdef XEMU_CPU_ARM
43 # warning "Compiling for ARM CPU. Some features of Xemu won't be avaialble because of usual limits of OSes (MacOS, Linux) on the ARM architecture."
44 # ifdef XEMU_ARCH_OSX
45 # warning "WOW! Are you on Apple M1?! Call me now!"
46 # endif
47 #endif
48 
49 #ifdef XEMU_ARCH_WIN
50 # include <windows.h>
51 # include <stdio.h>
52 # include <io.h>
53 # include <fcntl.h>
54 # include <math.h>
55 #endif
56 
57 const char EMPTY_STR[] = "";
58 const int ZERO_INT = 0;
59 const int ONE_INT = 1;
60 
61 #ifndef XEMU_NO_SDL_DIALOG_OVERRIDE
62 int (*SDL_ShowSimpleMessageBox_custom)(Uint32, const char*, const char*, SDL_Window* ) = SDL_ShowSimpleMessageBox;
63 int (*SDL_ShowMessageBox_custom)(const SDL_MessageBoxData*, int* ) = SDL_ShowMessageBox;
64 #endif
65 
66 #ifdef XEMU_ARCH_MAC
67 int macos_gui_started = 0;
68 #endif
69 
70 #ifdef XEMU_ARCH_WIN
71 static int atexit_callback_for_console_registered = 0;
72 #endif
73 
75 const char *str_are_you_sure_to_exit = "Are you sure to exit Xemu?";
76 
77 SDL_Window *sdl_win = NULL;
78 SDL_Renderer *sdl_ren = NULL;
79 SDL_Texture *sdl_tex = NULL;
80 SDL_PixelFormat *sdl_pix_fmt;
82 static Uint32 sdl_pixel_format_id;
83 static const char default_window_title[] = "XEMU";
85 char *xemu_app_org = NULL, *xemu_app_name = NULL;
86 #ifdef XEMU_ARCH_HTML
87 static const char *emscripten_sdl_base_dir = EMSCRIPTEN_SDL_BASE_DIR;
88 #endif
89 char *sdl_window_title = (char*)default_window_title;
96 static int win_xsize, win_ysize;
97 char *sdl_pref_dir = NULL, *sdl_base_dir = NULL, *sdl_inst_dir = NULL;
99 static Uint32 black_colour;
100 static void (*shutdown_user_function)(void) = NULL;
103 static char *window_title_buffer, *window_title_buffer_end;
104 static struct timeval unix_time_tv;
105 static Uint64 et_old;
106 static int td_balancer, td_em_ALL, td_pc_ALL;
107 static Uint64 td_stat_counter = 0, td_stat_sum = 0;
108 static int td_stat_min = INT_MAX, td_stat_max = INT_MIN;
110 FILE *debug_fp = NULL;
111 int chatty_xemu = 1;
114 static SDL_Rect sdl_viewport, *sdl_viewport_ptr = NULL;
115 static unsigned int sdl_texture_x_size, sdl_texture_y_size;
116 
117 static SDL_bool grabbed_mouse = SDL_FALSE, grabbed_mouse_saved = SDL_FALSE;
119 static int sdl_viewport_changed;
120 static int follow_win_size;
121 
122 #if !SDL_VERSION_ATLEAST(2, 0, 4)
123 #error "At least SDL version 2.0.4 is needed!"
124 #endif
125 
126 #ifdef XEMU_OSD_SUPPORT
127 #include "xemu/gui/osd.c"
128 #endif
129 
130 
131 int set_mouse_grab ( SDL_bool state, int force_allow )
132 {
133  if (state && (!allow_mouse_grab || force_allow))
134  return 0;
135  else if (state != grabbed_mouse) {
136  grabbed_mouse = state;
137  SDL_SetRelativeMouseMode(state);
138  SDL_SetWindowGrab(sdl_win, state);
139  return 1;
140  } else
141  return 0;
142 }
143 
144 
145 SDL_bool is_mouse_grab ( void )
146 {
147  return grabbed_mouse;
148 }
149 
150 
151 void save_mouse_grab ( void )
152 {
153  grabbed_mouse_saved = grabbed_mouse;
154  set_mouse_grab(SDL_FALSE, 1);
155 }
156 
157 
158 void restore_mouse_grab ( void )
159 {
160  set_mouse_grab(grabbed_mouse_saved, 1);
161 }
162 
163 
164 static inline int get_elapsed_time ( Uint64 t_old, Uint64 *t_new, struct timeval *store_time )
165 {
166 #ifdef XEMU_OLD_TIMING
167 #define __TIMING_METHOD_DESC "gettimeofday"
168  struct timeval tv;
169  gettimeofday(&tv, NULL);
170  if (store_time) {
171  store_time->tv_sec = tv.tv_sec;
172  store_time->tv_usec = tv.tv_usec;
173  }
174  *t_new = tv.tv_sec * 1000000UL + tv.tv_usec;
175  return *t_new - t_old;
176 #else
177 #define __TIMING_METHOD_DESC "SDL_GetPerformanceCounter"
178  if (store_time)
179  gettimeofday(store_time, NULL);
180  *t_new = SDL_GetPerformanceCounter();
181  return 1000000UL * (*t_new - t_old) / SDL_GetPerformanceFrequency();
182 #endif
183 }
184 
185 
186 
187 struct tm *xemu_get_localtime ( void )
188 {
189 #ifdef XEMU_ARCH_WIN64
190  // Fix a potentional issue with Windows 64 bit ...
191  const time_t temp = unix_time_tv.tv_sec;
192  return localtime(&temp);
193 #else
194  return localtime(&unix_time_tv.tv_sec);
195 #endif
196 }
197 
198 
199 time_t xemu_get_unixtime ( void )
200 {
201  return unix_time_tv.tv_sec;
202 }
203 
204 
205 unsigned int xemu_get_microseconds ( void )
206 {
207  return unix_time_tv.tv_usec;
208 }
209 
210 
211 Uint8 xemu_hour_to_bcd12h ( Uint8 hours, int hour_offset )
212 {
213  // hour offset is only an ugly hack to shift hour for testing! The value can be negative too, and over/under-flow of the 0-23 hours range
214  hours = abs((int)hours + hour_offset) % 24;
215  if (hours == 0)
216  return 0x12; // 00:mm -> 12:mmAM for HH = 0 (0x12 is BCD representation of 12)
217  else if (hours < 12)
218  return XEMU_BYTE_TO_BCD(hours); // HH:mm -> HH:mmAM for 0 < HH < 12
219  else if (hours == 12)
220  return 0x12 + 0x80; // 12:mm -> 12:mmPM for HH = 12 (0x80 is PM flag, 0x12 is BCD representation of 12)
221  else
222  return XEMU_BYTE_TO_BCD(hours - 12) + 0x80; // HH:mm -> HH:mmPM for HH > 12 (0x80 is PM flag)
223 }
224 
225 
226 void *xemu_malloc ( size_t size )
227 {
228  void *p = malloc(size);
229  if (XEMU_UNLIKELY(!p))
230  FATAL("Cannot allocate %d bytes of memory.", (int)size);
231  return p;
232 }
233 
234 
235 void *xemu_realloc ( void *p, size_t size )
236 {
237  p = realloc(p, size);
238  if (XEMU_UNLIKELY(!p))
239  FATAL("Cannot re-allocate %d bytes of memory.", (int)size);
240  return p;
241 }
242 
243 
245 {
247  unsigned int reminder = (unsigned int)((uintptr_t)p % (uintptr_t)__BIGGEST_ALIGNMENT__);
248  DEBUG("ALIGNED-ALLOC: using malloc(): base_pointer=%p size=%d need_alignment_of=%d reminder=%d" NL, p, (int)size, __BIGGEST_ALIGNMENT__, reminder);
249  if (reminder) {
250  void *p_old = p;
251  p += __BIGGEST_ALIGNMENT__ - reminder;
252  DEBUGPRINT("ALIGNED-ALLOC: malloc() alignment-workaround: correcting alignment %p -> %p (reminder: %u, need_alignment_of: %u)" NL, p_old, p, reminder, __BIGGEST_ALIGNMENT__);
253  } else
254  DEBUG("ALIGNED-ALLOC: malloc() alignment-workaround: alignment was OK already" NL);
255  return p;
256 }
257 #ifdef HAVE_MM_MALLOC
258 #ifdef XEMU_ARCH_WIN
259 extern void *_mm_malloc ( size_t size, size_t alignment ); // it seems mingw/win has issue not to define this properly ... FIXME? Ugly windows, always the problems ...
260 #endif
261 void *xemu_malloc_ALIGNED ( size_t size )
262 {
263  // it seems _mm_malloc() is quite standard at least on gcc, mingw, clang ... so let's try to use it
264  // unfortunately even the C11 standard (!) for this does not seem to work on Windows neither on Mac :(
265  void *p = _mm_malloc(size, __BIGGEST_ALIGNMENT__);
266  DEBUG("ALIGNED-ALLOC: using _mm_malloc(): base_pointer=%p size=%d alignment=%d" NL, p, (int)size, __BIGGEST_ALIGNMENT__);
267  if (p == NULL) {
268  DEBUGPRINT("ALIGNED-ALLOC: _mm_malloc() failed, errno=%d[%s] ... defaulting to malloc()" NL, errno, strerror(errno));
270  }
271  return p;
272 }
273 #else
274 #warning "No _mm_malloc() for this architecture ..."
275 #endif
276 
277 
278 char *xemu_strdup ( const char *s )
279 {
280  char *p = strdup(s);
281  if (XEMU_UNLIKELY(!p))
282  FATAL("Cannot allocate memory for strdup()");
283  return p;
284 }
285 
286 void xemu_restrdup ( char **ptr, const char *str )
287 {
288  size_t len = strlen(str) + 1;
289  *ptr = xemu_realloc(*ptr, len);
290  memcpy(*ptr, str, len);
291 }
292 
293 // Just drop queued SDL events ...
294 void xemu_drop_events ( void )
295 {
296  SDL_PumpEvents();
297  SDL_FlushEvent(SDL_KEYDOWN);
298  SDL_FlushEvent(SDL_KEYUP);
299  SDL_FlushEvent(SDL_MOUSEMOTION);
300  SDL_FlushEvent(SDL_MOUSEWHEEL);
301  SDL_FlushEvent(SDL_MOUSEBUTTONDOWN);
302  SDL_FlushEvent(SDL_MOUSEBUTTONUP);
303 }
304 
305 
306 /* Meaning of "setting":
307  -1 (or any negative integer): toggle, switch between fullscreen / windowed mode automatically depending on the previous state
308  0: set windowed mode (if it's not that already, then nothing will happen)
309  1 (or any positive integer): set full screen mode (if it's not that already, then nothing will happen)
310 */
311 void xemu_set_full_screen ( int setting )
312 {
313  if (setting > 1)
314  setting = 1;
315  if (setting < 0)
316  setting = !emu_is_fullscreen;
317  if (setting == emu_is_fullscreen)
318  return; // do nothing, already that!
319  if (setting) {
320  // entering into full screen mode ....
321  SDL_GetWindowSize(sdl_win, &win_xsize, &win_ysize); // save window size, it seems there are some problems with leaving fullscreen then
322  if (SDL_SetWindowFullscreen(sdl_win, SDL_WINDOW_FULLSCREEN_DESKTOP)) {
323  fprintf(stderr, "Cannot enter full screen mode: %s" NL, SDL_GetError());
324  } else {
325  emu_is_fullscreen = 1;
326  DEBUGPRINT("UI: entering fullscreen mode." NL);
327  }
328  } else {
329  // leaving full screen mode ...
330  if (SDL_SetWindowFullscreen(sdl_win, 0)) {
331  fprintf(stderr, "Cannot leave full screen mode: %s" NL, SDL_GetError());
332  } else {
333  emu_is_fullscreen = 0;
334  DEBUGPRINT("UI: leaving fullscreen mode." NL);
335  SDL_SetWindowSize(sdl_win, win_xsize, win_ysize); // restore window size saved on leaving fullscreen, there can be some bugs ...
336  }
337  }
338  SDL_RaiseWindow(sdl_win); // I have some problems with EP128 emulator that window went to the background. Let's handle that with raising it anyway :)
339 }
340 
341 
342 // 0 = full screen, 1 = default window size, 2 = zoom 200%, 3 = zoom 300%, 4 = zoom 400%
343 void xemu_set_screen_mode ( int setting )
344 {
345  if (setting <= 0) {
347  } else {
349  SDL_SetWindowSize(sdl_win, sdl_default_win_x_size * setting, sdl_default_win_y_size * setting);
350  }
351  SDL_RaiseWindow(sdl_win);
352 }
353 
354 
355 static inline void do_sleep ( int td )
356 {
357 #ifdef XEMU_ARCH_HTML
358 #define __SLEEP_METHOD_DESC "emscripten_set_main_loop_timing"
359  // Note: even if td is zero (or negative ...) give at least a little time for the browser
360  // do not detect the our JS script as a run-away one, suggesting to kill ...
361  // Note: this is not an actual sleep, we can't do that in JS. Instead of just "throttle"
362  // the "frequency" our main loop is called. This also means, that do_sleep should be
363  // called as last in case of emscripten target, since this does not sleep at all for real,
364  // unlike the other sleep methods for non-js targets.
365  emscripten_set_main_loop_timing(EM_TIMING_SETTIMEOUT, td > 999 ? td / 1000 : 1);
366 #elif defined(XEMU_SLEEP_IS_SDL_DELAY)
367 #define __SLEEP_METHOD_DESC "SDL_Delay"
368  if (td > 0)
369  SDL_Delay(td / 1000);
370 #elif defined(XEMU_SLEEP_IS_USLEEP)
371 #define __SLEEP_METHOD_DESC "usleep"
372  if (td > 0)
373  usleep(td);
374 #elif defined(XEMU_SLEEP_IS_NANOSLEEP)
375 #define __SLEEP_METHOD_DESC "nanosleep"
376  struct timespec req, rem;
377  if (td <= 0)
378  return;
379  td *= 1000;
380  req.tv_sec = td / 1000000000UL;
381  req.tv_nsec = td % 1000000000UL;
382  for (;;) {
383  if (nanosleep(&req, &rem)) {
384  if (errno == EINTR) {
385  req.tv_sec = rem.tv_sec;
386  req.tv_nsec = rem.tv_nsec;
387  } else
388  FATAL("nanosleep() returned with unhandable error");
389  } else
390  return;
391  }
392 #else
393 #error "No SLEEP method is defined with XEMU_SLEEP_IS_* macros!"
394 #endif
395 }
396 
397 
398 /* Should be called regularly (eg on each screen global update), this function
399  tries to keep the emulation speed near to real-time of the emulated machine.
400  It's assumed that this function is called at least at every 0.1 sec or even
401  more frequently ... Ideally it should be used at 25Hz rate (for PAL full TV
402  frame) or 50Hz (for PAL half frame).
403  Input: td_em: time in microseconds would be need on the REAL (emulated)
404  machine to do the task, since the last call of this function! */
405 void xemu_timekeeping_delay ( int td_em )
406 {
407  int td, td_pc;
408  time_t old_unix_time = unix_time_tv.tv_sec;
409  Uint64 et_new;
410  td_pc = get_elapsed_time(et_old, &et_new, NULL); // get realtime since last call in microseconds
411  if (td_pc < 0) return; // time goes backwards? maybe time was modified on the host computer. Skip this delay cycle
412  td = td_em - td_pc; // the time difference (+X = emu is faster (than emulated machine) - real time emulation, -X = emu is slower - real time emulation is not possible)
413  td_balancer += td;
414  if (td_balancer > 0)
415  do_sleep(td_balancer);
416  /* Purpose:
417  * get the real time spent sleeping (sleep is not an exact science on a multitask OS)
418  * also this will get the starter time for the next frame
419  */
420  // calculate real time slept
421  td = get_elapsed_time(et_new, &et_old, &unix_time_tv);
422  seconds_timer_trigger = (unix_time_tv.tv_sec != old_unix_time);
423  if (seconds_timer_trigger) {
424  snprintf(window_title_buffer_end, 64, " [%d%% %d%%] %s %s",
425  ((td_em_ALL < td_pc_ALL) && td_pc_ALL) ? td_em_ALL * 100 / td_pc_ALL : 100,
426  td_em_ALL ? (td_pc_ALL * 100 / td_em_ALL) : -1,
429  );
430  SDL_SetWindowTitle(sdl_win, window_title_buffer);
431  td_pc_ALL = td_pc;
432  td_em_ALL = td_em;
433  } else {
434  td_pc_ALL += td_pc;
435  td_em_ALL += td_em;
436  }
437  // Some statistics
438  if (td_em_ALL > 0 && td_pc_ALL > 0) {
439  int stat = td_pc_ALL * 100 / td_em_ALL;
440  td_stat_counter++;
441  td_stat_sum += stat;
442  if (stat > td_stat_max)
443  td_stat_max = stat;
444  if (stat < td_stat_min && stat)
445  td_stat_min = stat;
446  }
447  // Check: invalid, sleep was about for _minus_ time? eh, give me that time machine, dude! :)
448  if (td < 0)
449  return;
450  // Balancing real and wanted sleep time on long run
451  // Insane big values are forgotten, maybe emulator was stopped, or something like that
452  td_balancer -= td;
453  if (td_balancer > 1000000)
454  td_balancer = 0;
455  else if (td_balancer < -1000000) {
456  // reaching this means the anomaly above, OR simply the fact, that emulator is too slow to emulate in real time!
457  td_balancer = 0;
458  }
459 }
460 
461 
462 static void atexit_callback_for_console ( void )
463 {
464  sysconsole_close("Please review the console content (if you need it) before exiting!");
465 }
466 
467 
468 const char *xemu_get_uname_string ( void )
469 {
470 #ifdef XEMU_ARCH_UNIX
471  static const char *result = NULL;
472  if (!result) {
473  char buf[1024];
474  struct utsname uts;
475  uname(&uts);
476  if (snprintf(buf, sizeof buf, "%s %s %s %s %s",
477  uts.sysname, uts.nodename,
478  uts.release, uts.version, uts.machine
479  ) >= sizeof buf) {
480  strcpy(buf, "<buffer-is-too-small>");
481  }
482  result = xemu_strdup(buf);
483  }
484  return result;
485 #elif defined(XEMU_ARCH_WIN)
486  static const char *result = NULL;
487  if (!result) {
488  char buf[1024];
489  char host_name[128];
490  DWORD size_used = sizeof host_name;
491  if (!GetComputerNameA(host_name, &size_used))
492  strcpy(host_name, "<?name?>");
493  // query version, strange windows have no simple way and/or "obsoleted" to get version number :(
494  // Also functions like this GetVersionEx and such are strange, for example it needs LPOSVERSIONINFOA pointer
495  // according to mingw at least rather than the documented LPOSVERSIONINFOA ... Huh??
496  OSVERSIONINFOA info;
497  ZeroMemory(&info, sizeof info);
498  info.dwOSVersionInfoSize = sizeof info;
499  GetVersionEx(&info);
500  // query architecture
501  SYSTEM_INFO sysinfo;
502  GetNativeSystemInfo(&sysinfo);
503  //WORD w = sysinfo.DUMMYUNIONNAME.DUMMYSTRUCTNAME.wProcessorArchitecture; What is this shit? Windows is horrible ...
504  const char *isa_name = "(Xemu-unknown-ISA)";
505  switch (sysinfo.wProcessorArchitecture) {
506  case 9: // PROCESSOR_ARCHITECTURE_AMD64: x86_64 (intel or AMD)
507  isa_name = "x86_64"; break;
508  case 5: // PROCESSOR_ARCHITECTURE_ARM
509  isa_name = "ARM"; break;
510  case 12: // PROCESSOR_ARCHITECTURE_ARM64
511  isa_name = "ARM64"; break;
512  case 6: // PROCESSOR_ARCHITECTURE_IA64 (itanium, heh)
513  isa_name = "Itanium"; break;
514  case 0: // PROCESSOR_ARCHITECTURE_INTEL (32 bit x86?)
515  isa_name = "x86"; break;
516  case 0xffff: // PROCESSOR_ARCHITECTURE_UNKNOWN
517  isa_name = "(Windows-unknown-ISA)";
518  break;
519  }
520  // Huh, Windows is a real pain to collect _basic_ system informations ... on UNIX just an uname() and you're done ...
521  if (snprintf(buf, sizeof buf, "Windows %s %u.%u %s",
522  host_name,
523  (unsigned int)info.dwMajorVersion, (unsigned int)info.dwMinorVersion,
524  isa_name
525  ) >= sizeof buf) {
526  strcpy(buf, "<buffer-is-too-small>");
527  }
528  result = xemu_strdup(buf);
529  }
530  return result;
531 #else
532  static const char result[] = XEMU_ARCH_NAME " (Xemu-no-uname)";
533  return result;
534 #endif
535 }
536 
537 
538 void xemu_get_timing_stat_string ( char *buf, unsigned int size )
539 {
540  if (td_stat_counter) {
541  Uint32 ticks = SDL_GetTicks() / 1000;
542  snprintf(buf, size,
543  "avg=%.2f%%, min=%d%%, max=%d%% (%u counts), uptime=%02d:%02d",
544  td_stat_sum / (double)td_stat_counter,
545  td_stat_min == INT_MAX ? 0 : td_stat_min,
546  td_stat_max,
547  (unsigned int)td_stat_counter,
548  ticks / 60, ticks % 60
549  );
550  } else
551  snprintf(buf, size, "Currently unavailable");
552 }
553 
554 
555 static void shutdown_emulator ( void )
556 {
557  DEBUG("XEMU: Shutdown callback function has been called." NL);
558  if (shutdown_user_function)
559  shutdown_user_function();
560  if (sdl_win) {
561  SDL_DestroyWindow(sdl_win);
562  sdl_win = NULL;
563  }
564  atexit_callback_for_console();
565  //SDL_Quit();
566  if (td_stat_counter) {
567  char td_stat_str[XEMU_CPU_STAT_INFO_BUFFER_SIZE];
568  xemu_get_timing_stat_string(td_stat_str, sizeof td_stat_str);
569  DEBUGPRINT(NL "TIMING: Xemu CPU usage: %s" NL "XEMU: good by(T)e." NL, td_stat_str);
570  }
571  if (debug_fp) {
572  fclose(debug_fp);
573  debug_fp = NULL;
574  }
575  // It seems, calling SQL_Quit() at least on Windows causes "segfault".
576  // Not sure why, but to be safe, I just skip calling it :(
577  //SDL_Quit();
578 }
579 
580 
581 
582 int xemu_init_debug ( const char *fn )
583 {
584 #ifdef DISABLE_DEBUG
585  printf("Logging is disabled at compile-time." NL);
586 #else
587  if (debug_fp) {
588  ERROR_WINDOW("Debug file %s already used, you can't call emu_init_debug() twice!\nUse it before emu_init_sdl() if you need it!", fn);
589  return 1;
590  } else if (fn) {
591  debug_fp = fopen(fn, "wb");
592  if (!debug_fp) {
593  ERROR_WINDOW("Cannot open requested debug file: %s", fn);
594  return 1;
595  }
596  DEBUGPRINT("Logging into file: %s (fd=%d)." NL, fn, fileno(debug_fp));
598  return 0;
599  }
600 #endif
601  return 0;
602 }
603 
604 
605 #ifndef XEMU_ARCH_HTML
606 static char *GetHackedPrefDir ( const char *base_path, const char *name )
607 {
608  static const char prefdir_is_here_marker[] = "prefdir-is-here.txt";
609  char path[PATH_MAX];
610  sprintf(path, "%s%s%c", base_path, name, DIRSEP_CHR);
611  char file[PATH_MAX + sizeof(prefdir_is_here_marker)];
612  sprintf(file, "%s%s", path, prefdir_is_here_marker);
613  int fd = open(file, O_RDONLY | O_BINARY);
614  if (fd < 0)
615  return NULL;
616  close(fd);
617  return xemu_strdup(path);
618 }
619 #endif
620 
621 
622 // "First time user" check. We use SDL file functions here only, to be implementation independent (ie, no need for emutools_files.c ...)
624 {
625  static int is_first_time_user = -1;
626  if (is_first_time_user >= 0)
627  return is_first_time_user;
628  char fn[PATH_MAX];
629  snprintf(fn, sizeof fn, "%s%s", sdl_pref_dir, "notfirsttimeuser.txt");
630  SDL_RWops *file = SDL_RWFromFile(fn, "rb");
631  if (file) {
632  SDL_RWclose(file);
633  is_first_time_user = 0; // not first time user
634  return is_first_time_user;
635  }
636  // First time user, it seems, since we don't have our file
637  // Thus write the "signal file" so next time, it won't be first time ... ;) Confusing sentence ...
638  file = SDL_RWFromFile(fn, "wb");
639  if (!file) {
640  ERROR_WINDOW("Xemu cannot write the preferences directory!\nFile: %s\nError: %s", fn, SDL_GetError());
641  return 0; // pretend not first time user, since there is some serious problem already ... leave our static variable as is, also!!
642  }
643  static const char message[] = "DO NOT DELETE. Xemu uses this file to tell, if Xemu has been already run on this system at all.";
644  SDL_RWwrite(file, message, strlen(message), 1); // Nah, we simply do not check if write worked ...
645  SDL_RWclose(file);
646  is_first_time_user = 1;
647  return is_first_time_user; // first time user detected!!
648 }
649 
650 
651 void xemu_pre_init ( const char *app_organization, const char *app_name, const char *slogan )
652 {
653 #ifdef XEMU_ARCH_UNIX
654 #ifndef XEMU_DO_NOT_DISALLOW_ROOT
655  // Some check to disallow dangerous things (running Xemu as user/group root)
656  if (getuid() == 0 || geteuid() == 0)
657  FATAL("Xemu must not be run as user root");
658  if (getgid() == 0 || getegid() == 0)
659  FATAL("Xemu must not be run as group root");
660 #endif
661  // ignore SIGHUP, eg closing the terminal Xemu was started from ...
662  signal(SIGHUP, SIG_IGN); // ignore SIGHUP, eg closing the terminal Xemu was started from ...
663 #endif
664 #if 0
665  // This core is currently commented out, since I guess it would casue problems for many users
666  // Unfortunately Windows is not secure by nature (or better say, by user habits, that most
667  // user uses their system as administrator all the time ... when it would be desired to use
668  // administrator user only, if adminstration task is needed much like the habit in UNIX-like
669  // systems)
670 #if defined(XEMU_ARCH_WIN) && !defined(XEMU_DO_NOT_DISALLOW_ROOT)
671  BOOL fRet = FALSE;
672  HANDLE hToken = NULL;
673  if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
674  TOKEN_ELEVATION Elevation;
675  DWORD cbSize = sizeof(TOKEN_ELEVATION);
676  if (GetTokenInformation(hToken, TokenElevation, &Elevation, sizeof(Elevation), &cbSize)) {
677  fRet = Elevation.TokenIsElevated;
678  }
679  }
680  if (hToken) {
681  CloseHandle(hToken);
682  }
683  if (fRet) {
684  WARNING_WINDOW("Do not run Xemu with administrator rights!\nXemu is not OS security audited and can access network, filesystem, etc.\nIt can be easily used to exploit your system.\nAs always, never run anything as adminstrator, unless you really need to\nadministrate your OS, as the name suggest!");
685  }
686 #endif
687 #endif
688 #ifdef XEMU_ARCH_HTML
689  if (chatty_xemu)
690  xemu_dump_version(stdout, slogan);
691  MKDIR(emscripten_sdl_base_dir);
692  sdl_base_dir = (void*)emscripten_sdl_base_dir;
693  sdl_pref_dir = (void*)emscripten_sdl_base_dir;
694  sdl_inst_dir = (void*)emscripten_sdl_base_dir;
695  // In case of emscripten we do all the SDL init here!!!
696  // Please note: with emscripten, you can't use SDL_INIT_TIMER and SDL_INIT_HAPTIC subsystems it seems, it will
697  // give error on SDL_Init (I can understand with timer, as it would require multithreading)
698  if (SDL_Init(SDL_INIT_EVERYTHING & ~(SDL_INIT_TIMER | SDL_INIT_HAPTIC)))
699  FATAL("Cannot initialize SDL: %s", SDL_GetError());
700  atexit(shutdown_emulator);
701 #else
702  char *p;
703  sysconsole_open();
704  if (chatty_xemu)
705  xemu_dump_version(stdout, slogan);
706  // Initialize SDL with no subsystems
707  // This is needed, because SDL_GetPrefPath and co. are not safe on every platforms without it.
708  // But we DO want to use *before* the real SDL_Init, as the configuration file may describe
709  // parameters on the init itself, but to read the config file we must know where it is.
710  // You see, chicken & egg problem. We try to work this around with the solution to do the
711  // minimal init for the path info functions, then we shuts SDL down, and the "real" SDL_Init
712  // with subsystems etc will happen later!
713  if (SDL_Init(0))
714  FATAL("Cannot pre-initialize SDL without any subsystem: %s", SDL_GetError());
715  atexit(shutdown_emulator);
716  p = SDL_GetBasePath();
717  if (p) {
719  SDL_free(p);
720  } else
721  FATAL("Cannot query SDL base directory: %s", SDL_GetError());
722  p = GetHackedPrefDir(sdl_base_dir, app_name);
723  if (!p)
724  p = SDL_GetPrefPath(app_organization, app_name);
725  if (p) {
726  sdl_pref_dir = xemu_strdup(p); // we are too careful: I can't be sure the used SQL_Quit messes up the allocated buffer, so we "clone" it
727  sdl_inst_dir = xemu_malloc(strlen(p) + strlen(INSTALL_DIRECTORY_ENTRY_NAME) + strlen(DIRSEP_STR) + 1);
729  SDL_free(p);
730  } else
731  FATAL("Cannot query SDL preference directory: %s", SDL_GetError());
732 #endif
733  xemu_app_org = xemu_strdup(app_organization);
734  xemu_app_name = xemu_strdup(app_name);
735 #ifdef XEMU_CONFIGDB_SUPPORT
736  // If configDB support is compiled in, we can define some common options, should apply for ALL emulators.
737  // This way, it's not needed to define those in all of the emulator targets ...
738  // TODO: it's an unfinished project here ...
739 #endif
740 }
741 
742 
743 
744 int xemu_init_sdl ( void )
745 {
746 #ifndef XEMU_ARCH_HTML
747  const Uint32 XEMU_SDL_INIT_EVERYTHING =
748 #if defined(XEMU_ARCH_WIN) && defined(SDL_INIT_SENSOR)
749  // FIXME: SDL or Windows has the bug that SDL_INIT_SENSOR when used, there is some "sensor manager" problem, so we left it out
750  // SDL_INIT_SENSOR was introduced somewhere in 2.0.9, however since it's a macro, it's safer not to test actual SDL version number
751  SDL_INIT_EVERYTHING & ~(SDL_INIT_SENSOR | SDL_INIT_HAPTIC);
752 #warning "NOTE: SDL_INIT_SENSOR and SDL_INIT_HAPTIC is not used on Windows because seems to cause problems :("
753 #else
754  SDL_INIT_EVERYTHING;
755 #endif
756  if (!SDL_WasInit(XEMU_SDL_INIT_EVERYTHING)) {
757  DEBUGPRINT("SDL: no SDL subsystem initialization has been done yet, do it!" NL);
758  SDL_Quit(); // Please read the long comment at the pre-init func above to understand this SDL_Quit() here and then the SDL_Init() right below ...
759  DEBUG("SDL: before SDL init" NL);
760  if (SDL_Init(XEMU_SDL_INIT_EVERYTHING)) {
761  ERROR_WINDOW("Cannot initialize SDL: %s", SDL_GetError());
762  return 1;
763  }
764  DEBUG("SDL: after SDL init" NL);
765  if (!SDL_WasInit(XEMU_SDL_INIT_EVERYTHING))
766  FATAL("SDL_WasInit()=0 after init??");
767  } else
768  DEBUGPRINT("SDL: no SDL subsystem initialization has been done already." NL);
769 #endif
770  SDL_VERSION(&sdlver_compiled);
771  SDL_GetVersion(&sdlver_linked);
772  const char *sdl_video_driver = SDL_GetCurrentVideoDriver();
773  if (!sdl_video_driver)
774  FATAL("SDL_GetCurrentVideoDriver() == NULL");
775  sdl_on_x11 = !strcasecmp(sdl_video_driver, "x11");
776  sdl_on_wayland = !strcasecmp(sdl_video_driver, "wayland");
777  if (chatty_xemu)
778  printf( "SDL version: (%s) compiled with %d.%d.%d, used with %d.%d.%d on platform %s" NL
779  "SDL system info: %d bits %s, %d cores, l1_line=%d, RAM=%dMbytes, max_alignment=%d%s, CPU features: "
780  "3DNow=%d AVX=%d AVX2=%d AltiVec=%d MMX=%d RDTSC=%d SSE=%d SSE2=%d SSE3=%d SSE41=%d SSE42=%d" NL
781  "SDL drivers: video = %s, audio = %s" NL,
782  SDL_GetRevision(),
783  sdlver_compiled.major, sdlver_compiled.minor, sdlver_compiled.patch,
784  sdlver_linked.major, sdlver_linked.minor, sdlver_linked.patch,
785  SDL_GetPlatform(),
786  ARCH_BITS, ENDIAN_NAME, SDL_GetCPUCount(), SDL_GetCPUCacheLineSize(), SDL_GetSystemRAM(), __BIGGEST_ALIGNMENT__,
788  " (set-by-Xemu)",
789 #else
790  "",
791 #endif
792  SDL_Has3DNow(),SDL_HasAVX(),SDL_HasAVX2(),SDL_HasAltiVec(),SDL_HasMMX(),SDL_HasRDTSC(),SDL_HasSSE(),SDL_HasSSE2(),SDL_HasSSE3(),SDL_HasSSE41(),SDL_HasSSE42(),
793  sdl_video_driver, SDL_GetCurrentAudioDriver()
794  );
795 #if defined(XEMU_ARCH_WIN)
796 # define SDL_VER_MISMATCH_WARN_STR "Xemu was not compiled with the linked DLL for SDL.\nPlease upgrade your DLL too, not just Xemu binary."
797 #elif defined(XEMU_ARCH_OSX)
798 # define SDL_VER_MISMATCH_WARN_STR "Xemu was not compuled with the linked dylib for SDL.\nPlease upgrade your dylib too, not just Xemu binary."
799 #endif
800 #ifdef SDL_VER_MISMATCH_WARN_STR
801  if (sdlver_compiled.major != sdlver_linked.major || sdlver_compiled.minor != sdlver_linked.minor || sdlver_compiled.patch != sdlver_linked.patch)
802  WARNING_WINDOW(SDL_VER_MISMATCH_WARN_STR);
803 #endif
804  return 0;
805 }
806 
807 
809 {
810  // XXX TODO check if fullscreen state is active?
811  // though it must be checked if it's needed at all (ie: SDL is OK with resizing window in fullscreen mode without any effect BEFORE switcing back from fullscreen)
812  static Uint32 last_resize = 0;
813  Uint32 now = 0;
814  if (!forced && sdl_viewport_changed && follow_win_size) {
815  now = SDL_GetTicks();
816  if (now - last_resize >= 1000) {
817  sdl_viewport_changed = 0;
818  forced = 1;
819  }
820  }
821  if (!forced)
822  return;
823  int w, h;
824  SDL_GetWindowSize(sdl_win, &w, &h);
825  float rat = (float)w / (float)sdl_viewport.w;
826  const float rat2 = (float)h / (float)sdl_viewport.h;
827  if (rat2 > rat)
828  rat = rat2;
829  rat = roundf(rat); // XXX TODO: depends on math.h mingw warning!
830  // XXX TODO: check if window is not larger than the screen itself
831  if (rat < 1)
832  rat = 1;
833  const int w2 = rat * sdl_viewport.w;
834  const int h2 = rat * sdl_viewport.h;
835  if (w != w2 || h != h2) {
836  last_resize = now;
837  SDL_SetWindowSize(sdl_win, w2, h2);
838  DEBUGPRINT("SDL: auto-resizing window to %d x %d (zoom level approximated: %d)" NL, w2, h2, (int)rat);
839  } else
840  DEBUGPRINT("SDL: no auto-resizing was needed (same size)" NL);
841 }
842 
843 
844 void xemu_set_viewport ( unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, unsigned int flags )
845 {
846  if (XEMU_UNLIKELY(x1 == 0 && y1 == 0 && x2 == 0 && y2 == 0)) {
847  sdl_viewport_ptr = NULL;
848  sdl_viewport.x = 0;
849  sdl_viewport.y = 0;
850  sdl_viewport.w = sdl_texture_x_size;
851  sdl_viewport.h = sdl_texture_y_size;
852  } else {
853  if (XEMU_UNLIKELY(x1 > x2 || y1 > y2 || x1 >= sdl_texture_x_size || y1 >= sdl_texture_y_size || x2 >= sdl_texture_x_size || y2 >= sdl_texture_y_size)) {
854  FATAL("Invalid xemu_set_viewport(%d,%d,%d,%d) for texture (%d x %d)", x1, y1, x2, y2, sdl_texture_x_size, sdl_texture_y_size);
855  } else {
856  sdl_viewport_ptr = &sdl_viewport;
857  sdl_viewport.x = x1;
858  sdl_viewport.y = y1;
859  sdl_viewport.w = x2 - x1 + 1;
860  sdl_viewport.h = y2 - y1 + 1;
861  }
862  }
863  sdl_viewport_changed = 1;
864  follow_win_size = 0;
866  SDL_RenderSetLogicalSize(sdl_ren, sdl_viewport.w, sdl_viewport.h);
867  // XXX this should be not handled this way
868  sdl_default_win_x_size = sdl_viewport.w;
869  sdl_default_win_y_size = sdl_viewport.h;
870  //if ((flags & XEMU_VIEWPORT_WIN_SIZE_FOLLOW_LOGICAL))
871  //XXX remove this XEMU_VIEWPORT_WIN_SIZE_FOLLOW_LOGICAL then!
872  follow_win_size = 1;
873  }
874 }
875 
876 
877 void xemu_get_viewport ( unsigned int *x1, unsigned int *y1, unsigned int *x2, unsigned int *y2 )
878 {
879  if (x1)
880  *x1 = sdl_viewport.x;
881  if (y1)
882  *y1 = sdl_viewport.y;
883  if (x2)
884  *x2 = sdl_viewport.x + sdl_viewport.w - 1;
885  if (y2)
886  *y2 = sdl_viewport.y + sdl_viewport.h - 1;
887 }
888 
889 
890 static int xemu_create_main_texture ( void )
891 {
892  DEBUGPRINT("SDL: creating main texture %d x %d" NL, sdl_texture_x_size, sdl_texture_y_size);
893  SDL_Texture *new_tex = SDL_CreateTexture(sdl_ren, sdl_pixel_format_id, SDL_TEXTUREACCESS_STREAMING, sdl_texture_x_size, sdl_texture_y_size);
894  if (!new_tex) {
895  DEBUGPRINT("SDL: cannot create main texture: %s" NL, SDL_GetError());
896  return 1;
897  }
898  if (sdl_tex) {
899  DEBUGPRINT("SDL: destroying old main texture" NL);
900  SDL_DestroyTexture(sdl_tex);
901  }
902  sdl_tex = new_tex;
903  return 0;
904 }
905 
906 
907 /* Return value: 0 = ok, otherwise: ERROR, caller must exit, and can't use any other functionality, otherwise crash would happen.*/
909  const char *window_title, // title of our window
910  int is_resizable, // allow window resize? [0 = no]
911  int texture_x_size, int texture_y_size, // raw size of texture (in pixels)
912  int logical_x_size, int logical_y_size, // "logical" size in pixels, ie to correct aspect ratio, etc, can be the as texture of course, if it's OK ...
913  int win_x_size, int win_y_size, // default window size, in pixels [note: if logical/texture size combo does not match in ratio with this, black stripes you will see ...]
914  Uint32 pixel_format, // SDL pixel format we want to use (an SDL constant, like SDL_PIXELFORMAT_ARGB8888) Note: it can gave serve impact on performance, ARGB8888 recommended
915  int n_colours, // number of colours emulator wants to use
916  const Uint8 *colours, // RGB components of each colours, we need 3 * n_colours bytes to be passed!
917  Uint32 *store_palette, // this will be filled with generated palette, n_colours Uint32 values will be placed
918  int render_scale_quality, // render scale quality, must be 0, 1 or 2 _ONLY_
919  int locked_texture_update, // use locked texture method [non zero], or malloc'ed stuff [zero]. NOTE: locked access doesn't allow to _READ_ pixels and you must fill ALL pixels!
920  void (*shutdown_callback)(void) // callback function called on exit (can be nULL to not have any emulator specific stuff)
921 ) {
922  srand((unsigned int)time(NULL));
923 # include "build/xemu-48x48.xpm"
924  SDL_RendererInfo ren_info;
925  int a;
926  if (!debug_fp)
927  xemu_init_debug(getenv("XEMU_DEBUG_FILE"));
928  if (!debug_fp && chatty_xemu)
929  printf("Logging into file: not enabled." NL);
930  if (!sdl_pref_dir)
931  FATAL("xemu_pre_init() hasn't been called yet!");
932  if (xemu_byte_order_test()) {
933  ERROR_WINDOW("Byte order test failed!!");
934  return 1;
935  }
936 #ifdef SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR
937  // Disallow disabling compositing (of KDE, for example)
938  // Maybe needed before SDL_Init(), so it's here before calling xemu_init_sdl()
939  SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0");
940 #endif
941  if (xemu_init_sdl()) // it is possible that is has been already called, but it's not a problem
942  return 1;
943  shutdown_user_function = shutdown_callback;
944  DEBUGPRINT("TIMING: sleep = %s, query = %s" NL, __SLEEP_METHOD_DESC, __TIMING_METHOD_DESC);
945  DEBUGPRINT("SDL preferences directory: %s" NL, sdl_pref_dir);
946  DEBUG("SDL install directory: %s" NL, sdl_inst_dir);
947  DEBUG("SDL base directory: %s" NL, sdl_base_dir);
948 #ifndef XEMU_ARCH_HTML
949  if (MKDIR(sdl_inst_dir) && errno != EEXIST)
950  ERROR_WINDOW("Warning: cannot create directory %s: %s", sdl_inst_dir, strerror(errno));
951 #endif
952 #ifndef XEMU_ARCH_WIN
953  do {
954  char *p = getenv("HOME");
955  if (p && strlen(sdl_pref_dir) > strlen(p) + 1 && !strncmp(p, sdl_pref_dir, strlen(p)) && sdl_pref_dir[strlen(p)] == DIRSEP_CHR) {
956  char s[PATH_MAX];
957  sprintf(s, "%s" DIRSEP_STR ".%s", p, xemu_app_org);
958  p = sdl_pref_dir + strlen(p) + 1;
959  if (symlink(p, s)) {
960  if (errno != EEXIST)
961  WARNING_WINDOW("Warning: cannot create symlink %s to %s: %s", p, s, strerror(errno));
962  } else
963  INFO_WINDOW("Old-style link for pref.directory has been created as %s\npointing to: %s", s, p);
964  }
965  } while (0);
966 #endif
967  /* SDL hints */
968  // Moved here (instead of near the end of this func) since some of hints needed to be given
969  // rearly (like SDL_HINT_RENDER_SCALE_QUALITY before creating texture?)
970 #if defined(SDL_HINT_THREAD_STACK_SIZE) && defined(XEMU_THREAD_STACK_SIZE)
971  // string as positive number: use stack size, zero: use thread backend default (glibc usually gives 8Mb, other maybe small!)
972  // Leave that to user, if XEMU_THREAD_STACK_SIZE is defined, it will be set.
973  SDL_SetHint(SDL_HINT_THREAD_STACK_SIZE, STRINGIFY(XEMU_THREAD_STACK_SIZE));
974 #endif
975 #ifdef SDL_HINT_RENDER_SCALE_QUALITY
976  const char render_scale_quality_s[2] = { '0' + (render_scale_quality & 3), '\0' };
977  SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, render_scale_quality_s, SDL_HINT_OVERRIDE); // render scale quality 0, 1, 2
978 #endif
979 #ifdef SDL_HINT_VIDEO_X11_NET_WM_PING
980  SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_PING, "0"); // disable WM ping, SDL dialog boxes makes WMs things emu is dead (?)
981 #endif
982 #ifdef SDL_HINT_RENDER_VSYNC
983  SDL_SetHint(SDL_HINT_RENDER_VSYNC, "0"); // disable vsync aligned screen rendering
984 #endif
985 #ifdef SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4
986  SDL_SetHint(SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4, "1"); // 1 = disable ALT-F4 close on Windows
987 #endif
988 #ifdef SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS
989  SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0"); // 1 = do minimize the SDL_Window if it loses key focus when in fullscreen mode
990 #endif
991 #ifdef SDL_HINT_VIDEO_ALLOW_SCREENSAVER
992  SDL_SetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER, "1"); // 1 = enable screen saver
993 #endif
994  /* end of SDL hints section */
995  sdl_window_title = xemu_strdup(window_title);
996  sdl_win = SDL_CreateWindow(
997  window_title,
998  SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
999  win_x_size, win_y_size,
1000  SDL_WINDOW_SHOWN | (is_resizable ? SDL_WINDOW_RESIZABLE : 0)
1001  );
1002  sdl_default_win_x_size = win_x_size;
1003  sdl_default_win_y_size = win_y_size;
1004  DEBUGPRINT("SDL window native pixel format: %s" NL, SDL_GetPixelFormatName(SDL_GetWindowPixelFormat(sdl_win)));
1005  if (!sdl_win) {
1006  ERROR_WINDOW("Cannot create SDL window: %s", SDL_GetError());
1007  return 1;
1008  }
1009  window_title_buffer = xemu_malloc(strlen(window_title) + 128);
1010  strcpy(window_title_buffer, window_title);
1011  window_title_buffer_end = window_title_buffer + strlen(window_title);
1012  //SDL_SetWindowMinimumSize(sdl_win, SCREEN_WIDTH, SCREEN_HEIGHT * 2);
1013  a = SDL_GetNumRenderDrivers();
1014  while (--a >= 0) {
1015  if (!SDL_GetRenderDriverInfo(a, &ren_info)) {
1016  DEBUGPRINT("SDL renderer driver #%d: \"%s\"" NL, a, ren_info.name);
1017  } else
1018  DEBUGPRINT("SDL renderer driver #%d: FAILURE TO QUERY (%s)" NL, a, SDL_GetError());
1019  }
1020  sdl_ren = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_ACCELERATED);
1021  if (!sdl_ren) {
1022  ERROR_WINDOW("Cannot create accelerated SDL renderer: %s", SDL_GetError());
1023  sdl_ren = SDL_CreateRenderer(sdl_win, -1, 0);
1024  if (!sdl_ren) {
1025  ERROR_WINDOW("... and not even non-accelerated driver could be created, giving up: %s", SDL_GetError());
1026  return 1;
1027  } else {
1028  INFO_WINDOW("Created non-accelerated driver. NOTE: it will severly affect the performance!");
1029  }
1030  }
1031  SDL_SetRenderDrawColor(sdl_ren, 0, 0, 0, SDL_ALPHA_OPAQUE);
1032  if (!SDL_GetRendererInfo(sdl_ren, &ren_info)) {
1033  DEBUGPRINT("SDL renderer used: \"%s\" max_tex=%dx%d tex_formats=%d ", ren_info.name, ren_info.max_texture_width, ren_info.max_texture_height, ren_info.num_texture_formats);
1034  for (a = 0; a < ren_info.num_texture_formats; a++)
1035  DEBUGPRINT("%c%s", a ? ' ' : '(', SDL_GetPixelFormatName(ren_info.texture_formats[a]));
1036  DEBUGPRINT(")" NL);
1037  }
1038  SDL_RenderSetLogicalSize(sdl_ren, logical_x_size, logical_y_size); // this helps SDL to know the "logical ratio" of screen, even in full screen mode when scaling is needed!
1039  sdl_texture_x_size = texture_x_size;
1040  sdl_texture_y_size = texture_y_size;
1041  sdl_pixel_format_id = pixel_format;
1042  xemu_set_viewport(0, 0, 0, 0, 0);
1043  if (xemu_create_main_texture()) {
1044  ERROR_WINDOW("Cannot create SDL texture: %s", SDL_GetError());
1045  return 1;
1046  }
1047  texture_x_size_in_bytes = texture_x_size * 4;
1048  sdl_winid = SDL_GetWindowID(sdl_win);
1049  /* Intitialize palette from given RGB components */
1050  sdl_pix_fmt = SDL_AllocFormat(pixel_format);
1051  black_colour = SDL_MapRGBA(sdl_pix_fmt, 0, 0, 0, 0xFF); // used to initialize pixel buffer
1052  while (n_colours--)
1053  store_palette[n_colours] = SDL_MapRGBA(sdl_pix_fmt, colours[n_colours * 3], colours[n_colours * 3 + 1], colours[n_colours * 3 + 2], 0xFF);
1054  /* texture access / buffer */
1055  if (!locked_texture_update)
1057  // play a single frame game, to set a consistent colour (all black ...) for the emulator. Also, it reveals possible errors with rendering
1058  xemu_render_dummy_frame(black_colour, texture_x_size, texture_y_size);
1059  if (chatty_xemu)
1060  printf(NL);
1061  xemu_set_icon_from_xpm(favicon_xpm);
1062  return 0;
1063 }
1064 
1065 
1066 int xemu_set_icon_from_xpm ( char *xpm[] )
1067 {
1068  int width, height, colours, chperpix;
1069  if (sscanf(xpm[0], "%d %d %d %d", &width, &height, &colours, &chperpix) != 4) {
1070  ERROR_WINDOW("Icon internal error: bad format");
1071  return -1;
1072  }
1073  if (chperpix != 1) {
1074  ERROR_WINDOW("Icon internal error: not one-char per pixel format");
1075  return -1;
1076  }
1077  Uint8 *data = xemu_malloc(height * width);
1078  SDL_Surface *surf = SDL_CreateRGBSurfaceFrom(data, width, height, 8, width, 0, 0, 0, 0);
1079  if (!surf) {
1080  ERROR_WINDOW("Icon internal error: cannot allocate surface: %s", SDL_GetError());
1081  free(data);
1082  return -1;
1083  }
1084  int i = 1;
1085  while (colours) {
1086  SDL_Color *palentry = &(surf->format->palette->colors[(Uint8)xpm[i][0]]);
1087  Uint8 *p = (Uint8*)strchr(xpm[i] + 1, '#');
1088  if (p) {
1089  int vals[6]; // ugly, but again, Windows ... it does not support %02hhx for scanf(). Really what windows is for? it does not know any standards at all :-O
1090  for (int a = 0; a < 6; a++) {
1091  int hdig = p[a + 1];
1092  if (hdig >= '0' && hdig <= '9')
1093  vals[a] = hdig - '0';
1094  else if (hdig >= 'A' && hdig <= 'F')
1095  vals[a] = hdig - 'A' + 10;
1096  else
1097  vals[a] = hdig - 'a' + 10;
1098  }
1099  palentry->r = (vals[0] << 4) + vals[1];
1100  palentry->g = (vals[2] << 4) + vals[3];
1101  palentry->b = (vals[4] << 4) + vals[5];
1102  palentry->a = 0xFF;
1103  } else
1104  palentry->a = 0x00;
1105  colours--;
1106  i++;
1107  }
1108  Uint8 *d = data;
1109  while (height) {
1110  memcpy(d, xpm[i++], width);
1111  d += width;
1112  height--;
1113  }
1114  SDL_SetWindowIcon(sdl_win, surf);
1115  SDL_FreeSurface(surf);
1116  free(data);
1117  return 0;
1118 }
1119 
1120 
1121 // this is just for the time keeping stuff, to avoid very insane values (ie, years since the last update for the first call ...)
1123 {
1124  (void)get_elapsed_time(0, &et_old, &unix_time_tv);
1125  td_balancer = 0;
1126  td_em_ALL = 0;
1127  td_pc_ALL = 0;
1129 }
1130 
1131 
1132 void xemu_render_dummy_frame ( Uint32 colour, int texture_x_size, int texture_y_size )
1133 {
1134  int tail;
1136  for (int y = 0; y < texture_y_size; y++) {
1137  for (int x = 0; x < texture_x_size; x++)
1138  *(pp++) = colour;
1139  pp += tail;
1140  }
1143 }
1144 
1145 
1146 /* You *MUST* call this _ONCE_ before any access of pixels of the rendering target
1147  after render is done. Then pixels can be written but especially in locked_texture
1148  mode, you CAN'T read the previous frame pixels back! Also then you need to update
1149  *ALL* pixels of the texture before calling xemu_update_screen() func at the end!
1150  tail should have added at the end of each lines of the texture, in theory it should
1151  be zero (when it's not needed ...) but you CANNOT be sure, if it's really true!
1152  tail is meant in 4 bytes (ie Uint32 pointer)! */
1154 {
1157  xemu_create_main_texture();
1158  }
1159  if (sdl_pixel_buffer) {
1160  *texture_tail = 0; // using non-locked texture access, "tail" is always zero
1162  return sdl_pixel_buffer; // using non-locked texture access, return with the malloc'ed buffer
1163  } else {
1164  int pitch;
1165  void *pixels;
1166  if (SDL_LockTexture(sdl_tex, NULL, &pixels, &pitch))
1167  FATAL("Cannot lock texture: %s", SDL_GetError());
1168  if ((pitch & 3))
1169  FATAL("Not dword aligned texture pitch value got!");
1170  pitch -= texture_x_size_in_bytes;
1171  if (pitch < 0)
1172  FATAL("Negative pitch value got for the texture size!");
1173  *texture_tail = (pitch >> 2);
1175  return pixels;
1176  }
1177 }
1178 
1179 
1180 /* Call this, to "show" the result given by filled pixel buffer whose pointer is
1181  got by calling emu_start_pixel_buffer_access(). Please read the notes at
1182  emu_start_pixel_buffer_access() carefully, especially, if you use the locked
1183  texture method! */
1184 void xemu_update_screen ( void )
1185 {
1186  if (sdl_pixel_buffer) {
1187  SDL_UpdateTexture(sdl_tex, NULL, sdl_pixel_buffer, texture_x_size_in_bytes);
1188  } else {
1189  SDL_UnlockTexture(sdl_tex);
1190  xemu_frame_pixel_access_p = NULL; // not valid anymore!
1191  }
1192  //if (seconds_timer_trigger)
1193  SDL_RenderClear(sdl_ren); // Note: it's not needed at any price, however eg with full screen or ratio mismatches, unused screen space will be corrupted without this!
1194  SDL_RenderCopy(sdl_ren, sdl_tex, sdl_viewport_ptr, NULL);
1195 #ifdef XEMU_OSD_SUPPORT
1196  _osd_render();
1197 #endif
1198  SDL_RenderPresent(sdl_ren);
1199 }
1200 
1201 
1202 int ARE_YOU_SURE ( const char *s, int flags )
1203 {
1204  if ((flags & ARE_YOU_SURE_OVERRIDE))
1205  return 1;
1206  static const char *selector_default_yes = "!Yes|?No";
1207  static const char *selector_default_no = "Yes|*No";
1208  static const char *selector_generic = "Yes|No";
1209  const char *selector;
1211  selector = selector_default_yes;
1212  else if ((flags & ARE_YOU_SURE_DEFAULT_NO))
1213  selector = selector_default_no;
1214  else
1215  selector = selector_generic;
1216  return (QUESTION_WINDOW(selector, (s != NULL && *s != '\0') ? s : "Are you sure?") == 0);
1217 }
1218 
1219 
1220 int _sdl_emu_secured_modal_box_ ( const char *items_in, const char *msg )
1221 {
1222  char items_buf[512], *items = items_buf;
1223  int buttonid;
1224  SDL_MessageBoxButtonData buttons[16];
1225  SDL_MessageBoxData messageboxdata = {
1226  SDL_MESSAGEBOX_WARNING // .flags
1227 #if SDL_VERSION_ATLEAST(2, 0, 12)
1228  | SDL_MESSAGEBOX_BUTTONS_LEFT_TO_RIGHT
1229 #endif
1230  ,
1231  sdl_win, // .window
1232  default_window_title, // .title
1233  msg, // .message
1234  0, // number of buttons, will be updated!
1235  buttons,
1236  NULL // &colorScheme
1237  };
1238  if (!SDL_WasInit(0))
1239  FATAL("Calling _sdl_emu_secured_modal_box_() without non-zero SDL_Init() before!");
1240  strcpy(items_buf, items_in);
1241  for (;;) {
1242  char *p = strchr(items, '|');
1243  switch (*items) {
1244  case '!':
1245  buttons[messageboxdata.numbuttons].flags = SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
1246  items++;
1247  break;
1248  case '?':
1249  buttons[messageboxdata.numbuttons].flags = SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
1250  items++;
1251  break;
1252  case '*':
1253  buttons[messageboxdata.numbuttons].flags = SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT | SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
1254  items++;
1255  break;
1256  default:
1257  buttons[messageboxdata.numbuttons].flags = 0;
1258  break;
1259  }
1260 #ifdef XEMU_ARCH_HTML
1261  if ((buttons[messageboxdata.numbuttons].flags & SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT)) {
1262  DEBUGPRINT("Emscripten: faking chooser box answer %d for \"%s\"" NL, messageboxdata.numbuttons, msg);
1263  return messageboxdata.numbuttons;
1264  }
1265 #endif
1266  buttons[messageboxdata.numbuttons].text = items;
1267  buttons[messageboxdata.numbuttons].buttonid = messageboxdata.numbuttons;
1268  messageboxdata.numbuttons++;
1269  if (!p)
1270  break;
1271  *p = 0;
1272  items = p + 1;
1273  }
1274  save_mouse_grab();
1275  SDL_ShowMessageBox_custom(&messageboxdata, &buttonid);
1276  xemu_drop_events();
1277  clear_emu_events();
1278  SDL_RaiseWindow(sdl_win);
1281  return buttonid;
1282 }
1283 
1284 
1285 
1286 /* Note, Windows has some braindead idea about console, ie even the standard stdout/stderr/stdin does not work with
1287  a GUI application. We have to dance a bit, to fool Windows to do what is SHOULD according the standard to be used
1288  by every other operating systems. Ehhh, Microsoft, please, get some real designers and programmers :-)
1289  Though one thing is clear: I am *NOT* a Windows developer, I can't even understand what this does exactly to be
1290  honest, just try&error, and some advices from other people. For example, in Win64 there are some warnings about
1291  this function. I can't do anything, since Windows API is a nightmare, using non-C-standard types for system
1292  calls, I have no idea ... */
1293 
1294 void sysconsole_open ( void )
1295 {
1296 #ifdef XEMU_ARCH_WIN
1297  int hConHandle;
1298  HANDLE lStdHandle;
1299  CONSOLE_SCREEN_BUFFER_INFO coninfo;
1300  FILE *fp;
1301  if (sysconsole_is_open)
1302  return;
1303  sysconsole_is_open = 0;
1304  FreeConsole();
1305  if (!AllocConsole()) {
1306  ERROR_WINDOW("Cannot allocate windows console!");
1307  return;
1308  }
1309  // disallow closing console (this would kill the app, too!!!!)
1310 #if 1
1311  HWND hwnd = GetConsoleWindow();
1312  if (hwnd != NULL) {
1313  HMENU hmenu = GetSystemMenu(hwnd, FALSE);
1314  if (hmenu != NULL)
1315  DeleteMenu(hmenu, SC_CLOSE, MF_BYCOMMAND);
1316  else
1317  DEBUGPRINT("WINDOWS: GetSystemMenu() failed to give the menu for our console window." NL);
1318  } else
1319  DEBUGPRINT("WINDOWS: GetConsoleWindow() failed to give a handle." NL);
1320 #endif
1321  // end of close madness
1322  SetConsoleOutputCP(65001); // CP_UTF8, just to be sure to use the constant as not all mingw versions seems to define it
1323  SetConsoleTitle("Xemu Console");
1324  // set the screen buffer to be big enough to let us scroll text
1325  GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
1326  coninfo.dwSize.Y = 1024;
1327  //coninfo.dwSize.X = 100;
1328  SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);
1329  // redirect unbuffered STDOUT to the console
1330  lStdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
1331  hConHandle = _open_osfhandle((INT_PTR)lStdHandle, _O_TEXT);
1332  fp = _fdopen( hConHandle, "w" );
1333  *stdout = *fp;
1334  setvbuf( stdout, NULL, _IONBF, 0 );
1335  // redirect unbuffered STDIN to the console
1336  lStdHandle = GetStdHandle(STD_INPUT_HANDLE);
1337  hConHandle = _open_osfhandle((INT_PTR)lStdHandle, _O_TEXT);
1338  fp = _fdopen( hConHandle, "r" );
1339  *stdin = *fp;
1340  setvbuf( stdin, NULL, _IONBF, 0 );
1341  // redirect unbuffered STDERR to the console
1342  lStdHandle = GetStdHandle(STD_ERROR_HANDLE);
1343  hConHandle = _open_osfhandle((INT_PTR)lStdHandle, _O_TEXT);
1344  fp = _fdopen( hConHandle, "w" );
1345  *stderr = *fp;
1346  setvbuf( stderr, NULL, _IONBF, 0 );
1347  // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog point to console as well
1348  // sync_with_stdio();
1349  // Set Con Attributes
1350  //SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), FOREGROUND_RED | FOREGROUND_INTENSITY);
1351  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_INTENSITY);
1352  SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT);
1353  SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT);
1354  DEBUGPRINT("WINDOWS: console is open" NL);
1355  if (!atexit_callback_for_console_registered) {
1356  atexit(atexit_callback_for_console);
1357  atexit_callback_for_console_registered = 1;
1358  }
1359 #endif
1360  sysconsole_is_open = 1;
1361 }
1362 
1363 
1364 #ifdef XEMU_ARCH_WIN
1365 static CHAR sysconsole_getch( void )
1366 {
1367  HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
1368  if (!h) // console cannot be accessed or WTF?
1369  return 0;
1370  DWORD cc, mode_saved;
1371  GetConsoleMode(h, &mode_saved);
1372  SetConsoleMode(h, mode_saved & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT));
1373  TCHAR c = 0;
1374  ReadConsole(h, &c, 1, &cc, NULL);
1375  SetConsoleMode(h, mode_saved);
1376  return c;
1377 }
1378 #endif
1379 
1380 
1381 #ifdef XEMU_ARCH_WIN
1382 static int file_handle_redirect ( const char *target, const char *symname, const char *mode, FILE *handle )
1383 {
1384  if (!freopen(target, mode, handle)) {
1385  ERROR_WINDOW("Failed to redirect [%s] to \"%s\"\n%s", symname, target, strerror(errno));
1386  return 1;
1387  }
1388  return 0;
1389 }
1390 #endif
1391 
1392 
1393 void sysconsole_close ( const char *waitmsg )
1394 {
1395  if (!sysconsole_is_open)
1396  return;
1397 #ifdef XEMU_ARCH_WIN
1398  if (waitmsg) {
1399  // FIXME: for some reason on Windows (no idea why), window cannot be open from an atexit callback
1400  // So instead of a GUI element here with a dialog box, we must rely on the console to press a key to continue ...
1401  printf("\n\n*** %s\nPress SPACE to continue.", waitmsg);
1402  while (sysconsole_getch() != 32)
1403  SDL_Delay(1);
1404  }
1405  if (!FreeConsole()) {
1406  if (!waitmsg)
1407  ERROR_WINDOW("Cannot release windows console!");
1408  } else {
1409  sysconsole_is_open = 0;
1410 #if 1
1411  // redirect std file handled to "NUL" to avoid strange issues after closing the console, like corrupting
1412  // other files (for unknown reasons) by further I/O after FreeConsole() ...
1413  int ret = file_handle_redirect(NULL_DEVICE, "stderr", "w", stderr);
1414  ret |= file_handle_redirect(NULL_DEVICE, "stdout", "w", stdout);
1415  ret |= file_handle_redirect(NULL_DEVICE, "stdin", "r", stdin );
1416  DEBUG("WINDOWS: console has been closed (file_handle_redirect: %s)" NL, ret ? "ERROR" : "OK");
1417 #else
1418  DEBUGPRINT("WINDOWS: console has been closed" NL);
1419 #endif
1420  }
1421 #elif defined(XEMU_ARCH_MAC)
1422  if (macos_gui_started) {
1423  DEBUGPRINT("MACOS: GUI-startup detected, closing standard in/out/error file descriptors ..." NL);
1424  for (int fd = 0; fd <= 2; fd++) {
1425  int devnull = open("/dev/null", O_WRONLY); // WR by will, so even for STDIN, it will cause an error on read
1426  if (devnull >= 0 && devnull != fd)
1427  dup2(devnull, fd);
1428  if (devnull > 2)
1429  close(devnull);
1430  }
1431 #if 0
1432  // FIXME: do we really need this? AFAIK MacOS may cause to log things if terminal is not there but there is output, which is not so nice ...
1433  for (int fd = 0; fd < 100; fd++) {
1434  if (isatty(fd)) {
1435  if (fd <= 2) {
1436  int dupres = 0;
1437  int devnull = open("/dev/null", O_WRONLY); // WR by will, so even for STDIN, it will cause an error on read
1438  if (devnull >= 0 && devnull != fd)
1439  dupres = dup2(devnull, fd);
1440  if (devnull > 2)
1441  close(devnull);
1442  } else
1443  close(fd);
1444  }
1445  }
1446 #endif
1447  }
1448  sysconsole_is_open = 0;
1449 #else
1450  sysconsole_is_open = 0;
1451 #endif
1452 }
1453 
1454 
1455 int sysconsole_toggle ( int set )
1456 {
1457  switch (set) {
1458  case 0:
1459  sysconsole_close(NULL);
1460  break;
1461  case 1:
1462  sysconsole_open();
1463  break;
1464  default:
1465  if (sysconsole_is_open)
1466  sysconsole_close(NULL);
1467  else
1468  sysconsole_open();
1469  break;
1470  }
1471  return sysconsole_is_open;
1472 }
1473 
1474 #ifdef XEMU_ARCH_WIN
1475 
1476 // WideCharToMultiByte(UINT CodePage, DWORD dwFlags, _In_NLS_string_(cchWideChar)LPCWCH lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCCH lpDefaultChar, LPBOOL lpUsedDefaultChar)
1477 // CP_UTF8, 0, i, -1, o, size, NULL, NULL
1478 #define WIN_WCHAR_TO_UTF8(o,i,size) !WideCharToMultiByte(CP_UTF8, 0, i, -1, o, size, NULL, NULL)
1479 // int MultiByteToWideChar(UINT CodePage, DWORD dwFlags, _In_NLS_string_(cbMultiByte)LPCCH lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar)
1480 // CP_UTF8, 0, i, -1, o size
1481 #define WIN_UTF8_TO_WCHAR(o,i,size) !MultiByteToWideChar(CP_UTF8, 0, i, -1, o, size)
1482 
1483 #if 0
1484 #define WIN_WCHAR_TO_UTF8(o,i,size) xemu_winos_wchar_to_utf8
1485 #define WIN_UTF8_TO_WCHAR(o,i,size) xemu_winos_utf8_to_wchar
1486 #include <assert.h>
1487 // This function does not make fully extensive work to detect all errors etc ...
1488 int xemu_winos_utf8_to_wchar ( wchar_t *restrict o, const char *restrict i, size_t size )
1489 {
1490  Uint32 upos = 0;
1491  int ulen = 0;
1492  //BUILD_BUG_ON( sizeof(wchar_t) != 3 );
1493  static_assert(sizeof(wchar_t) == 2, "wchar_t must be two bytes long");
1494  for (;;) {
1495  Uint8 c = (unsigned)*i++;
1496  if (ulen == 1 && (c & 0xC0) != 0x80) {
1497  if (XEMU_UNLIKELY(!size--))
1498  return -1;
1499  if (XEMU_UNLIKELY(upos >= 0x100000)) // cannot be represented, even not by using surrogates! Dunno if it can happen AT ALL with utf8 source
1500  return -1;
1501  // FIXME, not so much idea about surrogate point pairs, maybe this code is totally worng what I "invented" here ...
1502  if (XEMU_UNLIKELY(upos >= (1U << (sizeof(wchar_t) << 3)))) {
1503  if (XEMU_UNLIKELY(!size--)) // check again, we need two chunks for a surrogate pair
1504  return -1;
1505  *o++ = (upos >> 10) + 0xD800; // high surrogate of the pair, STORE it
1506  upos = (upos & 1023) + 0xDC00; // this will be the low part, after this "if" ... which is also the normal case (no surrogate points needed)
1507  }
1508  *o++ = upos;
1509  ulen = 0;
1510  upos = 0;
1511  }
1512  if ((c & 0x80) == 0) {
1513  if (XEMU_UNLIKELY(!size--))
1514  return -1;
1515  if (XEMU_UNLIKELY(ulen))
1516  return -1;
1517  *o++ = c;
1518  if (!c)
1519  return 0; // WOW, the end :)
1520  } else if ((c & 0xE0) == 0xC0) {
1521  if (XEMU_UNLIKELY(ulen))
1522  return -1;
1523  ulen = 2;
1524  upos = c & 0x1F;
1525  } else if ((c & 0xF0) == 0xE0) {
1526  if (XEMU_UNLIKELY(ulen))
1527  return -1;
1528  ulen = 3;
1529  upos = c & 0x0F;
1530  } else if ((c & 0xF8) == 0xF0) {
1531  if (XEMU_UNLIKELY(ulen))
1532  return -1;
1533  ulen = 4;
1534  upos = c & 0x07;
1535  } else if ((c & 0xC0) == 0x80) {
1536  if (XEMU_UNLIKELY(ulen <= 1))
1537  return -1;
1538  ulen--;
1539  upos = (upos << 6) + (c & 0x3F);
1540  } else
1541  return -1;
1542  if (XEMU_UNLIKELY(ulen && !upos))
1543  return -1;
1544  }
1545 }
1546 
1547 
1548 
1549 int xemu_winos_wchar_to_utf8 ( char *restrict o, const wchar_t *restrict i, size_t size )
1550 {
1551  unsigned int sur = 0;
1552  for (;;) {
1553  unsigned int c = *i++;
1554  // FIXME: check this surrogate madness a bit more ...
1555  // Personally I just tried to follow wikipedia, as it says:
1556  // There are 1024 "high" surrogates (D800–DBFF) and 1024 "low" surrogates (DC00–DFFF)
1557  // In UTF-16, they must always appear in pairs, as a high surrogate followed by a low surrogate, thus using 32 bits to denote one code point.
1558  if (XEMU_UNLIKELY(c >= 0xD800 && c <= 0xDBFF)) {
1559  if (XEMU_UNLIKELY(sur))
1560  return -1;
1561  sur = (c - 0xD800) << 10;
1562  if (XEMU_UNLIKELY(!sur))
1563  return -1;
1564  continue;
1565  } else if (XEMU_UNLIKELY(c >= 0xDC00 && c <= 0xDFFF)) {
1566  if (XEMU_UNLIKELY(!sur))
1567  return -1;
1568  c = sur + (c - 0xDC00);
1569  sur = 0;
1570  }
1571  if (XEMU_UNLIKELY(sur))
1572  return -1;
1573  if (c < 0x80) {
1574  if (XEMU_UNLIKELY(size < 1))
1575  return -1;
1576  size =- 1;
1577  *o++ = c;
1578  if (!c)
1579  return 0; // Wow, the end :)
1580  } else if (c < 0x800) {
1581  if (XEMU_UNLIKELY(size < 2))
1582  return -1;
1583  size -= 2;
1584  *o++ = 0xC0 + ( c >> 6 );
1585  *o++ = 0x80 + ( c & 0x3F);
1586  } else if (c < 0x10000) {
1587  if (XEMU_UNLIKELY(size < 3))
1588  return -1;
1589  size -= 3;
1590  *o++ = 0xE0 + ( c >> 12 );
1591  *o++ = 0x80 + ((c >> 6) & 0x3F);
1592  *o++ = 0x80 + ( c & 0x3F);
1593  } else if (c < 0x110000) {
1594  if (XEMU_UNLIKELY(size < 4))
1595  return -1;
1596  size -= 4;
1597  *o++ = 0xF0 + ( c >> 18 );
1598  *o++ = 0x80 + ((c >> 12) & 0x3F);
1599  *o++ = 0x80 + ((c >> 6) & 0x3F);
1600  *o++ = 0x80 + ( c & 0x3F);
1601  } else
1602  return -1;
1603  }
1604 }
1605 #endif
1606 
1607 int xemu_os_open ( const char *fn, int flags )
1608 {
1609  wchar_t wchar_fn[PATH_MAX];
1610  if (WIN_UTF8_TO_WCHAR(wchar_fn, fn, PATH_MAX)) {
1611  errno = ENOENT;
1612  return -1;
1613  }
1614  return _wopen(wchar_fn, flags | O_BINARY);
1615 }
1616 
1617 int xemu_os_creat ( const char *fn, int flags, int pmode )
1618 {
1619  wchar_t wchar_fn[PATH_MAX];
1620  if (WIN_UTF8_TO_WCHAR(wchar_fn, fn, PATH_MAX)) {
1621  errno = ENOENT;
1622  return -1;
1623  }
1624  return _wopen(wchar_fn, flags | O_BINARY, pmode);
1625 }
1626 
1627 FILE *xemu_os_fopen ( const char *restrict fn, const char *restrict mode )
1628 {
1629  wchar_t wchar_fn[PATH_MAX];
1630  wchar_t wchar_mode[32]; // FIXME?
1631  if (WIN_UTF8_TO_WCHAR(wchar_fn, fn, PATH_MAX)) {
1632  errno = ENOENT;
1633  return NULL;
1634  }
1635  if (WIN_UTF8_TO_WCHAR(wchar_mode, mode, sizeof wchar_mode)) {
1636  errno = EINVAL; // FIXME?
1637  return NULL;
1638  }
1639  return _wfopen(wchar_fn, wchar_mode);
1640 }
1641 
1642 int xemu_os_unlink ( const char *fn )
1643 {
1644  wchar_t wchar_fn[PATH_MAX];
1645  if (WIN_UTF8_TO_WCHAR(wchar_fn, fn, PATH_MAX)) {
1646  errno = ENOENT;
1647  return -1;
1648  }
1649  return _wunlink(wchar_fn);
1650 }
1651 
1652 #include <direct.h>
1653 
1654 int xemu_os_mkdir ( const char *fn, const int mode ) // "mode" parameter is unused in Windows
1655 {
1656  wchar_t wchar_fn[PATH_MAX];
1657  if (WIN_UTF8_TO_WCHAR(wchar_fn, fn, PATH_MAX)) {
1658  errno = ENOENT;
1659  return -1;
1660  }
1661  return _wmkdir(wchar_fn);
1662 }
1663 
1664 XDIR *xemu_os_opendir ( const char *fn )
1665 {
1666  wchar_t wchar_fn[PATH_MAX];
1667  if (WIN_UTF8_TO_WCHAR(wchar_fn, fn, PATH_MAX)) {
1668  errno = ENOENT;
1669  return NULL;
1670  }
1671  return _wopendir(wchar_fn);
1672 }
1673 
1674 int xemu_os_closedir ( XDIR *dirp )
1675 {
1676  return _wclosedir(dirp);
1677 }
1678 
1679 int xemu_os_readdir ( XDIR *dirp, char *fn )
1680 {
1681  const struct _wdirent *p;
1682  do {
1683  errno = 0;
1684  p = _wreaddir(dirp);
1685  if (!p)
1686  return -1;
1687  } while (WIN_WCHAR_TO_UTF8(fn, p->d_name, FILENAME_MAX)); // UGLY! Though without this probably an opendir/readdir scan would be interrupted by this anomaly ...
1688  return 0;
1689 }
1690 
1691 #include <assert.h>
1692 
1693 int xemu_os_stat ( const char *fn, struct stat *statbuf )
1694 {
1695  wchar_t wchar_fn[PATH_MAX];
1696  if (WIN_UTF8_TO_WCHAR(wchar_fn, fn, PATH_MAX)) {
1697  errno = ENOENT;
1698  return -1;
1699  }
1700  struct __stat64 st;
1701  if (_wstat64(wchar_fn, &st))
1702  return -1; // _wstat64() sets errno
1703  //static_assert(sizeof(statbuf->st_atime) <= 4, "32-bit time for stat");
1704  //static_assert(sizeof(statbuf->st_size) <= 4, "32-bit file size for stat");
1705  //FIXME: how can be sure we have 64-bit time and 64-bit file size ALWAYS, win32+win64 too!!! (2038 is not so far away now ...)
1706  //FIXME-2: how can we present the input parameter of this func being struct stat (POSIX) but the same requirements as the previous comment line ...
1707  statbuf->st_gid = st.st_gid;
1708  statbuf->st_atime = st.st_atime;
1709  statbuf->st_ctime = st.st_ctime;
1710  statbuf->st_dev = st.st_dev;
1711  statbuf->st_ino = st.st_ino;
1712  statbuf->st_mode = st.st_mode;
1713  statbuf->st_mtime = st.st_mtime;
1714  statbuf->st_nlink = st.st_nlink;
1715  statbuf->st_rdev = st.st_rdev;
1716  statbuf->st_size = st.st_size;
1717  statbuf->st_uid = st.st_uid;
1718  return 0;
1719 }
1720 
1721 
1722 #endif
1723 
1724 
1725 int xemu_os_file_exists ( const char *fn )
1726 {
1727  struct stat st;
1728  return !xemu_os_stat(fn, &st);
1729 }
1730 
1731 
1732 #ifndef XEMU_ARCH_WIN
1733 int xemu_os_readdir ( XDIR *dirp, char *fn )
1734 {
1735  errno = 0;
1736  const struct dirent *p = readdir(dirp);
1737  if (!p)
1738  return -1;
1739  strcpy(fn, p->d_name);
1740  return 0;
1741 }
1742 #endif
1743 
1744 
1745 /* -------------------------- SHA1 checksumming -------------------------- */
1746 
1747 
1748 static inline Uint32 leftrotate ( Uint32 i, unsigned int count )
1749 {
1750  count &= 31;
1751  return (i << count) + (i >> (32 - count));
1752 }
1753 
1754 
1755 static void sha1_chunk ( Uint32 h[5], const Uint8 *data )
1756 {
1757  // Note: this function has been written by me (LGB) by following the pseudocode from Wikipedia
1758  Uint32 w[80];
1759  // Split our chunk into sixteen 32-bit big-endian words
1760  for (unsigned int i = 0; i < 16; i++) {
1761  w[i] = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
1762  data += 4;
1763  }
1764  // Extend the sixteen 32-bit words into eighty 32-bit words
1765  for (unsigned int i = 16; i <= 79; i++)
1766  w[i] = leftrotate(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);
1767  // Initialize variables from the current state of the hash (previous chunk OR default hash values for SHA-1)
1768  Uint32 a = h[0];
1769  Uint32 b = h[1];
1770  Uint32 c = h[2];
1771  Uint32 d = h[3];
1772  Uint32 e = h[4];
1773  // Main loop for the 80 words
1774  for (unsigned int i = 0; i <= 79; i++) {
1775  Uint32 f, k;
1776  if (i <= 19) { // 0 ... 19
1777  f = (b & c) | ((~b) & d);
1778  k = 0x5A827999U;
1779  } else if (i <= 39) { // 20 .. 39
1780  f = b ^ c ^ d;
1781  k = 0x6ED9EBA1U;
1782  } else if (i <= 59) { // 40 .. 59
1783  f = (b & c) | (b & d) | (c & d);
1784  k = 0x8F1BBCDCU;
1785  } else { // 60 .. 79
1786  f = b ^ c ^ d;
1787  k = 0xCA62C1D6U;
1788  }
1789  Uint32 temp = leftrotate(a, 5) + f + e + k + w[i];
1790  e = d;
1791  d = c;
1792  c = leftrotate(b, 30);
1793  b = a;
1794  a = temp;
1795  }
1796  // Update hash value with this chunk's result
1797  h[0] += a;
1798  h[1] += b;
1799  h[2] += c;
1800  h[3] += d;
1801  h[4] += e;
1802 }
1803 
1804 
1806 {
1807  hash[0] = 0x67452301U;
1808  hash[1] = 0xEFCDAB89U;
1809  hash[2] = 0x98BADCFEU;
1810  hash[3] = 0x10325476U;
1811  hash[4] = 0xC3D2E1F0U;
1812  Uint64 size_in_bits = (Uint64)size << 3;
1813  // Process full chunks (if any)
1814  while (size >= 64) { // 64 bytes = 512 bits
1815  sha1_chunk(hash, data);
1816  data += 64;
1817  size -= 64;
1818  }
1819  // Process remaining sub-chunk + SHA specific additions: it may result in two chunks, actually!
1820  Uint8 tail[128], *tail_p;
1821  memset(tail, 0, sizeof tail);
1822  if (size)
1823  memcpy(tail, data, size);
1824  tail[size++] = 0x80; // append '1' bit at the end of message
1825  if (size > 64 - 8) {
1826  // Needs an additional chunk
1827  sha1_chunk(hash, tail);
1828  tail_p = tail + 64;
1829  } else
1830  tail_p = tail;
1831  // Last chunk, with size information at the end
1832  for (unsigned int i = 63; i >= 56; i--) {
1833  tail_p[i] = size_in_bits & 0xFF;
1834  size_in_bits >>= 8;
1835  }
1836  sha1_chunk(hash, tail_p);
1837 }
1838 
1839 
1841 {
1842  Uint32 hash[5];
1844  for (unsigned int i = 0; i < 5; i++) {
1845  *hash_bytes++ = (hash[i] >> 24) & 0xFF;
1846  *hash_bytes++ = (hash[i] >> 16) & 0xFF;
1847  *hash_bytes++ = (hash[i] >> 8) & 0xFF;
1848  *hash_bytes++ = (hash[i] ) & 0xFF;
1849  }
1850 }
1851 
1852 
1854 {
1855  Uint32 hash[5];
1857  sprintf(hash_str, "%08x%08x%08x%08x%08x", hash[0], hash[1], hash[2], hash[3], hash[4]);
1858 }
xemu_pre_init
void xemu_pre_init(const char *app_organization, const char *app_name, const char *slogan)
Definition: emutools.c:651
sdl_ren
SDL_Renderer * sdl_ren
Definition: emutools.c:78
__TIMING_METHOD_DESC
#define __TIMING_METHOD_DESC
ARE_YOU_SURE_DEFAULT_NO
#define ARE_YOU_SURE_DEFAULT_NO
Definition: emutools.h:126
INSTALL_DIRECTORY_ENTRY_NAME
#define INSTALL_DIRECTORY_ENTRY_NAME
Definition: emutools.h:43
debug_fp
FILE * debug_fp
Definition: emutools.c:110
xemu_set_viewport
void xemu_set_viewport(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, unsigned int flags)
Definition: emutools.c:844
seconds_timer_trigger
int seconds_timer_trigger
Definition: emutools.c:101
xemu_init_debug
int xemu_init_debug(const char *fn)
Definition: emutools.c:582
xemu_is_first_time_user
int xemu_is_first_time_user(void)
Definition: emutools.c:623
sysconsole_is_open
int sysconsole_is_open
Definition: emutools.c:109
XEMU_VIEWPORT_ADJUST_LOGICAL_SIZE
#define XEMU_VIEWPORT_ADJUST_LOGICAL_SIZE
Definition: emutools.h:146
ZERO_INT
const int ZERO_INT
Definition: emutools.c:58
chatty_xemu
int chatty_xemu
Definition: emutools.c:111
xemu_timekeeping_delay
void xemu_timekeeping_delay(int td_em)
Definition: emutools.c:405
emutools.h
sysconsole_close
void sysconsole_close(const char *waitmsg)
Definition: emutools.c:1393
sha1_hash_str
char sha1_hash_str[41]
Definition: emutools.h:237
restore_mouse_grab
void restore_mouse_grab(void)
Definition: emutools.c:158
window_title_custom_addon
char * window_title_custom_addon
Definition: emutools.c:90
flags
Uint8 flags
Definition: z8k1.c:126
sdl_default_win_y_size
int sdl_default_win_y_size
Definition: emutools.c:113
EMPTY_STR
const char EMPTY_STR[]
Definition: emutools.c:57
ARE_YOU_SURE_OVERRIDE
#define ARE_YOU_SURE_OVERRIDE
Definition: emutools.h:124
xemu_get_localtime
struct tm * xemu_get_localtime(void)
Definition: emutools.c:187
sdlver_linked
SDL_version sdlver_linked
Definition: emutools.c:102
sdl_base_dir
char * sdl_base_dir
Definition: emutools.c:97
O_BINARY
#define O_BINARY
Definition: emutools_basicdefs.h:140
XEMU_MISSING_BIGGEST_ALIGNMENT_WORKAROUND
#define XEMU_MISSING_BIGGEST_ALIGNMENT_WORKAROUND
Definition: emutools_basicdefs.h:180
ENDIAN_NAME
#define ENDIAN_NAME
Definition: emutools_basicdefs.h:199
xemu_os_file_exists
int xemu_os_file_exists(const char *fn)
Definition: emutools.c:1725
sdl_window_title
char * sdl_window_title
Definition: emutools.c:89
colour
Uint32 colour
Definition: vera.c:67
items
const struct menu_st * items[XEMUGUI_MAX_ITEMS]
Definition: gui_win.c:33
fd
int fd
Definition: hdos.c:62
xemu_update_screen
void xemu_update_screen(void)
Definition: emutools.c:1184
xemu_os_closedir
#define xemu_os_closedir
Definition: emutools.h:269
xemu_set_icon_from_xpm
int xemu_set_icon_from_xpm(char *xpm[])
Definition: emutools.c:1066
i_am_sure_override
int i_am_sure_override
Definition: emutools.c:74
xemu_os_creat
#define xemu_os_creat
Definition: emutools.h:264
_xemu_malloc_ALIGNED_emulated
void * _xemu_malloc_ALIGNED_emulated(size_t size)
Definition: emutools.c:244
xemu_drop_events
void xemu_drop_events(void)
Definition: emutools.c:294
WARNING_WINDOW
#define WARNING_WINDOW(...)
Definition: xep128.h:115
is_mouse_grab
SDL_bool is_mouse_grab(void)
Definition: emutools.c:145
INFO_WINDOW
#define INFO_WINDOW(...)
Definition: xep128.h:114
sdl_pix_fmt
SDL_PixelFormat * sdl_pix_fmt
Definition: emutools.c:80
osd.c
fn
const char * fn
Definition: roms.c:42
set_mouse_grab
int set_mouse_grab(SDL_bool state, int force_allow)
Definition: emutools.c:131
sha1_hash_bytes
Uint8 sha1_hash_bytes[20]
Definition: emutools.h:238
SDL_ShowSimpleMessageBox_custom
int(* SDL_ShowSimpleMessageBox_custom)(Uint32, const char *, const char *, SDL_Window *)
Definition: emutools.c:62
ONE_INT
const int ONE_INT
Definition: emutools.c:59
dirp
XDIR * dirp
Definition: hdos.c:63
m65-memcontent-generator.data
data
Definition: m65-memcontent-generator.py:119
xemu_get_viewport
void xemu_get_viewport(unsigned int *x1, unsigned int *y1, unsigned int *x2, unsigned int *y2)
Definition: emutools.c:877
Uint32
uint32_t Uint32
Definition: fat32.c:49
sysconsole_open
void sysconsole_open(void)
Definition: emutools.c:1294
__BIGGEST_ALIGNMENT__
#define __BIGGEST_ALIGNMENT__
Definition: emutools_basicdefs.h:179
sdlver_compiled
SDL_version sdlver_compiled
Definition: emutools.c:102
xemu_get_uname_string
const char * xemu_get_uname_string(void)
Definition: emutools.c:468
xemu_app_org
char * xemu_app_org
Definition: emutools.c:85
ARCH_BITS
#define ARCH_BITS
Definition: emutools_basicdefs.h:89
Uint8
uint8_t Uint8
Definition: fat32.c:51
sdl_on_wayland
int sdl_on_wayland
Definition: emutools.c:81
sdl_on_x11
int sdl_on_x11
Definition: emutools.c:81
xemu_set_full_screen
void xemu_set_full_screen(int setting)
Definition: emutools.c:311
sha1_checksum_as_string
void sha1_checksum_as_string(sha1_hash_str hash_str, const Uint8 *data, Uint32 size)
Definition: emutools.c:1853
NULL_DEVICE
#define NULL_DEVICE
Definition: emutools_basicdefs.h:148
sdl_inst_dir
char * sdl_inst_dir
Definition: emutools.c:97
xemu_get_unixtime
time_t xemu_get_unixtime(void)
Definition: emutools.c:199
xemu_render_dummy_frame
void xemu_render_dummy_frame(Uint32 colour, int texture_x_size, int texture_y_size)
Definition: emutools.c:1132
xemu_os_opendir
#define xemu_os_opendir
Definition: emutools.h:268
xemu_malloc
void * xemu_malloc(size_t size)
Definition: emutools.c:226
x
int x
Definition: console.c:27
xemu_app_name
char * xemu_app_name
Definition: emutools.c:85
DEBUGPRINT
#define DEBUGPRINT(...)
Definition: emutools_basicdefs.h:171
sdl_pixel_buffer
Uint32 * sdl_pixel_buffer
Definition: emutools.c:92
xemu_os_stat
#define xemu_os_stat
Definition: emutools.h:270
sdl_default_win_x_size
int sdl_default_win_x_size
Definition: emutools.c:112
allow_mouse_grab
int allow_mouse_grab
Definition: emutools.c:118
xemu_start_pixel_buffer_access
Uint32 * xemu_start_pixel_buffer_access(int *texture_tail)
Definition: emutools.c:1153
sysconsole_toggle
int sysconsole_toggle(int set)
Definition: emutools.c:1455
xemu_get_microseconds
unsigned int xemu_get_microseconds(void)
Definition: emutools.c:205
ERROR_WINDOW
#define ERROR_WINDOW(...)
Definition: xep128.h:116
NL
#define NL
Definition: fat32.c:37
xemu_post_init
int xemu_post_init(const char *window_title, int is_resizable, int texture_x_size, int texture_y_size, int logical_x_size, int logical_y_size, int win_x_size, int win_y_size, Uint32 pixel_format, int n_colours, const Uint8 *colours, Uint32 *store_palette, int render_scale_quality, int locked_texture_update, void(*shutdown_callback)(void))
Definition: emutools.c:908
emu_is_fullscreen
int emu_is_fullscreen
Definition: emutools.c:95
xemu_frame_pixel_access_p
Uint32 * xemu_frame_pixel_access_p
Definition: emutools.c:93
xemu_get_timing_stat_string
void xemu_get_timing_stat_string(char *buf, unsigned int size)
Definition: emutools.c:538
STRINGIFY
#define STRINGIFY(x)
Definition: emutools_basicdefs.h:275
host_name
char host_name[13]
Definition: cpmfs.c:37
ARE_YOU_SURE_DEFAULT_YES
#define ARE_YOU_SURE_DEFAULT_YES
Definition: emutools.h:125
xemu_timekeeping_start
void xemu_timekeeping_start(void)
Definition: emutools.c:1122
xemu_os_unlink
#define xemu_os_unlink
Definition: emutools.h:266
DIRSEP_STR
#define DIRSEP_STR
Definition: emutools_basicdefs.h:141
size
int size
Definition: inject.c:37
clear_emu_events
void clear_emu_events(void)
Definition: commodore_65.c:193
ARE_YOU_SURE
int ARE_YOU_SURE(const char *s, int flags)
Definition: emutools.c:1202
sdl_tex
SDL_Texture * sdl_tex
Definition: emutools.c:79
__SLEEP_METHOD_DESC
#define __SLEEP_METHOD_DESC
xemu_os_fopen
#define xemu_os_fopen
Definition: emutools.h:265
MKDIR
#define MKDIR(__n)
Definition: emutools_basicdefs.h:147
xemu_hour_to_bcd12h
Uint8 xemu_hour_to_bcd12h(Uint8 hours, int hour_offset)
Definition: emutools.c:211
xemu_strdup
char * xemu_strdup(const char *s)
Definition: emutools.c:278
sdl_win
SDL_Window * sdl_win
Definition: emutools.c:77
colours
Uint32 colours[0x100]
Definition: vera.c:83
y
int y
Definition: console.c:27
str_are_you_sure_to_exit
const char * str_are_you_sure_to_exit
Definition: emutools.c:75
SDL_ShowMessageBox_custom
int(* SDL_ShowMessageBox_custom)(const SDL_MessageBoxData *, int *)
Definition: emutools.c:63
xemu_init_sdl
int xemu_init_sdl(void)
Definition: emutools.c:744
xemu_dump_version
void xemu_dump_version(FILE *fp, const char *slogan)
Definition: emutools_buildinfo.c:45
XEMU_CPU_STAT_INFO_BUFFER_SIZE
#define XEMU_CPU_STAT_INFO_BUFFER_SIZE
Definition: emutools.h:65
xemu_window_snap_to_optimal_size
void xemu_window_snap_to_optimal_size(int forced)
Definition: emutools.c:808
sha1_checksum_as_words
void sha1_checksum_as_words(Uint32 hash[5], const Uint8 *data, Uint32 size)
Definition: emutools.c:1805
QUESTION_WINDOW
#define QUESTION_WINDOW(items, msg)
Definition: xep128.h:124
name
const char * name
Definition: joystick.c:46
xemu_set_screen_mode
void xemu_set_screen_mode(int setting)
Definition: emutools.c:343
DEBUG
#define DEBUG(...)
Definition: emutools_basicdefs.h:167
texture_x_size_in_bytes
int texture_x_size_in_bytes
Definition: emutools.c:94
sdl_winid
Uint32 sdl_winid
Definition: emutools.c:98
save_mouse_grab
void save_mouse_grab(void)
Definition: emutools.c:151
xemu_realloc
void * xemu_realloc(void *p, size_t size)
Definition: emutools.c:235
_sdl_emu_secured_modal_box_
int _sdl_emu_secured_modal_box_(const char *items_in, const char *msg)
Definition: emutools.c:1220
xemu_malloc_ALIGNED
void * xemu_malloc_ALIGNED(size_t size)
sdl_pref_dir
char * sdl_pref_dir
Definition: emutools.c:97
FATAL
#define FATAL(...)
Definition: xep128.h:117
register_new_texture_creation
int register_new_texture_creation
Definition: emutools.c:84
window_title_info_addon
char * window_title_info_addon
Definition: emutools.c:91
xemu_restrdup
void xemu_restrdup(char **ptr, const char *str)
Definition: emutools.c:286
XDIR
DIR XDIR
Definition: emutools.h:262
sha1_checksum_as_bytes
void sha1_checksum_as_bytes(sha1_hash_bytes hash_bytes, const Uint8 *data, Uint32 size)
Definition: emutools.c:1840
xemu_os_readdir
int xemu_os_readdir(XDIR *dirp, char *fn)
Definition: emutools.c:1733
xemu_os_mkdir
#define xemu_os_mkdir
Definition: emutools.h:267
XEMU_UNLIKELY
#define XEMU_UNLIKELY(__x__)
Definition: emutools_basicdefs.h:125
pixels
Uint32 * pixels
Definition: osd.c:33
xemu_os_open
#define xemu_os_open
Definition: emutools.h:263
buf
Uint8 buf[512]
Definition: fat32.c:155
st
struct stat st
Definition: cpmfs.c:43
DIRSEP_CHR
#define DIRSEP_CHR
Definition: emutools_basicdefs.h:142