forked from jjgod/TextEditPlus
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTEFoundationExtras.m
151 lines (124 loc) · 4.58 KB
/
TEFoundationExtras.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// TEFoundationExtras.m
// TextExtras
//
// Copyright © 1996-2006, Mike Ferris.
// All rights reserved.
#import "TEFoundationExtras.h"
@implementation NSString (TEFoundationExtras)
- (NSString *)TE_stringByReplacingBackslashWithSlash {
NSMutableString *newStr = [self mutableCopy];
NSRange searchRange, foundRange;
searchRange = NSMakeRange(0, [self length]);
while ((searchRange.length > 0) && ((foundRange = [newStr rangeOfString:@"\\" options:NSLiteralSearch range:searchRange]).length > 0)) {
[newStr replaceCharactersInRange:foundRange withString:@"/"];
searchRange = NSMakeRange(NSMaxRange(foundRange), NSMaxRange(searchRange) - NSMaxRange(foundRange));
}
return [newStr autorelease];
}
@end
@implementation NSMutableString (TEFoundationExtras)
static void standardizeEndOfLineInString(NSMutableString *str, NSString *newEOL) {
// This function works by replacing ParagraphSeparator, CRLF, CR, or LF with newEOL. Note that CRLF is replaced by a single newEOL.
unsigned newEOLLen;
unichar newEOLStackBuf[2];
unichar *newEOLBuf;
BOOL freeNewEOLBuf = NO;
unsigned length = [str length];
unsigned curPos = 0;
unsigned start, end, contentsEnd;
newEOLLen = [newEOL length];
if (newEOLLen > 2) {
newEOLBuf = NSZoneMalloc(NULL, sizeof(unichar) * newEOLLen);
freeNewEOLBuf = YES;
} else {
newEOLBuf = newEOLStackBuf;
}
[newEOL getCharacters:newEOLBuf];
while (curPos < length) {
[str getLineStart:&start end:&end contentsEnd:&contentsEnd forRange:NSMakeRange(curPos, 1)];
if (contentsEnd < end) {
int changeInLength = newEOLLen - (end - contentsEnd);
BOOL alreadyNewEOL = YES;
if (changeInLength == 0) {
unsigned i;
for (i=0; i<newEOLLen; i++) {
// Multiple characterAtIndex: calls may be expensive. But for any normal case, it will be called either one or two times only. Still, it probably ought to be meaured whether it is faster to just do the no-op replace instead of detecting it and avoiding it.
if ([str characterAtIndex:contentsEnd+i] != newEOLBuf[i]) {
alreadyNewEOL = NO;
break;
}
}
} else {
alreadyNewEOL = NO;
}
if (!alreadyNewEOL) {
[str replaceCharactersInRange:NSMakeRange(contentsEnd, end - contentsEnd) withString:newEOL];
end += changeInLength;
length += changeInLength;
}
}
curPos = end;
}
if (freeNewEOLBuf) {
NSZoneFree(NSZoneFromPointer(newEOLBuf), newEOLBuf);
}
}
- (void)TE_standardizeEndOfLineToLF {
standardizeEndOfLineInString(self, @"\n");
}
- (void)TE_standardizeEndOfLineToCRLF {
standardizeEndOfLineInString(self, @"\r\n");
}
- (void)TE_standardizeEndOfLineToCR {
standardizeEndOfLineInString(self, @"\r");
}
- (void)TE_standardizeEndOfLineToParagraphSeparator {
unichar paragraphSeparator[1];
paragraphSeparator[0] = NSParagraphSeparatorCharacter;
standardizeEndOfLineInString(self, [NSString stringWithCharacters:paragraphSeparator length:1]);
}
- (void)TE_standardizeEndOfLineToLineSeparator {
unichar lineSeparator[1];
lineSeparator[0] = NSLineSeparatorCharacter;
standardizeEndOfLineInString(self, [NSString stringWithCharacters:lineSeparator length:1]);
}
@end
@implementation NSArray (TEFoundationExtras)
- (NSString *)TE_longestCommonPrefixForStrings {
unsigned charIndex = 0;
unsigned i, c;
NSString *curString;
unichar curChar = 0;
BOOL done = NO;
if ((c = [self count]) == 0) {
return @"";
}
if (c == 1) {
return [self objectAtIndex:0];
}
while (1) {
for (i=0; i<c; i++) {
curString = [self objectAtIndex:i];
if (charIndex < [curString length]) {
if (i==0) {
curChar = [curString characterAtIndex:charIndex];
} else {
if (curChar != [curString characterAtIndex:charIndex]) {
done = YES;
break;
}
}
} else {
done = YES;
break;
}
}
if (done) {
break;
}
charIndex++;
}
// charIndex is one past the end of the common prefix all the strings share
return ((charIndex > 0) ? [[self objectAtIndex:0] substringWithRange:NSMakeRange(0, charIndex)] : @"");
}
@end