ObjFW  Check-in [e10048ac32]

Overview
Comment:Merge trunk into branch "wii-u"
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | wii-u
Files: files | file ages | folders
SHA3-256: e10048ac32b8c2e2b2802204afdc6ddd3e7c91b725032c00baa5b2b8f29e1791
User & Date: js on 2022-07-31 14:16:57
Other Links: branch diff | manifest | tags
Context
2022-07-31
14:27
Fix accidental renames that happened during merge check-in: 15ab5fb29d user: js tags: wii-u
14:16
Merge trunk into branch "wii-u" check-in: e10048ac32 user: js tags: wii-u
14:15
configure: Add missing OBJFW_CPPFLAGS for Switch check-in: 5b6a00a277 user: js tags: trunk
2022-07-17
19:18
objfw-defs.h.in: Add OF_WII_U check-in: db3bb8bff0 user: js tags: wii-u
Changes

Modified .fossil-settings/clean-glob from [0c0ff942fb] to [fba2645b54].

40
41
42
43
44
45
46

47
48
49
50
51
40
41
42
43
44
45
46
47
48
49
50
51
52







+





tests/objc_sync/objc_sync
tests/plugin/Info.plist
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

Modified .fossil-settings/ignore-glob from [13af81fd69] to [a8ddbc70d8].

45
46
47
48
49
50
51

52
53
54
55
56
45
46
47
48
49
50
51
52
53
54
55
56
57







+





tests/objc_sync/objc_sync
tests/plugin/Info.plist
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

Modified .gitignore from [fdb1296647] to [30dcd26802].

45
46
47
48
49
50
51

52
53
54
55
56
45
46
47
48
49
50
51
52
53
54
55
56
57







+





tests/objc_sync/objc_sync
tests/plugin/Info.plist
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

Modified PLATFORMS.md from [aaef200c73] to [7b300be94c].

150
151
152
153
154
155
156











157
158
159
160
161
162
163
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174







+
+
+
+
+
+
+
+
+
+
+








  * Architectures: ARM (EABI)
  * 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
  * Architectures: MIPS64, PA-RISC, PowerPC, SPARC64, x86_64
  * Compilers: GCC 6.3.0, Clang 4.0

Modified configure.ac from [5a6b4fb150] to [2ca10c3d8d].

263
264
265
266
267
268
269
























270
271
272
273
274
275
276
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







	with_tls="no"
	check_pedantic="no"

	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"
OBJCFLAGS="$OBJCFLAGS -Wall $flags"
OBJFW_OBJCFLAGS="$OBJFW_OBJCFLAGS $flags"

Modified src/OFDNSResolverSettings.m from [94502fce5f] to [a43cd003ad].

62
63
64
65
66
67
68




69
70
71
72
73
74
75
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79







+
+
+
+







#elif defined(OF_AMIGAOS)
# define HOSTS_PATH @"AmiTCP:db/hosts"
# 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)
{
	OFString *ret;

98
99
100
101
102
103
104
105

106
107

108
109
110
111
112
113
114
102
103
104
105
106
107
108

109
110

111
112
113
114
115
116
117
118







-
+

-
+







}
#endif

#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]];
}
#endif

Modified src/OFFile.m from [0786a18c44] to [6bda5c55f7].

44
45
46
47
48
49
50





51
52
53
54
55
56
57
58
59
60
61
62
63




64
65
66
67
68
69
70
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65



66
67
68
69
70
71
72
73
74
75
76







+
+
+
+
+










-
-
-
+
+
+
+







#import "OFReadFailedException.h"
#import "OFSeekFailedException.h"
#import "OFWriteFailedException.h"

#ifdef OF_WINDOWS
# include <windows.h>
#endif

#ifdef OF_AMIGAOS
# include <proto/exec.h>
# include <proto/dos.h>
#endif

#ifdef OF_WII
# include <fat.h>
#endif

#ifdef OF_NINTENDO_DS
# include <stdbool.h>
# include <filesystem.h>
#endif

#ifdef OF_AMIGAOS
# include <proto/exec.h>
# include <proto/dos.h>
#ifdef OF_NINTENDO_SWITCH
# define id nx_id
# include <switch.h>
# undef id
#endif

#ifndef O_BINARY
# define O_BINARY 0
#endif
#ifndef O_CLOEXEC
# define O_CLOEXEC 0
180
181
182
183
184
185
186









187
188
189
190
191
192
193
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208







+
+
+
+
+
+
+
+
+







#endif

#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];
}

Modified src/OFSocket.m from [8f11763ca5] to [16116f3ca3].

52
53
54
55
56
57
58






59
60
61
62
63
64
65
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71







+
+
+
+
+
+







# include <proto/exec.h>
#endif

#ifdef OF_NINTENDO_3DS
# include <3ds/types.h>
# include <3ds/services/soc.h>
#endif

#ifdef OF_NINTENDO_SWITCH
# define id nx_id
# include <switch.h>
# undef id
#endif

#if defined(OF_HAVE_THREADS) && (!defined(OF_AMIGAOS) || defined(OF_MORPHOS))
static OFMutex *mutex;

static void
releaseMutex(void)
{
126
127
128
129
130
131
132





133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148





149
150
151
152
153
154
155







+
+
+
+
+





-
-
-
-
-







	if ((ctx = memalign(0x1000, 0x100000)) == NULL)
		return;

	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;
}

OF_DESTRUCTOR()
{

Modified src/OFString+PathAdditions.m from [422d7384b5] to [dfeb40c068].

17
18
19
20
21
22
23
24


25
26
27
28
17
18
19
20
21
22
23

24
25
26
27
28
29







-
+
+





#include "platform.h"

#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

Modified src/OFSystemInfo.m from [2ea5196f61] to [ae514f74f6].

36
37
38
39
40
41
42






43
44
45
46
47
48
49
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55







+
+
+
+
+
+







#endif

#if defined(OF_AMIGAOS4)
# include <exec/exectags.h>
#elif defined(OF_MORPHOS)
# include <exec/system.h>
#endif

#ifdef OF_NINTENDO_SWITCH
# define id nx_id
# import <switch.h>
# undef nx_id
#endif

#import "OFSystemInfo.h"
#import "OFApplication.h"
#import "OFArray.h"
#import "OFDictionary.h"
#import "OFLocale.h"
#import "OFOnce.h"
231
232
233
234
235
236
237











238
239
240
241
242
243
244
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261







+
+
+
+
+
+
+
+
+
+
+







		return;

	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)
{
	struct X86Regs regs;

564
565
566
567
568
569
570





571
572
573
574
575
576
577
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599







+
+
+
+
+







	return [OFString stringWithUTF8String: pathC];
# elif defined(OF_AMIGAOS)
	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)
		return path;

Modified src/OFTimer.m from [a9abf62d66] to [6b846b58a6].

677
678
679
680
681
682
683
684

685


686















687
688
689
690
691
692

693
694
695
696
697










698
677
678
679
680
681
682
683

684
685
686
687

688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712


713
714
715
716
717
718
719
720
721
722
723







-
+

+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+






+



-
-
+
+
+
+
+
+
+
+
+
+

		    @"\tInterval: %lf\n"
		    @"\tRepeats: %s\n"
		    @"\tBlock: %@\n"
		    @"\tValid: %s\n"
		    @">",
		    self.class, _fireDate, _interval, (_repeats ? "yes" : "no"),
		    _block, (_valid ? "yes" : "no")];
	else
	else {
#endif
		void *pool = objc_autoreleasePoolPush();
		OFString *objects = @"", *ret;
		return [OFString stringWithFormat:

		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

Modified src/objfw-defs.h.in from [2eb2b431d4] to [8f5a561d98].

39
40
41
42
43
44
45

46
47
48
49
50
39
40
41
42
43
44
45
46
47
48
49
50
51







+





#undef OF_HAVE_THREADS
#undef OF_HAVE_UNICODE_TABLES
#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

Modified src/tls/OFOpenSSLTLSStream.m from [f8706b398d] to [faf6205c5a].

188
189
190
191
192
193
194
195

196
197
198
199
200
201
202
188
189
190
191
192
193
194

195
196
197
198
199
200
201
202







-
+







	}

	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;
}

- (void)asyncPerformClientHandshakeWithHost: (OFString *)host
				runLoopMode: (OFRunLoopMode)runLoopMode

Modified tests/Makefile from [4aacff62b2] to [d685186721].

1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18










+







include ../extra.mk

SUBDIRS = ${TESTPLUGIN}	\
	  ${OBJC_SYNC}	\
	  terminal

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}
SRCS = ForwardingTests.m		\
       OFArrayTests.m			\
191
192
193
194
195
196
197



198
199
200
201
202


203
204
205
206

207
208

209
210








211
212
213
214
215
216
217
218
219
192
193
194
195
196
197
198
199
200
201
202
203
204
205

206
207
208
209
210

211
212
213
214


215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231







+
+
+




-
+
+



-
+


+
-
-
+
+
+
+
+
+
+
+









	psp-strip ${PROG_NOINST}
	pack-pbp $@ PARAM.SFO NULL NULL NULL NULL NULL ${PROG_NOINST} NULL

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}.nro: ${PROG_NOINST} testfile.bin testfile.txt testfile.ini
${PROG_NOINST}.3dsx: ${PROG_NOINST}
	3dsxtool $< $@
${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}

Modified tests/OFStringTests.m from [7a4f20e376] to [9b77bee5fe].

560
561
562
563
564
565
566
567


568
569
570
571
572
573
574
560
561
562
563
564
565
566

567
568
569
570
571
572
573
574
575







-
+
+







	TEST(@"-[isAbsolutePath]",
	    C(@"C:\\foo").absolutePath && C(@"a:/foo").absolutePath &&
	    !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]",
	    C(@"/foo").absolutePath && C(@"/foo/bar").absolutePath &&
	    !C(@"foo/bar").absolutePath && !C(@"foo").absolutePath)
726
727
728
729
730
731
732
733


734
735
736
737
738
739
740
727
728
729
730
731
732
733

734
735
736
737
738
739
740
741
742







-
+
+







	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"foo", @"bar", @"baz", nil]] isEqual: @"foo/bar/baz"] &&
	    [[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]]
	    isEqual: @"sdmc:/foo/bar/baz"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
850
851
852
853
854
855
856
857


858
859
860
861
862
863
864
852
853
854
855
856
857
858

859
860
861
862
863
864
865
866
867







-
+
+







	    [[array objectAtIndex: 1] isEqual: @"bar"] &&
	    [[array objectAtIndex: 2] isEqual: @"baz"] &&
	    /* 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"] &&
	    /* sdmc:/ */
	    (array = C(@"sdmc:/").pathComponents) && array.count == 1 &&
931
932
933
934
935
936
937
938


939
940
941
942
943
944
945
934
935
936
937
938
939
940

941
942
943
944
945
946
947
948
949







-
+
+







	    [C(@"dh0:tmp").lastPathComponent isEqual: @"tmp"] &&
	    [C(@"dh0:tmp/").lastPathComponent isEqual: @"tmp"] &&
	    [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:"] &&
	    [C(@"foo").lastPathComponent isEqual: @"foo"] &&
	    [C(@"foo/bar").lastPathComponent isEqual: @"bar"] &&
997
998
999
1000
1001
1002
1003
1004


1005
1006
1007
1008
1009
1010
1011
1001
1002
1003
1004
1005
1006
1007

1008
1009
1010
1011
1012
1013
1014
1015
1016







-
+
+







	    [C(@"dh0:tmp/").stringByDeletingLastPathComponent
	    isEqual: @"dh0:"] &&
	    [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
	    isEqual: @"sdmc:/"] &&
	    [C(@"foo/bar").stringByDeletingLastPathComponent isEqual: @"foo"] &&
1044
1045
1046
1047
1048
1049
1050
1051


1052
1053
1054
1055
1056
1057
1058
1049
1050
1051
1052
1053
1054
1055

1056
1057
1058
1059
1060
1061
1062
1063
1064







-
+
+







	    [C(@"dh0:foo./bar.baz").stringByDeletingPathExtension
	    isEqual: @"dh0:foo./bar"] &&
	    [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"] &&
	    [C(@"sdmc:/foo./bar.baz").stringByDeletingPathExtension
	    isEqual: @"sdmc:/foo./bar"] &&

Modified tests/TestsAppDelegate.m from [e90fb7f104] to [a6eba3166b].

46
47
48
49
50
51
52


















53
54
55
56
57
58
59
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+








#ifdef OF_NINTENDO_3DS
/* 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 <switch.h>
# 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
exitCallback(int arg1, int arg2, void *arg)
{
133
134
135
136
137
138
139
140










141
142

143
144
145
146
147
148
149
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169

170
171
172
173
174
175
176
177








+
+
+
+
+
+
+
+
+
+

-
+








#ifdef OF_NINTENDO_3DS
	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:
		    @"\nRuntime error: Unhandled exception:\n%@\n", e];
		OFString *backtrace = [OFString stringWithFormat:
186
187
188
189
190
191
192






193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209




210
211
212
213
214
215
216
217
218
219




220
221
222
223
224
225
226
227


228
229
230
231


232
233
234


235
236
237


238
239
240


241
242
243
244


245
246
247


248
249
250
251
252
253
254
255
256
257









258
259
260
261


262
263
264
265
266
267
268






269
270
271
272


273
274
275


276
277
278


279
280
281


282



283












284
285
286
287
288

289
290
291
292
293
294
295
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273


274
275
276


277
278
279


280
281
282


283
284
285
286


287
288
289


290
291
292









293
294
295
296
297
298
299
300
301
302
303


304
305
306






307
308
309
310
311
312
313
314


315
316
317


318
319
320


321
322
323


324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345


346
347
348
349
350
351
352
353







+
+
+
+
+
+

















+
+
+
+










+
+
+
+








+
+


-
-
+
+

-
-
+
+

-
-
+
+

-
-
+
+


-
-
+
+

-
-
+
+

-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+


-
-
+
+

-
-
-
-
-
-
+
+
+
+
+
+


-
-
+
+

-
-
+
+

-
-
+
+

-
-
+
+

+
+
+

+
+
+
+
+
+
+
+
+
+
+
+



-
-
+







			hidScanInput();

			if (hidKeysDown() & KEY_START)
				[OFApplication terminateWithStatus: 1];

			gspWaitForVBlank();
		}
# elif defined(OF_NINTENDO_SWITCH)
		while (appletMainLoop())
			updateConsole(true);

		consoleExit(NULL);
		abort();
# else
		abort();
# endif
	}
#else
	return OFApplicationMain(&argc, &argv, [[TestsAppDelegate alloc] init]);
#endif
}

@implementation TestsAppDelegate
- (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
{
	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
{
	if (OFStdOut.hasTerminal) {
		[OFStdOut setForegroundColor: [OFColor red]];
		[OFStdOut eraseLine];
		[OFStdOut writeFormat: @"\r[%@] %@: failed\n", module, test];
	} else
		[OFStdOut writeLine: @"failed"];

#ifdef OF_WII
		[OFStdOut reset];
		[OFStdOut writeLine: @"Press A to continue!"];
	[OFStdOut reset];
	[OFStdOut writeLine: @"Press A to continue!"];

		for (;;) {
			WPAD_ScanPads();
	for (;;) {
		WPAD_ScanPads();

			if (WPAD_ButtonsDown(0) & WPAD_BUTTON_A)
				return;
		if (WPAD_ButtonsDown(0) & WPAD_BUTTON_A)
			return;

			VIDEO_WaitVSync();
		}
		VIDEO_WaitVSync();
	}
#endif
#ifdef OF_PSP
		[OFStdOut reset];
		[OFStdOut writeLine: @"Press X to continue!"];
	[OFStdOut reset];
	[OFStdOut writeLine: @"Press X to continue!"];

		for (;;) {
			SceCtrlData pad;
	for (;;) {
		SceCtrlData pad;

			sceCtrlReadBufferPositive(&pad, 1);
			if (pad.Buttons & PSP_CTRL_CROSS) {
				for (;;) {
					sceCtrlReadBufferPositive(&pad, 1);
					if (!(pad.Buttons & PSP_CTRL_CROSS))
						return;
				}
			}
		}
		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!"];
	[OFStdOut reset];
	[OFStdOut writeString: @"Press A to continue!"];

		for (;;) {
			swiWaitForVBlank();
			scanKeys();
			if (keysDown() & KEY_A)
				break;
		}
	for (;;) {
		swiWaitForVBlank();
		scanKeys();
		if (keysDown() & KEY_A)
			break;
	}
#endif
#ifdef OF_NINTENDO_3DS
		[OFStdOut reset];
		[OFStdOut writeString: @"Press A to continue!"];
	[OFStdOut reset];
	[OFStdOut writeString: @"Press A to continue!"];

		for (;;) {
			hidScanInput();
	for (;;) {
		hidScanInput();

			if (hidKeysDown() & KEY_A)
				break;
		if (hidKeysDown() & KEY_A)
			break;

			gspWaitForVBlank();
		}
		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)
	CFBundleRef mainBundle = CFBundleGetMainBundle();
	CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle);
430
431
432
433
434
435
436







437
438
439
440
441
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506







+
+
+
+
+
+
+





		hidScanInput();

		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