ObjFW  Check-in [a7ce7bb441]

Overview
Comment:Treat the leading slash of a path as a component
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: a7ce7bb44102d696b6ab0051d13dcf8d766e0ba5012d5396efaec35194a9ad55
User & Date: js on 2018-03-13 23:05:56
Other Links: manifest | tags
Context
2018-03-17
21:53
Add +[OFSystemInfo operatingSystem{Name,Version}] check-in: c6ed29d881 user: js tags: trunk
2018-03-13
23:05
Treat the leading slash of a path as a component check-in: a7ce7bb441 user: js tags: trunk
2018-03-11
23:11
OFHTTPClient: Throw if socket got closed too early check-in: 69c2ca803a user: js tags: trunk
Changes

Modified src/OFString+PathAdditions_UNIX.m from [223d3e3c81] to [800379d99e].

23
24
25
26
27
28
29













30




31
32
33
34
35
36
37
#import "OFOutOfRangeException.h"

int _OFString_PathAdditions_reference;

@implementation OFString (PathAdditions)
+ (OFString *)pathWithComponents: (OFArray *)components
{













	return [components componentsJoinedByString: @"/"];




}

- (bool)isAbsolutePath
{
	return [self hasPrefix: @"/"];
}








>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#import "OFOutOfRangeException.h"

int _OFString_PathAdditions_reference;

@implementation OFString (PathAdditions)
+ (OFString *)pathWithComponents: (OFArray *)components
{
	void *pool = objc_autoreleasePoolPush();
	OFString *ret;

	if ([[components firstObject] isEqual: @"/"]) {
		OFMutableArray OF_GENERIC(OFString *) *mutableComponents =
		    [[components mutableCopy] autorelease];

		[mutableComponents replaceObjectAtIndex: 0
					     withObject: @""];

		components = mutableComponents;
	}

	ret = [components componentsJoinedByString: @"/"];

	[ret retain];
	objc_autoreleasePoolPop(pool);
	return [ret autorelease];
}

- (bool)isAbsolutePath
{
	return [self hasPrefix: @"/"];
}

56
57
58
59
60
61
62




63
64
65
66
67
68
69
			    [OFString stringWithUTF8String: cString + last
						    length: i - last]];
			last = i + 1;
		}
	}
	[ret addObject: [OFString stringWithUTF8String: cString + last
						length: i - last]];





	[ret makeImmutable];

	objc_autoreleasePoolPop(pool);

	return ret;
}







>
>
>
>







73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
			    [OFString stringWithUTF8String: cString + last
						    length: i - last]];
			last = i + 1;
		}
	}
	[ret addObject: [OFString stringWithUTF8String: cString + last
						length: i - last]];

	if ([[ret firstObject] isEqual: @""])
		[ret replaceObjectAtIndex: 0
			       withObject: @"/"];

	[ret makeImmutable];

	objc_autoreleasePoolPop(pool);

	return ret;
}
208
209
210
211
212
213
214
215
216
217
218
219










220




221
222
223
224
225
226
227
228
229
230
231
	objc_autoreleasePoolPop(pool);
	return [ret autorelease];
}

- (OFString *)stringByStandardizingPath
{
	void *pool = objc_autoreleasePoolPush();
	OFArray OF_GENERIC(OFString *) *components = [self pathComponents];
	OFMutableArray OF_GENERIC(OFString *) *array;
	OFString *ret;
	bool done = false, startsWithEmpty, endsWithEmpty;











	array = [[components mutableCopy] autorelease];





	if ((startsWithEmpty = [[array firstObject] isEqual: @""]))
		[array removeObjectAtIndex: 0];
	endsWithEmpty = [[array lastObject] isEqual: @""];

	while (!done) {
		size_t length = [array count];

		done = true;

		for (size_t i = 0; i < length; i++) {







|

|
|

>
>
>
>
>
>
>
>
>
>

>
>
>
>

|

<







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
	objc_autoreleasePoolPop(pool);
	return [ret autorelease];
}

- (OFString *)stringByStandardizingPath
{
	void *pool = objc_autoreleasePoolPush();
	OFArray OF_GENERIC(OFString *) *components;
	OFMutableArray OF_GENERIC(OFString *) *array;
	OFString *firstComponent, *ret;
	bool done = false, startsWithSlash, endsWithEmpty;

	if ([self length] == 0)
		return @"";

	components = [self pathComponents];

	if ([components count] == 1) {
		objc_autoreleasePoolPop(pool);
		return self;
	}

	array = [[components mutableCopy] autorelease];
	firstComponent = [array firstObject];
	startsWithSlash =
	    ([firstComponent isEqual: @"/"] || [firstComponent length] == 0);
	endsWithEmpty = ([[array lastObject] length] == 0);

	if (startsWithSlash)
		[array removeObjectAtIndex: 0];


	while (!done) {
		size_t length = [array count];

		done = true;

		for (size_t i = 0; i < length; i++) {
248
249
250
251
252
253
254
255
256
257

258
259
260
261
262
263
264

				done = false;
				break;
			}
		}
	}

	if (startsWithEmpty)
		[array insertObject: @""
			    atIndex: 0];

	if (endsWithEmpty)
		[array addObject: @""];

	ret = [[array componentsJoinedByString: @"/"] retain];

	objc_autoreleasePoolPop(pool);








|


>







282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299

				done = false;
				break;
			}
		}
	}

	if (startsWithSlash)
		[array insertObject: @""
			    atIndex: 0];

	if (endsWithEmpty)
		[array addObject: @""];

	ret = [[array componentsJoinedByString: @"/"] retain];

	objc_autoreleasePoolPop(pool);

Modified src/OFURL.m from [6014ddabe8] to [c9e9081959].

962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977

	if ([path hasSuffix: @"/"])
		path = [path substringWithRange:
		    of_range(0, [path length] - 1)];

#if defined(OF_WINDOWS) || defined(OF_MSDOS)
	path = [path substringWithRange: of_range(1, [path length] - 1)];
	path = [OFString pathWithComponents:
	    [path componentsSeparatedByString: @"/"]];
#endif

	[path retain];

	objc_autoreleasePoolPop(pool);

	return [path autorelease];







|
|







962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977

	if ([path hasSuffix: @"/"])
		path = [path substringWithRange:
		    of_range(0, [path length] - 1)];

#if defined(OF_WINDOWS) || defined(OF_MSDOS)
	path = [path substringWithRange: of_range(1, [path length] - 1)];
	path = [path stringByReplacingOccurrencesOfString: @"/"
					       withString: @"\\"];
#endif

	[path retain];

	objc_autoreleasePoolPop(pool);

	return [path autorelease];

Modified tests/OFStringTests.m from [067d094bf5] to [fa776f7eaf].

617
618
619
620
621
622
623
624




625
626
627
628
629
630
631
632
633

634
635
636
637

638
639



























640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663

664
665
666
667
668
669
670
671
672
673
674
675
676
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
				options: OF_STRING_SKIP_EMPTY]) &&
	    [a count] == 3 &&
	    [[a objectAtIndex: i++] isEqual: @"foo"] &&
	    [[a objectAtIndex: i++] isEqual: @"bar"] &&
	    [[a objectAtIndex: i++] isEqual: @"baz"])

#ifdef OF_HAVE_FILES
# if !defined(OF_WINDOWS) && !defined(OF_MSDOS)




#  define EXPECTED @"foo/bar/baz"
# else
#  define EXPECTED @"foo\\bar\\baz"
# endif
	TEST(@"+[pathWithComponents:]",
	    (is = [stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"foo", @"bar", @"baz", nil]]) &&
	    [is isEqual: EXPECTED] &&
	    (is = [stringClass pathWithComponents:

	    [OFArray arrayWithObjects: @"foo", nil]]) &&
	    [is isEqual: @"foo"])
# undef EXPECTED


	TEST(@"-[pathComponents]",
	    /* /tmp */



























	    (a = [C(@"/tmp") pathComponents]) && [a count] == 2 &&
	    [[a objectAtIndex: 0] isEqual: @""] &&
	    [[a objectAtIndex: 1] isEqual: @"tmp"] &&
	    /* /tmp/ */
	    (a = [C(@"/tmp/") pathComponents]) && [a count] == 2 &&
	    [[a objectAtIndex: 0] isEqual: @""] &&
	    [[a objectAtIndex: 1] isEqual: @"tmp"] &&
	    /* / */
	    (a = [C(@"/") pathComponents]) && [a count] == 1 &&
	    [[a objectAtIndex: 0] isEqual: @""] &&
	    /* foo/bar */
	    (a = [C(@"foo/bar") pathComponents]) && [a count] == 2 &&
	    [[a objectAtIndex: 0] isEqual: @"foo"] &&
	    [[a objectAtIndex: 1] isEqual: @"bar"] &&
	    /* foo/bar/baz/ */
	    (a = [C(@"foo/bar/baz") pathComponents]) && [a count] == 3 &&
	    [[a objectAtIndex: 0] isEqual: @"foo"] &&
	    [[a objectAtIndex: 1] isEqual: @"bar"] &&
	    [[a objectAtIndex: 2] isEqual: @"baz"] &&
	    /* foo// */
	    (a = [C(@"foo//") pathComponents]) && [a count] == 2 &&
	    [[a objectAtIndex: 0] isEqual: @"foo"] &&
	    [[a objectAtIndex: 1] isEqual: @""] &&
	    [[C(@"") pathComponents] count] == 0)


#if !defined(OF_WINDOWS) && !defined(OF_MSDOS)
	TEST(@"-[lastPathComponent]",
	    [[C(@"/tmp") lastPathComponent] isEqual: @"tmp"] &&
	    [[C(@"/tmp/") lastPathComponent] isEqual: @"tmp"] &&
	    [[C(@"/") lastPathComponent] isEqual: @"/"] &&
	    [[C(@"foo") lastPathComponent] isEqual: @"foo"] &&
	    [[C(@"foo/bar") lastPathComponent] isEqual: @"bar"] &&
	    [[C(@"foo/bar/baz/") lastPathComponent] isEqual: @"baz"])
#else
	TEST(@"-[lastPathComponent]",
	    [[C(@"c:/tmp") lastPathComponent] isEqual: @"tmp"] &&
	    [[C(@"c:\\tmp\\") lastPathComponent] isEqual: @"tmp"] &&
	    [[C(@"\\") lastPathComponent] isEqual: @""] &&
	    [[C(@"foo") lastPathComponent] isEqual: @"foo"] &&
	    [[C(@"foo\\bar") lastPathComponent] isEqual: @"bar"] &&
	    [[C(@"foo/bar/baz/") lastPathComponent] isEqual: @"baz"])
#endif

	TEST(@"-[pathExtension]",
	    [[C(@"foo.bar") pathExtension] isEqual: @"bar"] &&
	    [[C(@"foo/.bar") pathExtension] isEqual: @""] &&
	    [[C(@"foo/.bar.baz") pathExtension] isEqual: @"baz"] &&
	    [[C(@"foo/bar.baz/") pathExtension] isEqual: @"baz"])

#if !defined(OF_WINDOWS) && !defined(OF_MSDOS)
	TEST(@"-[stringByDeletingLastPathComponent]",
	    [[C(@"/tmp") stringByDeletingLastPathComponent] isEqual: @"/"] &&
	    [[C(@"/tmp/") stringByDeletingLastPathComponent] isEqual: @"/"] &&
	    [[C(@"/tmp/foo/") stringByDeletingLastPathComponent]
	    isEqual: @"/tmp"] &&
	    [[C(@"foo/bar") stringByDeletingLastPathComponent]
	    isEqual: @"foo"] &&
	    [[C(@"/") stringByDeletingLastPathComponent] isEqual: @"/"] &&
	    [[C(@"foo") stringByDeletingLastPathComponent] isEqual: @"."])
#else
	TEST(@"-[stringByDeletingLastPathComponent]",
	    [[C(@"\\tmp") stringByDeletingLastPathComponent] isEqual: @""] &&
	    [[C(@"/tmp/") stringByDeletingLastPathComponent] isEqual: @""] &&
	    [[C(@"c:\\tmp/foo/") stringByDeletingLastPathComponent]
	    isEqual: @"c:\\tmp"] &&
	    [[C(@"foo\\bar") stringByDeletingLastPathComponent]
	    isEqual: @"foo"] &&
	    [[C(@"\\") stringByDeletingLastPathComponent] isEqual: @""] &&
	    [[C(@"foo") stringByDeletingLastPathComponent] isEqual: @"."])
#endif

# if !defined(OF_WINDOWS) && !defined(OF_MSDOS)
#  define EXPECTED @"/foo./bar"
# else
#  define EXPECTED @"\\foo.\\bar"
# endif
	TEST(@"-[stringByDeletingPathExtension]",







|
>
>
>
>
|

<
<

|
|
<
|
>
|
|
|

>


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|



|



|














>

|







|







|







|









|









|







617
618
619
620
621
622
623
624
625
626
627
628
629
630


631
632
633

634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
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
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
				options: OF_STRING_SKIP_EMPTY]) &&
	    [a count] == 3 &&
	    [[a objectAtIndex: i++] isEqual: @"foo"] &&
	    [[a objectAtIndex: i++] isEqual: @"bar"] &&
	    [[a objectAtIndex: i++] isEqual: @"baz"])

#ifdef OF_HAVE_FILES
# if defined(OF_WINDOWS) || defined(OF_MSDOS)
	TEST(@"+[pathWithComponents:]",
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"foo", @"bar", @"baz", nil]] isEqual: @"foo\\bar\\baz"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"foo", nil]] isEqual: @"foo"])
# else


	TEST(@"+[pathWithComponents:]",
	    [[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"])
# endif

# if defined(OF_WINDOWS) || defined(OF_MSDOS)
	TEST(@"-[pathComponents]",
	    /* /tmp */
	    (a = [C(@"c:/tmp") pathComponents]) && [a count] == 2 &&
	    [[a objectAtIndex: 0] isEqual: @"c:"] &&
	    [[a objectAtIndex: 1] isEqual: @"tmp"] &&
	    /* /tmp/ */
	    (a = [C(@"c:\\tmp\\") pathComponents]) && [a count] == 2 &&
	    [[a objectAtIndex: 0] isEqual: @"c:"] &&
	    [[a objectAtIndex: 1] isEqual: @"tmp"] &&
	    /* / */
	    (a = [C(@"c:/") pathComponents]) && [a count] == 1 &&
	    [[a objectAtIndex: 0] isEqual: @"c:"] &&
	    /* foo/bar */
	    (a = [C(@"foo\\bar") pathComponents]) && [a count] == 2 &&
	    [[a objectAtIndex: 0] isEqual: @"foo"] &&
	    [[a objectAtIndex: 1] isEqual: @"bar"] &&
	    /* foo/bar/baz/ */
	    (a = [C(@"foo\\bar/baz") pathComponents]) && [a count] == 3 &&
	    [[a objectAtIndex: 0] isEqual: @"foo"] &&
	    [[a objectAtIndex: 1] isEqual: @"bar"] &&
	    [[a objectAtIndex: 2] isEqual: @"baz"] &&
	    /* foo// */
	    (a = [C(@"foo\\/") pathComponents]) && [a count] == 2 &&
	    [[a objectAtIndex: 0] isEqual: @"foo"] &&
	    [[a objectAtIndex: 1] isEqual: @""] &&
	    [[C(@"") pathComponents] count] == 0)
# else
	TEST(@"-[pathComponents]",
	    /* /tmp */
	    (a = [C(@"/tmp") pathComponents]) && [a count] == 2 &&
	    [[a objectAtIndex: 0] isEqual: @"/"] &&
	    [[a objectAtIndex: 1] isEqual: @"tmp"] &&
	    /* /tmp/ */
	    (a = [C(@"/tmp/") pathComponents]) && [a count] == 2 &&
	    [[a objectAtIndex: 0] isEqual: @"/"] &&
	    [[a objectAtIndex: 1] isEqual: @"tmp"] &&
	    /* / */
	    (a = [C(@"/") pathComponents]) && [a count] == 1 &&
	    [[a objectAtIndex: 0] isEqual: @"/"] &&
	    /* foo/bar */
	    (a = [C(@"foo/bar") pathComponents]) && [a count] == 2 &&
	    [[a objectAtIndex: 0] isEqual: @"foo"] &&
	    [[a objectAtIndex: 1] isEqual: @"bar"] &&
	    /* foo/bar/baz/ */
	    (a = [C(@"foo/bar/baz") pathComponents]) && [a count] == 3 &&
	    [[a objectAtIndex: 0] isEqual: @"foo"] &&
	    [[a objectAtIndex: 1] isEqual: @"bar"] &&
	    [[a objectAtIndex: 2] isEqual: @"baz"] &&
	    /* foo// */
	    (a = [C(@"foo//") pathComponents]) && [a count] == 2 &&
	    [[a objectAtIndex: 0] isEqual: @"foo"] &&
	    [[a objectAtIndex: 1] isEqual: @""] &&
	    [[C(@"") pathComponents] count] == 0)
# endif

# if !defined(OF_WINDOWS) && !defined(OF_MSDOS)
	TEST(@"-[lastPathComponent]",
	    [[C(@"/tmp") lastPathComponent] isEqual: @"tmp"] &&
	    [[C(@"/tmp/") lastPathComponent] isEqual: @"tmp"] &&
	    [[C(@"/") lastPathComponent] isEqual: @"/"] &&
	    [[C(@"foo") lastPathComponent] isEqual: @"foo"] &&
	    [[C(@"foo/bar") lastPathComponent] isEqual: @"bar"] &&
	    [[C(@"foo/bar/baz/") lastPathComponent] isEqual: @"baz"])
# else
	TEST(@"-[lastPathComponent]",
	    [[C(@"c:/tmp") lastPathComponent] isEqual: @"tmp"] &&
	    [[C(@"c:\\tmp\\") lastPathComponent] isEqual: @"tmp"] &&
	    [[C(@"\\") lastPathComponent] isEqual: @""] &&
	    [[C(@"foo") lastPathComponent] isEqual: @"foo"] &&
	    [[C(@"foo\\bar") lastPathComponent] isEqual: @"bar"] &&
	    [[C(@"foo/bar/baz/") lastPathComponent] isEqual: @"baz"])
# endif

	TEST(@"-[pathExtension]",
	    [[C(@"foo.bar") pathExtension] isEqual: @"bar"] &&
	    [[C(@"foo/.bar") pathExtension] isEqual: @""] &&
	    [[C(@"foo/.bar.baz") pathExtension] isEqual: @"baz"] &&
	    [[C(@"foo/bar.baz/") pathExtension] isEqual: @"baz"])

# if !defined(OF_WINDOWS) && !defined(OF_MSDOS)
	TEST(@"-[stringByDeletingLastPathComponent]",
	    [[C(@"/tmp") stringByDeletingLastPathComponent] isEqual: @"/"] &&
	    [[C(@"/tmp/") stringByDeletingLastPathComponent] isEqual: @"/"] &&
	    [[C(@"/tmp/foo/") stringByDeletingLastPathComponent]
	    isEqual: @"/tmp"] &&
	    [[C(@"foo/bar") stringByDeletingLastPathComponent]
	    isEqual: @"foo"] &&
	    [[C(@"/") stringByDeletingLastPathComponent] isEqual: @"/"] &&
	    [[C(@"foo") stringByDeletingLastPathComponent] isEqual: @"."])
# else
	TEST(@"-[stringByDeletingLastPathComponent]",
	    [[C(@"\\tmp") stringByDeletingLastPathComponent] isEqual: @""] &&
	    [[C(@"/tmp/") stringByDeletingLastPathComponent] isEqual: @""] &&
	    [[C(@"c:\\tmp/foo/") stringByDeletingLastPathComponent]
	    isEqual: @"c:\\tmp"] &&
	    [[C(@"foo\\bar") stringByDeletingLastPathComponent]
	    isEqual: @"foo"] &&
	    [[C(@"\\") stringByDeletingLastPathComponent] isEqual: @""] &&
	    [[C(@"foo") stringByDeletingLastPathComponent] isEqual: @"."])
# endif

# if !defined(OF_WINDOWS) && !defined(OF_MSDOS)
#  define EXPECTED @"/foo./bar"
# else
#  define EXPECTED @"\\foo.\\bar"
# endif
	TEST(@"-[stringByDeletingPathExtension]",