@@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -48,27 +48,45 @@ /* 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 -exit_cb(int arg1, int arg2, void *arg) +exitCallback(int arg1, int arg2, void *arg) { sceKernelExitGame(); return 0; } static int -callback_thread(SceSize args, void *argp) +threadCallback(SceSize args, void *argp) { sceKernelRegisterExitCallback( - sceKernelCreateCallback("Exit Callback", exit_cb, NULL)); + sceKernelCreateCallback("Exit Callback", exitCallback, NULL)); sceKernelSleepThreadCB(); return 0; } #endif @@ -83,14 +101,14 @@ #if defined(OF_OBJFW_RUNTIME) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS) /* * This does not work on Win32 if ObjFW is built as a DLL. * * On AmigaOS, some destructors need to be able to send messages. - * Calling objc_exit() via atexit() would result in the runtime being + * Calling objc_deinit() via atexit() would result in the runtime being * destructed before for the destructors ran. */ - atexit(objc_exit); + atexit(objc_deinit); #endif /* We need deterministic hashes for tests */ OFHashSeed = 0; @@ -120,11 +138,11 @@ pspDebugScreenInit(); sceCtrlSetSamplingCycle(0); sceCtrlSetSamplingMode(PSP_CTRL_MODE_DIGITAL); - if ((tid = sceKernelCreateThread("update_thread", callback_thread, + if ((tid = sceKernelCreateThread("update_thread", threadCallback, 0x11, 0xFA0, 0, 0)) >= 0) sceKernelStartThread(tid, 0, 0); #endif #ifdef OF_NINTENDO_DS @@ -136,12 +154,23 @@ atexit(gfxExit); consoleInit(GFX_TOP, NULL); #endif -#if defined(OF_WII) || defined(OF_PSP) || defined(OF_NINTENDO_DS) || \ - defined(OF_NINTENDO_3DS) +#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_WII_U) || defined(OF_PSP) || \ + defined(OF_NINTENDO_DS) || 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 +217,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 @@ -198,99 +233,120 @@ return OFApplicationMain(&argc, &argv, [[TestsAppDelegate alloc] init]); #endif } @implementation TestsAppDelegate -- (void)outputTesting: (OFString *)test - inModule: (OFString *)module +- (void)outputTesting: (OFString *)test inModule: (OFString *)module { 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 +- (void)outputSuccess: (OFString *)test inModule: (OFString *)module { if (OFStdOut.hasTerminal) { [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 +- (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) @@ -332,23 +388,23 @@ [self setTests]; [self dateTests]; [self valueTests]; [self numberTests]; [self streamTests]; -#ifdef OF_HAVE_FILES + [self memoryStreamTests]; + [self notificationCenterTests]; [self MD5HashTests]; [self RIPEMD160HashTests]; [self SHA1HashTests]; [self SHA224HashTests]; [self SHA256HashTests]; [self SHA384HashTests]; [self SHA512HashTests]; [self HMACTests]; -#endif [self PBKDF2Tests]; [self scryptTests]; -#if defined(OF_HAVE_FILES) && defined(HAVE_CODEPAGE_437) +#ifdef HAVE_CODEPAGE_437 [self INIFileTests]; #endif #ifdef OF_HAVE_SOCKETS [self socketTests]; [self TCPSocketTests]; @@ -356,10 +412,14 @@ # ifdef OF_HAVE_IPX [self IPXSocketTests]; [self SPXSocketTests]; [self SPXStreamSocketTests]; # endif +# ifdef OF_HAVE_UNIX_SOCKETS + [self UNIXDatagramSocketTests]; + [self UNIXStreamSocketTests]; +# endif [self kernelEventObserverTests]; #endif #ifdef OF_HAVE_THREADS [self threadTests]; #endif @@ -372,13 +432,11 @@ [self HTTPCookieManagerTests]; #endif [self XMLParserTests]; [self XMLNodeTests]; [self XMLElementBuilderTests]; -#ifdef OF_HAVE_FILES [self serializationTests]; -#endif [self JSONTests]; [self propertyListTests]; [self ASN1DERParsingTests]; [self ASN1DERRepresentationTests]; #if defined(OF_HAVE_PLUGINS) @@ -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