12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019 |
- /*
- * meg4/platform/common.h
- *
- * Copyright (C) 2023 bzt
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * @brief Common on all platforms, mostly OS specific file management stuff
- *
- */
- #include <stdio.h>
- #include <limits.h>
- #ifndef PATH_MAX
- #define PATH_MAX 4096
- #endif
- #ifndef FILENAME_MAX
- #define FILENAME_MAX 255
- #endif
- /* command line flags */
- int verbose = 0, zenity = 0, nearest = 0, windowed = 0, strace = 0;
- char *main_floppydir = NULL;
- void main_hdr(void);
- void meg4_export(char *name, int binary);
- extern uint8_t binary_game[];
- /**
- * Windows workaround
- */
- #ifdef __WIN32__
- #define CLIFLAG "/"
- #define SEP "\\"
- #include <windows.h>
- #include <winnls.h>
- #include <fileapi.h>
- #include <shlobj.h>
- #include <shellapi.h>
- /* Ehhh, we MUST include this AFTER the standard windows headers, otherwise OFN doesn't work */
- #ifdef SDL_VERSION_ATLEAST
- #include <SDL_syswm.h>
- #endif
- static HWND hwnd = NULL;
- static HINSTANCE hWinInstance;
- static char *main_lng = NULL;
- /* these two functions were borrowed from sdl_windows_main.c */
- static void UnEscapeQuotes(char *arg)
- {
- char *last = NULL, *c_curr, *c_last;
- while (*arg) {
- if (*arg == '"' && (last != NULL && *last == '\\')) {
- c_curr = arg;
- c_last = last;
- while (*c_curr) {
- *c_last = *c_curr;
- c_last = c_curr;
- c_curr++;
- }
- *c_last = '\0';
- }
- last = arg;
- arg++;
- }
- }
- /* Parse a command line buffer into arguments */
- static int ParseCommandLine(WCHAR *cmdline, char **argv)
- {
- char *bufp, *args;
- char *lastp = NULL;
- int argc, last_argc, l;
- l = WideCharToMultiByte(CP_UTF8, 0, cmdline, -1, NULL, 0, NULL, NULL);
- if(!l || !(args = malloc(l))) return 0;
- WideCharToMultiByte(CP_UTF8, 0, cmdline, -1, args, l, NULL, NULL);
- argc = last_argc = 0;
- for (bufp = args; *bufp;) {
- /* Skip leading whitespace */
- while (*bufp == ' ') {
- ++bufp;
- }
- /* Skip over argument */
- if (*bufp == '"') {
- ++bufp;
- if (*bufp) {
- if (argv) {
- argv[argc] = bufp;
- }
- ++argc;
- }
- /* Skip over word */
- lastp = bufp;
- while (*bufp && (*bufp != '"' || *lastp == '\\')) {
- lastp = bufp;
- ++bufp;
- }
- } else {
- if (*bufp) {
- if (argv) {
- argv[argc] = bufp;
- }
- ++argc;
- }
- /* Skip over word */
- while (*bufp && *bufp != ' ') {
- ++bufp;
- }
- }
- if (*bufp) {
- if (argv) {
- *bufp = '\0';
- }
- ++bufp;
- }
- /* Strip out \ from \" sequences */
- if (argv && last_argc != argc) {
- UnEscapeQuotes(argv[last_argc]);
- }
- last_argc = argc;
- }
- if (argv) {
- argv[argc] = NULL;
- }
- return (argc);
- }
- /* Windows entry point */
- int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
- {
- WCHAR *cmdline = GetCommandLineW();
- int ret, argc = ParseCommandLine(cmdline, NULL);
- char **argv = calloc(argc+2, sizeof(char*));
- char *lng = getenv("LANG");
- FILE *f;
- int lid;
- (void)hPrevInstance;
- (void)lpCmdLine;
- (void)nCmdShow;
- hWinInstance = hInstance;
- if(!lng) {
- lid = GetUserDefaultLangID(); /* GetUserDefaultUILanguage(); */
- /* see https://docs.microsoft.com/en-us/windows/win32/intl/language-identifier-constants-and-strings */
- switch(lid & 0xFF) {
- case 0x01: lng = "ar"; break; case 0x02: lng = "bg"; break; case 0x03: lng = "ca"; break;
- case 0x04: lng = "zh"; break; case 0x05: lng = "cs"; break; case 0x06: lng = "da"; break;
- case 0x07: lng = "de"; break; case 0x08: lng = "el"; break; case 0x0A: lng = "es"; break;
- case 0x0B: lng = "fi"; break; case 0x0C: lng = "fr"; break; case 0x0D: lng = "he"; break;
- case 0x0E: lng = "hu"; break; case 0x0F: lng = "is"; break; case 0x10: lng = "it"; break;
- case 0x11: lng = "ja"; break; case 0x12: lng = "ko"; break; case 0x13: lng = "nl"; break;
- case 0x14: lng = "no"; break; case 0x15: lng = "pl"; break; case 0x16: lng = "pt"; break;
- case 0x17: lng = "rm"; break; case 0x18: lng = "ro"; break; case 0x19: lng = "ru"; break;
- case 0x1A: lng = "hr"; break; case 0x1B: lng = "sk"; break; case 0x1C: lng = "sq"; break;
- case 0x1D: lng = "sv"; break; case 0x1E: lng = "th"; break; case 0x1F: lng = "tr"; break;
- case 0x20: lng = "ur"; break; case 0x21: lng = "id"; break; case 0x22: lng = "uk"; break;
- case 0x23: lng = "be"; break; case 0x24: lng = "sl"; break; case 0x25: lng = "et"; break;
- case 0x26: lng = "lv"; break; case 0x27: lng = "lt"; break; case 0x29: lng = "fa"; break;
- case 0x2A: lng = "vi"; break; case 0x2B: lng = "hy"; break; case 0x2D: lng = "bq"; break;
- case 0x2F: lng = "mk"; break; case 0x36: lng = "af"; break; case 0x37: lng = "ka"; break;
- case 0x38: lng = "fo"; break; case 0x39: lng = "hi"; break; case 0x3A: lng = "mt"; break;
- case 0x3C: lng = "gd"; break; case 0x3E: lng = "ms"; break; case 0x3F: lng = "kk"; break;
- case 0x40: lng = "ky"; break; case 0x45: lng = "bn"; break; case 0x47: lng = "gu"; break;
- case 0x4D: lng = "as"; break; case 0x4E: lng = "mr"; break; case 0x4F: lng = "sa"; break;
- case 0x53: lng = "kh"; break; case 0x54: lng = "lo"; break; case 0x56: lng = "gl"; break;
- case 0x5E: lng = "am"; break; case 0x62: lng = "fy"; break; case 0x68: lng = "ha"; break;
- case 0x6D: lng = "ba"; break; case 0x6E: lng = "lb"; break; case 0x6F: lng = "kl"; break;
- case 0x7E: lng = "br"; break; case 0x92: lng = "ku"; break; case 0x09: default: lng = "en"; break;
- }
- }
- main_lng = lng;
- /* restore stdout to console */
- AttachConsole(ATTACH_PARENT_PROCESS);
- f = _fdopen(_open_osfhandle((intptr_t)GetStdHandle(STD_OUTPUT_HANDLE), 0x4000/*_O_TEXT*/), "w");
- if(f) { *stdout = *f; *stderr = *f; }
- printf("\r\n");
- ParseCommandLine(cmdline, argv);
- #ifdef SDL_h_
- SDL_SetMainReady();
- #endif
- ret = main(argc, argv);
- free(argv);
- exit(ret);
- return ret;
- }
- /**
- * Read a file entirely into memory
- */
- uint8_t* main_readfile(char *file, int *size)
- {
- #ifdef __EMSCRIPTEN__
- (void)file; (void)size;
- return NULL;
- #else
- wchar_t szFile[PATH_MAX + FILENAME_MAX + 1];
- uint8_t *data = NULL;
- HANDLE f;
- DWORD r, t;
- if(!file || !*file || !size) return NULL;
- MultiByteToWideChar(CP_UTF8, 0, file, -1, szFile, PATH_MAX + FILENAME_MAX);
- f = CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
- if(f) {
- r = GetFileSize(f, NULL);
- *size = r;
- data = (uint8_t*)malloc(*size);
- if(data) {
- memset(data, 0, *size);
- if(!ReadFile(f, data, r, &t, NULL) || r != t) { free(data); data = NULL; *size = 0; }
- }
- CloseHandle(f);
- }
- return data;
- #endif
- }
- /**
- * Write to a file
- */
- int main_writefile(char *file, uint8_t *buf, int size)
- {
- #ifdef __EMSCRIPTEN__
- (void)file; (void)buf; (void)size;
- return 0;
- #else
- int ret = 0;
- wchar_t szFile[PATH_MAX + FILENAME_MAX + 1];
- HANDLE f;
- DWORD w = size, t;
- if(!file || !*file || !buf || size < 1) return 0;
- MultiByteToWideChar(CP_UTF8, 0, file, -1, szFile, PATH_MAX + FILENAME_MAX);
- f = CreateFileW(szFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- if(f) {
- ret = (WriteFile(f, buf, w, &t, NULL) && w == t);
- CloseHandle(f);
- }
- return ret;
- #endif
- }
- /**
- * Open open file modal and import selected file
- */
- void main_openfile(void)
- {
- #if !defined(EMBED) && !defined(NOEDITORS)
- #ifdef __EMSCRIPTEN__
- EM_ASM({ document.getElementById('meg4_upload').click(); });
- #else
- OPENFILENAMEW ofn;
- wchar_t szFile[PATH_MAX + FILENAME_MAX + 1];
- char fn[PATH_MAX + FILENAME_MAX + 1], *n;
- int len;
- uint8_t *buf;
- memset(&szFile,0,sizeof(szFile));
- memset(&ofn,0,sizeof(ofn));
- ofn.lStructSize = sizeof(ofn);
- ofn.hwndOwner = hwnd;
- ofn.hInstance = hWinInstance;
- ofn.lpstrFile = szFile;
- ofn.nMaxFile = sizeof(szFile)-1;
- ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST;
- if(GetOpenFileNameW(&ofn)) {
- WideCharToMultiByte(CP_UTF8, 0, szFile, -1, fn, PATH_MAX + FILENAME_MAX, NULL, NULL);
- if((buf = main_readfile(fn, &len))) {
- n = strrchr(fn, SEP[0]); if(!n) n = fn; else n++;
- meg4_insert(fn, buf, len);
- free(buf);
- }
- main_focus();
- }
- #endif
- #endif
- }
- /**
- * Open save file modal and write buffer to selected file
- */
- int main_savefile(const char *name, uint8_t *buf, int len)
- {
- #ifndef NOEDITORS
- #ifdef __EMSCRIPTEN__
- if(name && buf && len > 0) {
- EM_ASM({ meg4_savefile($0, $1, $2, $3); }, name, strlen(name), buf, len);
- return 1;
- }
- return 0;
- #else
- #ifndef EMBED
- OPENFILENAMEW ofn;
- wchar_t szExt[FILENAME_MAX];
- int l = 0;
- #endif
- wchar_t szFile[PATH_MAX + FILENAME_MAX + 1];
- char fn[PATH_MAX + FILENAME_MAX + 1];
- int ret = 0;
- if(!name || !*name || !buf || len < 1) return 0;
- memset(&szFile,0,sizeof(szFile));
- if(main_floppydir && *main_floppydir) {
- strcpy(fn, main_floppydir);
- if(fn[strlen(fn) - 1] == SEP[0]) fn[strlen(fn) - 1] = 0;
- MultiByteToWideChar(CP_UTF8, 0, fn, -1, szFile, sizeof(szFile)-1);
- _wmkdir(szFile);
- strcat(fn, SEP);
- strcat(fn, name);
- return main_writefile(fn, buf, len);
- }
- #ifndef EMBED
- else {
- memset(&szExt,0,sizeof(szExt));
- memcpy(szExt, L"All\0*.*\0", 18);
- l = MultiByteToWideChar(CP_UTF8, 0, name, -1, szFile, sizeof(szFile)-1);
- while(l > 0 && szFile[l - 1] != L'.') l--;
- if(l > 0) wsprintfW(szExt, L"%s\0*.%s\0", szFile + l, szFile + l);
- memset(&ofn,0,sizeof(ofn));
- ofn.lStructSize = sizeof(ofn);
- ofn.hwndOwner = hwnd;
- ofn.hInstance = hWinInstance;
- ofn.lpstrFilter = szExt;
- ofn.lpstrFile = szFile;
- ofn.nMaxFile = sizeof(szFile)-1;
- ofn.lpstrDefExt = l > 0 ? &szFile[l] : NULL;
- ofn.Flags = OFN_EXPLORER | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
- if(buf && len > 0 && GetSaveFileNameW(&ofn)) {
- WideCharToMultiByte(CP_UTF8, 0, szFile, -1, fn, PATH_MAX + FILENAME_MAX + 1, NULL, NULL);
- ret = main_writefile(fn, buf, len);
- }
- main_focus();
- }
- #endif
- #endif
- return ret;
- #else
- (void)name; (void)buf; (void)len;
- return 0;
- #endif
- }
- /**
- * Return floppy list
- */
- char **main_getfloppies(void)
- {
- #if !defined(__EMSCRIPTEN__) && !defined(NOEDITORS)
- wchar_t szFile[PATH_MAX + FILENAME_MAX + 1];
- WIN32_FIND_DATAW ffd;
- HANDLE h;
- int n = 0, j, l;
- char **ret = NULL;
- if(!main_floppydir || !*main_floppydir) return NULL;
- ret = (char**)malloc(sizeof(char*));
- if(!ret) return NULL; else ret[0] = NULL;
- memset(&szFile,0,sizeof(szFile));
- l = MultiByteToWideChar(CP_UTF8, 0, main_floppydir, -1, szFile, sizeof(szFile)-1) - 1;
- if(l < 1) return NULL;
- if(szFile[l - 1] != L'\\') szFile[l++] = L'\\';
- wcscpy_s(szFile + l, FILENAME_MAX, L"*.PNG");
- h = FindFirstFileW(szFile, &ffd);
- if(h != INVALID_HANDLE_VALUE) {
- do {
- wcscpy_s(szFile + l, FILENAME_MAX, ffd.cFileName);
- j = wcslen(ffd.cFileName) * 4;
- if(ffd.cFileName[0] == L'.' || !j) continue;
- ret = (char**)realloc(ret, (n + 2) * sizeof(char*));
- if(!ret) break;
- ret[n + 1] = NULL;
- ret[n] = (char*)malloc(l + j + 1);
- if(!ret[n]) continue;
- WideCharToMultiByte(CP_UTF8, 0, szFile, -1, ret[n], l + j + 1, NULL, NULL);
- n++;
- } while(FindNextFileW(h, &ffd) != 0);
- FindClose(h);
- }
- return ret;
- #else
- return NULL;
- #endif
- }
- #ifndef __EMSCRIPTEN__
- /**
- * Save a config file
- */
- int main_cfgsave(char *cfg, uint8_t *buf, int len)
- {
- HANDLE f;
- DWORD w = len, t;
- wchar_t szFile[PATH_MAX + FILENAME_MAX + 1], szCfg[FILENAME_MAX];
- int ret = 0, i;
- if(!SHGetFolderPathW(HWND_DESKTOP, CSIDL_PROFILE, NULL, 0, szFile)) {
- MultiByteToWideChar(CP_UTF8, 0, cfg, -1, szCfg, sizeof(szCfg)-1);
- wcscat(szFile, L"\\AppData"); _wmkdir(szFile);
- wcscat(szFile, L"\\Local"); _wmkdir(szFile);
- wcscat(szFile, L"\\MEG-4"); _wmkdir(szFile);
- wcscat(szFile, L"\\"); i = wcslen(szFile); wcscat(szFile, szCfg);
- for(; szFile[i]; i++) if(szFile[i] == L'/' || szFile[i] == L'\\') { szFile[i] = 0; _wmkdir(szFile); szFile[i] = L'\\'; }
- f = CreateFileW(szFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- if(f) {
- ret = (WriteFile(f, buf, w, &t, NULL) && w == t);
- CloseHandle(f);
- }
- }
- return ret;
- }
- /**
- * Load a config file
- */
- uint8_t *main_cfgload(char *cfg, int *len)
- {
- uint8_t *data = NULL;
- HANDLE f;
- DWORD r, t;
- wchar_t szFile[PATH_MAX + FILENAME_MAX + 1], szCfg[FILENAME_MAX];
- int i;
- if(!SHGetFolderPathW(HWND_DESKTOP, CSIDL_PROFILE, NULL, 0, szFile)) {
- MultiByteToWideChar(CP_UTF8, 0, cfg, -1, szCfg, sizeof(szCfg)-1);
- wcscat(szFile, L"\\AppData\\Local\\MEG-4\\"); wcscat(szFile, szCfg);
- for(i = 0; szFile[i]; i++) if(szFile[i] == L'/') szFile[i] = '\\';
- f = CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
- if(f) {
- r = GetFileSize(f, NULL);
- *len = r;
- data = (uint8_t*)malloc(*len + 1);
- if(data) {
- memset(data, 0, *len + 1);
- if(!ReadFile(f, data, r, &t, NULL) || r != t) { free(data); data = NULL; *len = 0; }
- }
- CloseHandle(f);
- }
- }
- return data;
- }
- #endif
- #else
- #define CLIFLAG "-"
- #define SEP "/"
- #include <dirent.h>
- #ifdef _MACOS_
- #include <AppKit/AppKit.h>
- #else
- void main_delay(int msec);
- #include <signal.h> /* including the glib version of this with __USE_MISC doesn't compile... */
- #define __USE_MISC /* needed for MAP_ANONYMOUS */
- #include <dlfcn.h>
- #include <unistd.h>
- #include <sys/mman.h>
- #include <sys/stat.h> /* mkdir... */
- #include <sys/types.h>
- #ifndef MAP_ANONYMOUS
- #define MAP_ANONYMOUS 0x20
- #endif
- int strcasecmp(const char *, const char *);
- /* some moron hide these behind feature defines which don't work if you have __USE_MISC... */
- int kill(pid_t pid, int sig);
- FILE *popen(const char *command, const char *type);
- int pclose(FILE *stream);
- /* gtk is sooo fucked up, DO NOT include its headers... */
- /*#include <gtk/gtk.h>*/
- void (*gtk_init)(int *argc, char ***argv);
- void* (*gtk_file_chooser_dialog_new)(const char *title, void *parent, int action, const char *first_button_text, ...);
- int (*gtk_dialog_run)(void *dialog);
- void (*gtk_widget_destroy)(void *widget);
- char* (*gtk_file_chooser_get_filename)(void *chooser);
- void (*gtk_file_chooser_set_do_overwrite_confirmation)(void *chooser, int do_overwrite_confirmation);
- void (*gtk_file_chooser_set_create_folders)(void *chooser, int create_folders);
- int (*gtk_file_chooser_set_current_name)(void *chooser, const char *filename);
- #endif
- /**
- * Read a file entirely into memory
- */
- uint8_t* main_readfile(char *file, int *size)
- {
- #ifdef __EMSCRIPTEN__
- (void)file; (void)size;
- return NULL;
- #else
- uint8_t *data = NULL;
- FILE *f;
- if(!file || !*file || !size) return NULL;
- f = fopen(file, "rb");
- if(f) {
- fseek(f, 0L, SEEK_END);
- *size = (int)ftell(f);
- fseek(f, 0L, SEEK_SET);
- data = (uint8_t*)malloc(*size);
- if(data) {
- memset(data, 0, *size);
- if((int)fread(data, 1, *size, f) != *size) { free(data); data = NULL; *size = 0; }
- }
- fclose(f);
- }
- return data;
- #endif
- }
- /**
- * Write to a file
- */
- int main_writefile(char *file, uint8_t *buf, int size)
- {
- #ifdef __EMSCRIPTEN__
- (void)file; (void)buf; (void)size;
- return 0;
- #else
- int ret = 0;
- FILE *f;
- if(!file || !*file || !buf || size < 1) return 0;
- f = fopen(file, "wb");
- if(f) {
- ret = ((int)fwrite(buf, 1, size, f) == size);
- fclose(f);
- }
- return ret;
- #endif
- }
- /**
- * Open open file modal and import selected file
- */
- void main_openfile(void)
- {
- #if !defined(EMBED) && !defined(NOEDITORS)
- #ifdef __EMSCRIPTEN__
- EM_ASM({ document.getElementById('meg4_upload').click(); });
- #else
- char *fn = NULL, *n;
- int len;
- uint8_t *buf;
- #ifdef __ANDROID__
- /* TODO */
- #else
- #ifdef _MACOS_
- const char *utf8Path;
- NSURL *url;
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];
- NSOpenPanel *dialog = [NSOpenPanel openPanel];
- [dialog setAllowsMultipleSelection:NO];
- if([dialog runModal] == NSModalResponseOK) {
- url = [dialog URL];
- utf8Path = [[url path] UTF8String];
- len = strlen(utf8Path);
- fn = (char*)malloc(len + 1);
- if(fn) strcpy(ret, utf8Path);
- }
- [pool release];
- [keyWindow makeKeyAndOrderFront:nil];
- #else
- FILE *p = NULL;
- pid_t pid;
- void *chooser;
- void *handle;
- char *tmp1, *tmp2;
- tmp1 = mmap(NULL, PATH_MAX, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
- if(!tmp1) return;
- memset(tmp1, 0, PATH_MAX);
- meg4_showcursor();
- if(zenity) p = popen("/usr/bin/zenity --file-selection", "r");
- if(p) {
- main_log(1, "using zenity hack");
- if(!fgets(tmp1 + 1, PATH_MAX - 1, p)) main_log(1, "fgets error");
- pclose(p);
- for(tmp2 = tmp1 + 1; *tmp2 && *tmp2 != '\n' && *tmp2 != '\r'; tmp2++);
- *tmp2 = 0;
- tmp1[0] = 1;
- } else {
- main_log(1, "trying to dlopen gtk");
- if(!(pid = fork())) {
- handle = dlopen("libgtk-3.so", RTLD_LAZY | RTLD_LOCAL);
- if(handle) {
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wpedantic"
- #endif
- if( (gtk_init = dlsym(handle, "gtk_init")) &&
- (gtk_file_chooser_dialog_new = dlsym(handle, "gtk_file_chooser_dialog_new")) &&
- (gtk_dialog_run = dlsym(handle, "gtk_dialog_run")) &&
- (gtk_file_chooser_set_create_folders = dlsym(handle, "gtk_file_chooser_set_create_folders")) &&
- (gtk_file_chooser_set_do_overwrite_confirmation = dlsym(handle, "gtk_file_chooser_set_do_overwrite_confirmation")) &&
- (gtk_file_chooser_set_current_name = dlsym(handle, "gtk_file_chooser_set_current_name")) &&
- (gtk_file_chooser_get_filename = dlsym(handle, "gtk_file_chooser_get_filename")) &&
- (gtk_widget_destroy = dlsym(handle, "gtk_widget_destroy")) ) {
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
- (*gtk_init)(NULL, NULL);
- chooser = (*gtk_file_chooser_dialog_new)(NULL, NULL, 0, "gtk-cancel", -6, "gtk-open", -3, NULL);
- if((*gtk_dialog_run)(chooser) == -3) {
- tmp2 = (*gtk_file_chooser_get_filename)(chooser);
- if(tmp2) strncpy(tmp1 + 1, tmp2, PATH_MAX - 2);
- }
- (*gtk_widget_destroy)(chooser);
- } else fprintf(stderr, "meg4: unable to load GTK symbols\n");
- dlclose(handle);
- } else fprintf(stderr, "meg4: unable to run-time link the GTK3 library\n");
- tmp1[0] = 1;
- /* this will actually hang if gtk_init was called... */
- exit(0);
- }
- if(pid < 0) fprintf(stderr, "meg4: unable to fork\n");
- else {
- /* waitpid(pid, &ret, 0); */
- while(!tmp1[0] && !kill(pid, SIGCONT)) main_delay(100);
- kill(pid, SIGKILL);
- }
- }
- meg4_hidecursor();
- if(tmp1[1]) {
- fn = (char*)malloc(strlen(tmp1 + 1) + 1);
- if(fn) strcpy(fn, tmp1 + 1);
- }
- munmap(tmp1, PATH_MAX);
- #endif
- #endif
- main_focus();
- if(fn) {
- if((buf = main_readfile(fn, &len))) {
- n = strrchr(fn, SEP[0]); if(!n) n = fn; else n++;
- meg4_insert(fn, buf, len);
- free(buf);
- }
- free(fn);
- }
- #endif
- #endif
- }
- /**
- * Open save file modal and write buffer to selected file
- */
- int main_savefile(const char *name, uint8_t *buf, int len)
- {
- #ifndef NOEDITORS
- #ifdef __EMSCRIPTEN__
- if(name && buf && len > 0) {
- EM_ASM({ meg4_savefile($0, $1, $2, $3); }, name, strlen(name), buf, len);
- return 1;
- }
- return 0;
- #else
- char path[PATH_MAX + FILENAME_MAX + 2];
- int ret = 0;
- #ifndef EMBED
- char *fn = NULL;
- int i;
- #endif
- #ifdef __ANDROID__
- /* TODO */
- #else
- #ifdef _MACOS_
- const char *utf8Path;
- NSURL *url;
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];
- #else
- #ifndef EMBED
- FILE *p = NULL;
- pid_t pid;
- void *chooser;
- void *handle;
- char *tmp1, *tmp2;
- #endif
- #endif
- #endif
- if(!name || !*name || !buf || len < 1) return 0;
- if(main_floppydir && *main_floppydir) {
- strcpy(path, main_floppydir);
- if(path[strlen(path) - 1] == SEP[0]) path[strlen(path) - 1] = 0;
- mkdir(path, 0755);
- strcat(path, SEP);
- strcat(path, name);
- ret = main_writefile(path, buf, len);
- if(!memcmp(buf, "\177ELF", 4)) chmod(path, 0755);
- return ret;
- }
- #ifndef EMBED
- else {
- #ifdef __ANDROID__
- /* TODO */
- #else
- #ifdef _MACOS_
- NSSavePanel *dialog = [NSSavePanel savePanel];
- [dialog setExtensionHidden:NO];
- if([dialog runModal] == NSModalResponseOK) {
- url = [dialog URL];
- utf8Path = [[url path] UTF8String];
- i = strlen(utf8Path);
- fn = (char*)malloc(i + 1);
- if(fn) strcpy(ret, utf8Path);
- }
- [pool release];
- [keyWindow makeKeyAndOrderFront:nil];
- #else
- tmp1 = mmap(NULL, PATH_MAX, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
- if(!tmp1) return 0;
- memset(tmp1, 0, PATH_MAX);
- meg4_showcursor();
- if(zenity) {
- strcpy(tmp1, "/usr/bin/zenity --file-selection --save --filename=\""); tmp2 = tmp1 + strlen(tmp1);
- for(i = 0; name && name[i]; i++)
- if(name[i] >= ' ' && name[i] != '\"') *tmp2++ = name[i];
- *tmp2 = '\"';
- p = popen(tmp1, "r");
- memset(tmp1, 0, PATH_MAX);
- }
- if(p) {
- main_log(1, "using zenity hack");
- if(!fgets(tmp1 + 1, PATH_MAX - 1, p)) main_log(1, "fgets error");
- pclose(p);
- for(tmp2 = tmp1 + 1; *tmp2 && *tmp2 != '\n' && *tmp2 != '\r'; tmp2++);
- *tmp2 = 0;
- tmp1[0] = 1;
- } else {
- main_log(1, "trying to dlopen gtk");
- if(!(pid = fork())) {
- handle = dlopen("libgtk-3.so", RTLD_LAZY | RTLD_LOCAL);
- if(handle) {
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wpedantic"
- #endif
- if( (gtk_init = dlsym(handle, "gtk_init")) &&
- (gtk_file_chooser_dialog_new = dlsym(handle, "gtk_file_chooser_dialog_new")) &&
- (gtk_dialog_run = dlsym(handle, "gtk_dialog_run")) &&
- (gtk_file_chooser_set_create_folders = dlsym(handle, "gtk_file_chooser_set_create_folders")) &&
- (gtk_file_chooser_set_do_overwrite_confirmation = dlsym(handle, "gtk_file_chooser_set_do_overwrite_confirmation")) &&
- (gtk_file_chooser_set_current_name = dlsym(handle, "gtk_file_chooser_set_current_name")) &&
- (gtk_file_chooser_get_filename = dlsym(handle, "gtk_file_chooser_get_filename")) &&
- (gtk_widget_destroy = dlsym(handle, "gtk_widget_destroy")) ) {
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
- (*gtk_init)(NULL, NULL);
- chooser = (*gtk_file_chooser_dialog_new)(NULL, NULL, 1, "gtk-cancel", -6, "gtk-save", -3, NULL);
- (*gtk_file_chooser_set_create_folders)(chooser, 1);
- (*gtk_file_chooser_set_do_overwrite_confirmation)(chooser, 1);
- (*gtk_file_chooser_set_current_name)(chooser, name);
- if((*gtk_dialog_run)(chooser) == -3) {
- tmp2 = (*gtk_file_chooser_get_filename)(chooser);
- if(tmp2) strncpy(tmp1 + 1, tmp2, PATH_MAX - 2);
- }
- (*gtk_widget_destroy)(chooser);
- } else fprintf(stderr, "meg4: unable to load GTK symbols\n");
- dlclose(handle);
- } else fprintf(stderr, "meg4: unable to run-time link the GTK3 library\n");
- tmp1[0] = 1;
- /* this will actually hang if gtk_init was called... */
- exit(0);
- }
- if(pid < 0) fprintf(stderr, "meg4: unable to fork\n");
- else {
- /* waitpid(pid, &ret, 0); */
- while(!tmp1[0] && !kill(pid, SIGCONT)) main_delay(100);
- kill(pid, SIGKILL);
- }
- }
- meg4_hidecursor();
- if(tmp1[1]) {
- fn = (char*)malloc(strlen(tmp1 + 1) + 1);
- if(fn) strcpy(fn, tmp1 + 1);
- }
- munmap(tmp1, PATH_MAX);
- #endif
- main_focus();
- if(fn) {
- ret = main_writefile(fn, buf, len);
- if(!memcmp(buf, "\177ELF", 4)) chmod(fn, 0755);
- free(fn);
- }
- }
- #endif
- #endif
- return ret;
- #endif
- #else
- (void)name; (void)buf; (void)len;
- return 0;
- #endif
- }
- /**
- * Return floppy list
- */
- char **main_getfloppies(void)
- {
- #if !defined(__EMSCRIPTEN__) && !defined(NOEDITORS)
- DIR *dir;
- struct dirent *ent;
- char fn[PATH_MAX + FILENAME_MAX + 1], *ext, **ret = NULL;
- int n = 0, j, l;
- if(!main_floppydir || !*main_floppydir) return NULL;
- ret = (char**)malloc(sizeof(char*));
- if(!ret) return NULL; else ret[0] = NULL;
- strcpy(fn, main_floppydir); l = strlen(fn);
- if(l > 0 && fn[l - 1] == SEP[0]) fn[--l] = 0;
- if((dir = opendir(fn)) != NULL) {
- while ((ent = readdir(dir)) != NULL) {
- if(ent->d_name[0] == '.' || !(ext = strrchr(ent->d_name, '.')) || strcasecmp(ext, ".png")) continue;
- fn[l] = SEP[0]; strncpy(fn + l + 1, ent->d_name, FILENAME_MAX);
- j = strlen(fn);
- if(!j) continue;
- ret = (char**)realloc(ret, (n + 2) * sizeof(char*));
- if(!ret) break;
- ret[n + 1] = NULL;
- ret[n] = (char*)malloc(j + 1);
- if(!ret[n]) continue;
- strcpy(ret[n], fn);
- n++;
- }
- closedir(dir);
- }
- return ret;
- #else
- return NULL;
- #endif
- }
- #ifndef __EMSCRIPTEN__
- /**
- * Save a config file
- */
- int main_cfgsave(char *cfg, uint8_t *buf, int len)
- {
- char file[PATH_MAX + FILENAME_MAX + 1], *tmp =
- #ifdef USE_INIT
- "/mnt/MEG-4";
- #else
- # ifdef __ANDROID__
- SDL_AndroidGetExternalStoragePath();
- # else
- # ifdef __LIBRETRO__
- main_floppydir;
- # else
- getenv("HOME");
- # endif
- # endif
- #endif
- int ret = 0, i;
- if(tmp && *tmp) {
- strcpy(file, tmp);
- strcat(file, "/.config"); mkdir(file, 0755);
- strcat(file, "/MEG-4"); mkdir(file, 0700);
- strcat(file, "/"); i = strlen(file); strcat(file, cfg);
- for(; file[i]; i++) if(file[i] == '/') { file[i] = 0; mkdir(file, 0755); file[i] = '/'; }
- ret = main_writefile(file, buf, len);
- }
- return ret;
- }
- /**
- * Load a config file
- */
- uint8_t *main_cfgload(char *cfg, int *len)
- {
- uint8_t *ret = NULL;
- char file[PATH_MAX + FILENAME_MAX + 1], *tmp =
- #ifdef USE_INIT
- "/mnt/MEG-4";
- #else
- # ifdef __ANDROID__
- SDL_AndroidGetExternalStoragePath();
- # else
- # ifdef __LIBRETRO__
- main_floppydir;
- # else
- getenv("HOME");
- # endif
- # endif
- #endif
- if(tmp && *tmp) {
- strcpy(file, tmp);
- strcat(file, "/.config/MEG-4/"); strcat(file, cfg);
- ret = main_readfile(file, len);
- }
- return ret;
- }
- #endif
- #endif
- #ifdef __EMSCRIPTEN__
- /**
- * Save a config file
- */
- int main_cfgsave(char *cfg, uint8_t *buf, int len)
- {
- EM_ASM({
- var name = new TextDecoder("utf-8").decode(new Uint8Array(Module.HEAPU8.buffer,$0,$1));
- var data = new TextDecoder("utf-8").decode(new Uint8Array(Module.HEAPU8.buffer,$2,$3));
- localStorage.setItem("MEG-4/"+name, data);
- }, cfg, strlen(cfg), buf, len);
- return 1;
- }
- /**
- * Load a config file
- */
- uint8_t *main_cfgload(char *cfg, int *len)
- {
- uint8_t *buf = EM_ASM_PTR({
- var name = new TextDecoder("utf-8").decode(new Uint8Array(Module.HEAPU8.buffer,$0,$1));
- var data = localStorage.getItem("MEG-4/"+name);
- if(data != undefined) {
- const buf = Module._malloc(data.length + 1);
- Module.HEAPU8.set(new TextEncoder("utf-8").encode(data + String.fromCharCode(0)), buf);
- return buf;
- }
- return 0;
- }, cfg, strlen(cfg));
- if(buf) *len = strlen((const char*)buf);
- return buf;
- }
- #endif
- /**
- * Log messages
- */
- void main_log(int lvl, const char* fmt, ...)
- {
- __builtin_va_list args;
- __builtin_va_start(args, fmt);
- if(verbose >= lvl) { printf("meg4: "); vprintf(fmt, args); printf("\r\n"); }
- __builtin_va_end(args);
- }
- /**
- * Parse the command line
- */
- void main_parsecommandline(int argc, char **argv, char **lng, char ***infile)
- {
- int i, j;
- #ifdef __ANDROID__
- char *tmp = SDL_AndroidGetExternalStoragePath();
- main_floppydir = (char*)malloc(strlen(tmp) + 32);
- if(main_floppydir) {
- strcpy(main_floppydir, tmp);
- strcat(main_floppydir, "/../../../../Download/MEG-4");
- mkdir(main_floppydir, 0777);
- }
- #endif
- *infile = NULL;
- for(i = 1; i < argc && argv && argv[i]; i++) {
- if(!memcmp(argv[i], "--help", 6) || !strcmp(argv[i], CLIFLAG "h") || !strcmp(argv[i], CLIFLAG "?")) goto usage;
- if(argv[i][0] == CLIFLAG[0]) {
- for(j = 1; j < 16 && argv[i][j]; j++)
- switch(argv[i][j]) {
- case 'L': if(j == 1 && argv[i + 1]) { *lng = argv[++i]; j = 16; } else goto usage; break;
- case 'd': if(j == 1 && argv[i + 1]) { main_floppydir = argv[++i]; j = 16; } else goto usage; break;
- case 'v': verbose++; break;
- #ifdef DEBUG
- case 's': strace++; break;
- #endif
- #ifndef __WIN32__
- case 'z': zenity++; break;
- #endif
- case 'n': nearest++; break;
- case 'w': windowed++; break;
- default:
- usage: main_hdr();
- printf(" meg4 [" CLIFLAG "L <xx>] "
- #ifndef __WIN32__
- "[" CLIFLAG "z] "
- #endif
- "[" CLIFLAG "n] [" CLIFLAG "w] [" CLIFLAG "v|" CLIFLAG "vv|" CLIFLAG "vvv] "
- #ifdef DEBUG
- "[" CLIFLAG "s]"
- #endif
- #ifndef EMBED
- "["
- #endif
- CLIFLAG "d <dir>"
- #ifndef EMBED
- "]"
- #endif
- " [floppy]\r\n\r\n");
- exit(0);
- break;
- }
- } else
- if(!*infile) *infile = &argv[i];
- }
- #ifdef EMBED
- if(!main_floppydir) goto usage;
- #endif
- if(!*lng) *lng = "en";
- }
|