Index: .fossil-settings/clean-glob ================================================================== --- .fossil-settings/clean-glob +++ .fossil-settings/clean-glob @@ -42,10 +42,11 @@ tests/terminal/terminal_tests tests/tests tests/tests.3dsx tests/tests.arm9 tests/tests.nds +tests/tests.nro utils/objfw-config utils/ofarc/ofarc utils/ofdns/ofdns utils/ofhash/ofhash utils/ofhttp/ofhttp Index: .fossil-settings/ignore-glob ================================================================== --- .fossil-settings/ignore-glob +++ .fossil-settings/ignore-glob @@ -47,10 +47,11 @@ tests/terminal/terminal_tests tests/tests tests/tests.3dsx tests/tests.arm9 tests/tests.nds +tests/tests.nro utils/objfw-config utils/ofarc/ofarc utils/ofdns/ofdns utils/ofhash/ofhash utils/ofhttp/ofhttp Index: .gitignore ================================================================== --- .gitignore +++ .gitignore @@ -47,10 +47,11 @@ tests/terminal/terminal_tests tests/tests tests/tests.3dsx tests/tests.arm9 tests/tests.nds +tests/tests.nro utils/objfw-config utils/ofarc/ofarc utils/ofdns/ofdns utils/ofhash/ofhash utils/ofhttp/ofhttp Index: PLATFORMS.md ================================================================== --- PLATFORMS.md +++ PLATFORMS.md @@ -152,10 +152,21 @@ * Compilers: GCC 4.8.2 (devkitARM release 42) * Runtimes: ObjFW * Limitations: No threads, no sockets * Notes: File support requires an argv-compatible launcher (such as HBMenu) + +Nintendo Switch +--------------- + + * OS Versions: yuzu 1093 + * Architectures: AArch64 + * Compilers: GCC 12.1.0 (devkitA64 release 19) + * Runtimes: ObjFW + * Limitations: No threads, no sockets, no shared libraries, not tested on + real hardware + OpenBSD ------- * OS Versions: 5.2-6.7 Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -265,10 +265,34 @@ AC_DEFINE(OF_NINTENDO_3DS, 1, [Whether we are compiling for Nintendo 3DS]) AC_SUBST(MAP_LDFLAGS, ['-Wl,-Map,$@.map']) ]) + +AC_ARG_WITH(nintendo-switch, + AS_HELP_STRING([--with-nintendo-switch], [build for Nintendo Switch])) +AS_IF([test x"$with_nintendo_switch" = x"yes"], [ + AS_IF([test x"$DEVKITPRO" = x""], [ + AC_MSG_ERROR([DEVKITPRO is not set! Please set DEVKITPRO.]) + ]) + + flags="-march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE" + OBJCFLAGS="$OBJCFLAGS $flags" + OBJFW_OBJCFLAGS="$OBJFW_OBJCFLAGS $flags" + CPPFLAGS="$CPPFLAGS -D__SWITCH__ -I$DEVKITPRO/libnx/include" + OBJFW_CPPFLAGS="$OBJFW_CPPFLAGS -D__SWITCH__ -I$DEVKITPRO/libnx/include" + ASFLAGS="$ASFLAGS $flags" + LDFLAGS="$LDFLAGS -specs=$DEVKITPRO/libnx/switch.specs $flags" + LIBS="$LIBS -L$DEVKITPRO/libnx/lib -lnx" + enable_shared="no" + enable_threads="no" # TODO + enable_sockets="no" # TODO + check_pedantic="no" + + AC_DEFINE(OF_NINTENDO_SWITCH, 1, + [Whether we are compiling for Nintendo Switch]) +]) CPP="$OBJCPP" CPPFLAGS="$CPPFLAGS $OBJCPPFLAGS -DOF_COMPILING_OBJFW" flags="-fexceptions -fobjc-exceptions -funwind-tables" flags="$flags -fconstant-string-class=OFConstantString" Index: src/OFDNSResolverSettings.m ================================================================== --- src/OFDNSResolverSettings.m +++ src/OFDNSResolverSettings.m @@ -64,10 +64,14 @@ # define RESOLV_CONF_PATH @"AmiTCP:db/resolv.conf" #else # define HOSTS_PATH @"/etc/hosts" # define RESOLV_CONF_PATH @"/etc/resolv.conf" #endif + +#ifndef HOST_NAME_MAX +# define HOST_NAME_MAX 255 +#endif #ifndef OF_WII static OFString * domainFromHostname(OFString *hostname) { @@ -100,13 +104,13 @@ #if !defined(OF_WII) && !defined(OF_MORPHOS) static OFString * obtainHostname(void) { - char hostname[256]; + char hostname[HOST_NAME_MAX + 1]; - if (gethostname(hostname, 256) != 0) + if (gethostname(hostname, HOST_NAME_MAX + 1) != 0) return nil; return [OFString stringWithCString: hostname encoding: [OFLocale encoding]]; } Index: src/OFFile.m ================================================================== --- src/OFFile.m +++ src/OFFile.m @@ -46,10 +46,15 @@ #import "OFWriteFailedException.h" #ifdef OF_WINDOWS # include #endif + +#ifdef OF_AMIGAOS +# include +# include +#endif #ifdef OF_WII # include #endif @@ -56,13 +61,14 @@ #ifdef OF_NINTENDO_DS # include # include #endif -#ifdef OF_AMIGAOS -# include -# include +#ifdef OF_NINTENDO_SWITCH +# define id nx_id +# include +# undef id #endif #ifndef O_BINARY # define O_BINARY 0 #endif @@ -182,10 +188,19 @@ #ifdef OF_NINTENDO_DS if (!nitroFSInit(NULL)) @throw [OFInitializationFailedException exceptionWithClass: self]; #endif + +#ifdef OF_NINTENDO_SWITCH + if (R_SUCCEEDED(romfsInit())) + /* + * Errors are intentionally ignored, as it's possible we just + * have no romfs. + */ + atexit((void (*)(void))romfsExit); +#endif } + (instancetype)fileWithPath: (OFString *)path mode: (OFString *)mode { return [[[self alloc] initWithPath: path mode: mode] autorelease]; Index: src/OFSocket.m ================================================================== --- src/OFSocket.m +++ src/OFSocket.m @@ -54,10 +54,16 @@ #ifdef OF_NINTENDO_3DS # include <3ds/types.h> # include <3ds/services/soc.h> #endif + +#ifdef OF_NINTENDO_SWITCH +# define id nx_id +# include +# undef id +#endif #if defined(OF_HAVE_THREADS) && (!defined(OF_AMIGAOS) || defined(OF_MORPHOS)) static OFMutex *mutex; static void @@ -128,20 +134,20 @@ if (socInit(ctx, 0x100000) != 0) return; atexit((void (*)(void))socExit); +# elif defined(OF_NINTENDO_SWITCH) + if (R_FAILED(socketInitializeDefault())) + return; + + atexit(socketExit); # endif # if defined(OF_HAVE_THREADS) && (!defined(OF_AMIGAOS) || defined(OF_MORPHOS)) mutex = [[OFMutex alloc] init]; atexit(releaseMutex); - -# ifdef OF_WII - if (OFSpinlockNew(&spinlock) != 0) - return; -# endif # endif initSuccessful = true; } Index: src/OFString+PathAdditions.m ================================================================== --- src/OFString+PathAdditions.m +++ src/OFString+PathAdditions.m @@ -19,10 +19,11 @@ #if defined(OF_WINDOWS) || defined(OF_MSDOS) || defined(OF_MINT) # import "platform/Windows/OFString+PathAdditions.m" #elif defined(OF_AMIGAOS) # import "platform/AmigaOS/OFString+PathAdditions.m" -#elif defined(OF_NINTENDO_3DS) || defined(OF_WII) +#elif defined(OF_NINTENDO_3DS) || defined(OF_WII) || \ + defined(OF_NINTENDO_SWITCH) # import "platform/libfat/OFString+PathAdditions.m" #else # import "platform/POSIX/OFString+PathAdditions.m" #endif Index: src/OFSystemInfo.m ================================================================== --- src/OFSystemInfo.m +++ src/OFSystemInfo.m @@ -38,10 +38,16 @@ #if defined(OF_AMIGAOS4) # include #elif defined(OF_MORPHOS) # include #endif + +#ifdef OF_NINTENDO_SWITCH +# define id nx_id +# import +# undef nx_id +#endif #import "OFSystemInfo.h" #import "OFApplication.h" #import "OFArray.h" #import "OFDictionary.h" @@ -233,10 +239,21 @@ operatingSystemVersion = [[OFString alloc] initWithCString: utsname.release encoding: [OFLocale encoding]]; #endif } + +#ifdef OF_NINTENDO_SWITCH +static OFString *tmpFSPath = nil; + +static void +mountTmpFS(void) +{ + if (R_SUCCEEDED(fsdevMountTemporaryStorage("tmpfs"))) + tmpFSPath = @"tmpfs:/"; +} +#endif #if defined(OF_X86_64) || defined(OF_X86) static OF_INLINE struct X86Regs OF_CONST_FUNC x86CPUID(uint32_t eax, uint32_t ecx) { @@ -566,10 +583,15 @@ return @"T:"; # elif defined(OF_MSDOS) return [[OFApplication environment] objectForKey: @"TEMP"]; # elif defined(OF_MINT) return @"u:\\tmp"; +# elif defined(OF_NINTENDO_SWITCH) + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, mountTmpFS); + + return tmpFSPath; # else OFString *path = [[OFApplication environment] objectForKey: @"XDG_RUNTIME_DIR"]; if (path != nil) Index: src/OFTimer.m ================================================================== --- src/OFTimer.m +++ src/OFTimer.m @@ -679,20 +679,45 @@ @"\tBlock: %@\n" @"\tValid: %s\n" @">", self.class, _fireDate, _interval, (_repeats ? "yes" : "no"), _block, (_valid ? "yes" : "no")]; - else + else { #endif - return [OFString stringWithFormat: + void *pool = objc_autoreleasePoolPush(); + OFString *objects = @"", *ret; + + if (_arguments >= 1) + objects = [objects stringByAppendingFormat: + @"\tObject: %@\n", _object1]; + if (_arguments >= 2) + objects = [objects stringByAppendingFormat: + @"\tObject: %@\n", _object2]; + if (_arguments >= 3) + objects = [objects stringByAppendingFormat: + @"\tObject: %@\n", _object3]; + if (_arguments >= 4) + objects = [objects stringByAppendingFormat: + @"\tObject: %@\n", _object4]; + + ret = [[OFString alloc] initWithFormat: @"<%@:\n" @"\tFire date: %@\n" @"\tInterval: %lf\n" @"\tRepeats: %s\n" @"\tTarget: %@\n" @"\tSelector: %s\n" + @"%@" @"\tValid: %s\n" @">", self.class, _fireDate, _interval, (_repeats ? "yes" : "no"), - _target, sel_getName(_selector), (_valid ? "yes" : "no")]; + _target, sel_getName(_selector), objects, + (_valid ? "yes" : "no")]; + + objc_autoreleasePoolPop(pool); + + return [ret autorelease]; +#ifdef OF_HAVE_BLOCKS + } +#endif } @end Index: src/objfw-defs.h.in ================================================================== --- src/objfw-defs.h.in +++ src/objfw-defs.h.in @@ -41,10 +41,11 @@ #undef OF_HAVE_UNIX_SOCKETS #undef OF_HAVE__THREAD_LOCAL #undef OF_HAVE___THREAD #undef OF_NINTENDO_3DS #undef OF_NINTENDO_DS +#undef OF_NINTENDO_SWITCH #undef OF_NO_SHARED #undef OF_OBJFW_RUNTIME #undef OF_UNIVERSAL #undef OF_WII #undef OF_WII_U Index: src/tls/OFOpenSSLTLSStream.m ================================================================== --- src/tls/OFOpenSSLTLSStream.m +++ src/tls/OFOpenSSLTLSStream.m @@ -190,11 +190,11 @@ return bytesWritten; } - (bool)hasDataInReadBuffer { - if (SSL_has_pending(_SSL) || BIO_ctrl_pending(_readBIO) > 0) + if (SSL_pending(_SSL) > 0 || BIO_ctrl_pending(_readBIO) > 0) return true; return super.hasDataInReadBuffer; } Index: tests/Makefile ================================================================== --- tests/Makefile +++ tests/Makefile @@ -6,10 +6,11 @@ CLEAN = EBOOT.PBP \ boot.dol \ ${PROG_NOINST}.arm9 \ ${PROG_NOINST}.nds \ + ${PROG_NOINST}.nro \ ${PROG_NOINST}.rpx DISTCLEAN = Info.plist PROG_NOINST = tests${PROG_SUFFIX} STATIC_LIB_NOINST = ${TESTS_STATIC_LIB} @@ -193,27 +194,38 @@ boot.dol: ${PROG_NOINST} elf2dol ${PROG_NOINST} $@ ${PROG_NOINST}: ${LIBOBJFW_DEP} ${LIBOBJFWRT_DEP} + +${PROG_NOINST}.3dsx: ${PROG_NOINST} + 3dsxtool $< $@ ${PROG_NOINST}.arm9: ${PROG_NOINST} arm-none-eabi-objcopy -O binary $< $@ -${PROG_NOINST}.nds: ${PROG_NOINST}.arm9 +${PROG_NOINST}.nds: ${PROG_NOINST}.arm9 testfile.bin testfile.txt testfile.ini +${PROG_NOINST}.nds: serialization.xml rm -fr nds-data mkdir -p nds-data cp testfile.bin testfile.txt testfile.ini serialization.xml nds-data - ndstool -c $@ -9 $< -d nds-data + ndstool -c $@ -9 ${PROG_NOINST} -d nds-data rm -fr nds-data -${PROG_NOINST}.3dsx: ${PROG_NOINST} - 3dsxtool $< $@ +${PROG_NOINST}.nro: ${PROG_NOINST} testfile.bin testfile.txt testfile.ini +${PROG_NOINST}.nro: serialization.xml + rm -fr romfs + mkdir -p romfs + cp testfile.bin testfile.txt testfile.ini serialization.xml romfs + nacptool --create "ObjFW tests" "Jonathan Schleifer" \ + "${PACKAGE_VERSION}" tests.nacp + elf2nro ${PROG_NOINST} $@ --nacp=tests.nacp --romfsdir=romfs + rm -fr romfs tests.nacp ${PROG_NOINST}.rpx: ${PROG_NOINST} elf2rpl $< $@ CPPFLAGS += -I../src -I../src/exceptions -I../src/runtime -I.. -DSTDOUT OBJCFLAGS_RuntimeARCTests.m = -fobjc-arc -fobjc-arc-exceptions LIBS := ${TESTS_LIBS} ${LIBS} LDFLAGS += ${MAP_LDFLAGS} LD = ${OBJC} Index: tests/OFStringTests.m ================================================================== --- tests/OFStringTests.m +++ tests/OFStringTests.m @@ -562,11 +562,12 @@ !C(@"foo").absolutePath && !C(@"b:foo").absolutePath) # elif defined(OF_AMIGAOS) TEST(@"-[isAbsolutePath]", C(@"dh0:foo").absolutePath && C(@"dh0:a/b").absolutePath && !C(@"foo/bar").absolutePath && !C(@"foo").absolutePath) -# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) +# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) || \ + defined(OF_NINTENDO_SWITCH) TEST(@"-[isAbsolutePath]", C(@"sdmc:/foo").absolutePath && !C(@"sdmc:foo").absolutePath && !C(@"foo/bar").absolutePath && !C(@"foo").absolutePath) # else TEST(@"-[isAbsolutePath]", @@ -728,11 +729,12 @@ [[stringClass pathWithComponents: [OFArray arrayWithObjects: @"foo/", @"bar", @"", @"baz", @"/", nil]] isEqual: @"foo//bar/baz//"] && [[stringClass pathWithComponents: [OFArray arrayWithObjects: @"foo", nil]] isEqual: @"foo"]) -# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) +# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) || \ + defined(OF_NINTENDO_SWITCH) TEST(@"+[pathWithComponents:]", [[stringClass pathWithComponents: [OFArray arrayWithObjects: @"foo", @"bar", @"baz", nil]] isEqual: @"foo/bar/baz"] && [[stringClass pathWithComponents: [OFArray arrayWithObjects: @"sdmc:", @"foo", @"bar", @"baz", nil]] @@ -852,11 +854,12 @@ /* foo// */ (array = C(@"foo//").pathComponents) && array.count == 2 && [[array objectAtIndex: 0] isEqual: @"foo"] && [[array objectAtIndex: 1] isEqual: @"/"] && C(@"").pathComponents.count == 0) -# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) +# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) || \ + defined(OF_NINTENDO_SWITCH) TEST(@"-[pathComponents]", /* sdmc:/tmp */ (array = C(@"sdmc:/tmp").pathComponents) && array.count == 2 && [[array objectAtIndex: 0] isEqual: @"sdmc:"] && [[array objectAtIndex: 1] isEqual: @"tmp"] && @@ -933,11 +936,12 @@ [C(@"dh0:/").lastPathComponent isEqual: @"/"] && [C(@"dh0:").lastPathComponent isEqual: @"dh0:"] && [C(@"foo").lastPathComponent isEqual: @"foo"] && [C(@"foo/bar").lastPathComponent isEqual: @"bar"] && [C(@"foo/bar/baz/").lastPathComponent isEqual: @"baz"]) -# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) +# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) || \ + defined(OF_NINTENDO_SWITCH) TEST(@"-[lastPathComponent]", [C(@"sdmc:/tmp").lastPathComponent isEqual: @"tmp"] && [C(@"sdmc:/tmp/").lastPathComponent isEqual: @"tmp"] && [C(@"sdmc:/").lastPathComponent isEqual: @"sdmc:/"] && [C(@"sdmc:").lastPathComponent isEqual: @"sdmc:"] && @@ -999,11 +1003,12 @@ [C(@"dh0:/").stringByDeletingLastPathComponent isEqual: @"dh0:"] && [C(@"dh0:tmp/foo/").stringByDeletingLastPathComponent isEqual: @"dh0:tmp"] && [C(@"foo/bar").stringByDeletingLastPathComponent isEqual: @"foo"] && [C(@"foo").stringByDeletingLastPathComponent isEqual: @""]) -# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) +# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) || \ + defined(OF_NINTENDO_SWITCH) TEST(@"-[stringByDeletingLastPathComponent]", [C(@"/tmp/").stringByDeletingLastPathComponent isEqual: @""] && [C(@"sdmc:/tmp/foo/").stringByDeletingLastPathComponent isEqual: @"sdmc:/tmp"] && [C(@"sdmc:/").stringByDeletingLastPathComponent @@ -1046,11 +1051,12 @@ [C(@"foo.bar/").stringByDeletingPathExtension isEqual: @"foo"] && [C(@".foo").stringByDeletingPathExtension isEqual: @".foo"] && [C(@".foo\\bar").stringByDeletingPathExtension isEqual: @".foo\\bar"] && [C(@".foo.bar").stringByDeletingPathExtension isEqual: @".foo"]) -# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) +# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) || \ + defined(OF_NINTENDO_SWITCH) TEST(@"-[stringByDeletingPathExtension]", [C(@"foo.bar").stringByDeletingPathExtension isEqual: @"foo"] && [C(@"foo..bar").stringByDeletingPathExtension isEqual: @"foo."] && [C(@"sdmc:/foo./bar").stringByDeletingPathExtension isEqual: @"sdmc:/foo./bar"] && Index: tests/TestsAppDelegate.m ================================================================== --- tests/TestsAppDelegate.m +++ tests/TestsAppDelegate.m @@ -48,10 +48,28 @@ /* Newer versions of libctru started using id as a parameter name. */ # define id id_3ds # include <3ds.h> # undef id #endif + +#ifdef OF_NINTENDO_SWITCH +# define id nx_id +# include +# undef id + +static OFDate *lastConsoleUpdate; + +static void +updateConsole(bool force) +{ + if (force || lastConsoleUpdate.timeIntervalSinceNow <= -1.0 / 60) { + consoleUpdate(NULL); + [lastConsoleUpdate release]; + lastConsoleUpdate = [[OFDate alloc] init]; + } +} +#endif extern unsigned long OFHashSeed; #ifdef OF_PSP static int @@ -135,13 +153,23 @@ gfxInitDefault(); atexit(gfxExit); consoleInit(GFX_TOP, NULL); #endif + +#ifdef OF_NINTENDO_SWITCH + consoleInit(NULL); + padConfigureInput(1, HidNpadStyleSet_NpadStandard); + updateConsole(true); + +# ifdef OF_HAVE_FILES + [[OFFileManager defaultManager] changeCurrentDirectoryPath: @"romfs:/"]; +# endif +#endif #if defined(OF_WII) || defined(OF_PSP) || defined(OF_NINTENDO_DS) || \ - defined(OF_NINTENDO_3DS) + defined(OF_NINTENDO_3DS) || defined(OF_NINTENDO_SWITCH) @try { return OFApplicationMain(&argc, &argv, [[TestsAppDelegate alloc] init]); } @catch (id e) { OFString *string = [OFString stringWithFormat: @@ -188,10 +216,16 @@ if (hidKeysDown() & KEY_START) [OFApplication terminateWithStatus: 1]; gspWaitForVBlank(); } +# elif defined(OF_NINTENDO_SWITCH) + while (appletMainLoop()) + updateConsole(true); + + consoleExit(NULL); + abort(); # else abort(); # endif } #else @@ -205,10 +239,14 @@ if (OFStdOut.hasTerminal) { [OFStdOut setForegroundColor: [OFColor yellow]]; [OFStdOut writeFormat: @"[%@] %@: testing...", module, test]; } else [OFStdOut writeFormat: @"[%@] %@: ", module, test]; + +#ifdef OF_NINTENDO_SWITCH + updateConsole(false); +#endif } - (void)outputSuccess: (OFString *)test inModule: (OFString *)module { if (OFStdOut.hasTerminal) { @@ -215,79 +253,99 @@ [OFStdOut setForegroundColor: [OFColor lime]]; [OFStdOut eraseLine]; [OFStdOut writeFormat: @"\r[%@] %@: ok\n", module, test]; } else [OFStdOut writeLine: @"ok"]; + +#ifdef OF_NINTENDO_SWITCH + updateConsole(false); +#endif } - (void)outputFailure: (OFString *)test inModule: (OFString *)module { if (OFStdOut.hasTerminal) { [OFStdOut setForegroundColor: [OFColor red]]; [OFStdOut eraseLine]; [OFStdOut writeFormat: @"\r[%@] %@: failed\n", module, test]; - -#ifdef OF_WII - [OFStdOut reset]; - [OFStdOut writeLine: @"Press A to continue!"]; - - for (;;) { - WPAD_ScanPads(); - - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_A) - return; - - VIDEO_WaitVSync(); - } -#endif -#ifdef OF_PSP - [OFStdOut reset]; - [OFStdOut writeLine: @"Press X to continue!"]; - - for (;;) { - SceCtrlData pad; - - sceCtrlReadBufferPositive(&pad, 1); - if (pad.Buttons & PSP_CTRL_CROSS) { - for (;;) { - sceCtrlReadBufferPositive(&pad, 1); - if (!(pad.Buttons & PSP_CTRL_CROSS)) - return; - } - } - } -#endif -#ifdef OF_NINTENDO_DS - [OFStdOut reset]; - [OFStdOut writeString: @"Press A to continue!"]; - - for (;;) { - swiWaitForVBlank(); - scanKeys(); - if (keysDown() & KEY_A) - break; - } -#endif -#ifdef OF_NINTENDO_3DS - [OFStdOut reset]; - [OFStdOut writeString: @"Press A to continue!"]; - - for (;;) { - hidScanInput(); - - if (hidKeysDown() & KEY_A) - break; - - gspWaitForVBlank(); - } -#endif - + } else + [OFStdOut writeLine: @"failed"]; + +#ifdef OF_WII + [OFStdOut reset]; + [OFStdOut writeLine: @"Press A to continue!"]; + + for (;;) { + WPAD_ScanPads(); + + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_A) + return; + + VIDEO_WaitVSync(); + } +#endif +#ifdef OF_PSP + [OFStdOut reset]; + [OFStdOut writeLine: @"Press X to continue!"]; + + for (;;) { + SceCtrlData pad; + + sceCtrlReadBufferPositive(&pad, 1); + if (pad.Buttons & PSP_CTRL_CROSS) { + for (;;) { + sceCtrlReadBufferPositive(&pad, 1); + if (!(pad.Buttons & PSP_CTRL_CROSS)) + return; + } + } + } +#endif +#ifdef OF_NINTENDO_DS + [OFStdOut reset]; + [OFStdOut writeString: @"Press A to continue!"]; + + for (;;) { + swiWaitForVBlank(); + scanKeys(); + if (keysDown() & KEY_A) + break; + } +#endif +#ifdef OF_NINTENDO_3DS + [OFStdOut reset]; + [OFStdOut writeString: @"Press A to continue!"]; + + for (;;) { + hidScanInput(); + + if (hidKeysDown() & KEY_A) + break; + + gspWaitForVBlank(); + } +#endif +#ifdef OF_NINTENDO_SWITCH + [OFStdOut reset]; + [OFStdOut writeString: @"Press A to continue!"]; + + while (appletMainLoop()) { + PadState pad; + + padUpdate(&pad); + updateConsole(true); + + if (padGetButtonsDown(&pad) & HidNpadButton_A) + break; + } +#endif + + if (OFStdOut.hasTerminal) { [OFStdOut writeString: @"\r"]; [OFStdOut reset]; [OFStdOut eraseLine]; - } else - [OFStdOut writeLine: @"failed"]; + } } - (void)applicationDidFinishLaunching { #if defined(OF_IOS) && defined(OF_HAVE_FILES) @@ -432,10 +490,17 @@ if (hidKeysDown() & KEY_START) [OFApplication terminateWithStatus: _fails]; gspWaitForVBlank(); } +#elif defined(OF_NINTENDO_SWITCH) + while (appletMainLoop()) + updateConsole(true); + + consoleExit(NULL); + + [OFApplication terminateWithStatus: _fails]; #else [OFApplication terminateWithStatus: _fails]; #endif } @end