Changeset 24146
- Timestamp:
- 07/01/2008 03:02:10 PM (5 months ago)
- Files:
-
- trunk/Frameworks/AutoHyperlinks Framework/AutoHyperlinks.framework.xcodeproj/project.pbxproj (modified) (4 diffs)
- trunk/Frameworks/AutoHyperlinks Framework/LinkDriver/LinkDriverWindowController.m (modified) (2 diffs)
- trunk/Frameworks/AutoHyperlinks Framework/Source/AHHyperlinkScanner.h (modified) (3 diffs)
- trunk/Frameworks/AutoHyperlinks Framework/Source/AHHyperlinkScanner.m (modified) (14 diffs)
- trunk/Frameworks/AutoHyperlinks Framework/Source/AHLinkLexer.h (modified) (1 diff)
- trunk/Frameworks/AutoHyperlinks Framework/Source/AHLinkLexer.l (modified) (3 diffs)
- trunk/Frameworks/AutoHyperlinks Framework/UnitTests/HyperlinkContextTest.m (modified) (2 diffs)
- trunk/Frameworks/AutoHyperlinks Framework/UnitTests/NegativeURLTest.h (modified) (1 diff)
- trunk/Frameworks/AutoHyperlinks Framework/UnitTests/NegativeURLTest.m (modified) (1 diff)
- trunk/Frameworks/AutoHyperlinks Framework/UnitTests/SimpleURLTest.h (modified) (1 diff)
- trunk/Frameworks/AutoHyperlinks Framework/UnitTests/SimpleURLTest.m (modified) (1 diff)
- trunk/Frameworks/AutoHyperlinks Framework/UnitTests/StressTest.m (modified) (1 diff)
- trunk/Frameworks/AutoHyperlinks Framework/UnitTests/ThreadedStressTest.m (modified) (3 diffs)
- trunk/Plugins/Link Management/SHAutoValidatingTextView.m (modified) (1 diff)
- trunk/Plugins/Link Management/SHLinkEditorWindowController.m (modified) (1 diff)
- trunk/Source/AIAutoLinkingPlugin.h (modified) (1 diff)
- trunk/Source/AIAutoLinkingPlugin.m (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/Frameworks/AutoHyperlinks Framework/AutoHyperlinks.framework.xcodeproj/project.pbxproj
r24137 r24146 979 979 GCC_PRECOMPILE_PREFIX_HEADER = YES; 980 980 GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h"; 981 INFOPLIST_FILE = "LinkDriver -Info.plist";981 INFOPLIST_FILE = "LinkDriver/LinkDriver-Info.plist"; 982 982 INSTALL_PATH = "$(HOME)/Applications"; 983 983 OTHER_LDFLAGS = ( … … 1003 1003 GCC_PRECOMPILE_PREFIX_HEADER = YES; 1004 1004 GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h"; 1005 INFOPLIST_FILE = "LinkDriver -Info.plist";1005 INFOPLIST_FILE = "LinkDriver/LinkDriver-Info.plist"; 1006 1006 INSTALL_PATH = "$(HOME)/Applications"; 1007 1007 OTHER_LDFLAGS = ( … … 1025 1025 GCC_PRECOMPILE_PREFIX_HEADER = YES; 1026 1026 GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h"; 1027 INFOPLIST_FILE = "LinkDriver -Info.plist";1027 INFOPLIST_FILE = "LinkDriver/LinkDriver-Info.plist"; 1028 1028 INSTALL_PATH = "$(HOME)/Applications"; 1029 1029 OTHER_LDFLAGS = ( … … 1047 1047 GCC_PRECOMPILE_PREFIX_HEADER = YES; 1048 1048 GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h"; 1049 INFOPLIST_FILE = "LinkDriver -Info.plist";1049 INFOPLIST_FILE = "LinkDriver/LinkDriver-Info.plist"; 1050 1050 INSTALL_PATH = "$(HOME)/Applications"; 1051 1051 OTHER_LDFLAGS = ( trunk/Frameworks/AutoHyperlinks Framework/LinkDriver/LinkDriverWindowController.m
r24114 r24146 4 4 // 5 5 // Created by Stephen Holt on 5/15/08. 6 // Copyright 2008 __MyCompanyName__. All rights reserved.7 6 // 8 7 … … 25 24 { 26 25 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 27 AHHyperlinkScanner *scanner = [ [AHHyperlinkScanner alloc] initWithStrictChecking:NO];28 [ scanner linkifyTextView:inView];26 AHHyperlinkScanner *scanner = [AHHyperlinkScanner hyperlinkScannerWithAttributedString:[inView textStorage]]; 27 [[inView textStorage] setAttributedString:[scanner linkifiedString]]; 29 28 [pool release]; 30 29 } trunk/Frameworks/AutoHyperlinks Framework/Source/AHHyperlinkScanner.h
r24137 r24146 28 28 #import "AHLinkLexer.h" 29 29 30 extern long AHleng; 31 extern long AHlex(); 30 typedef void* yyscan_t; 31 32 extern long AHlex( yyscan_t yyscanner ); 33 extern long AHlex_init( yyscan_t * ptr_yy_globals ); 34 extern long AHlex_destroy ( yyscan_t yyscanner ); 35 extern long AHget_leng ( yyscan_t scanner ); 36 extern void AHset_in ( FILE * in_str , yyscan_t scanner ); 37 32 38 typedef struct AH_buffer_state *AH_BUFFER_STATE; 33 void AH_switch_to_buffer(AH_BUFFER_STATE);34 AH_BUFFER_STATE AH_scan_string (const char *);35 void AH_delete_buffer(AH_BUFFER_STATE);39 extern void AH_switch_to_buffer(AH_BUFFER_STATE, yyscan_t scanner); 40 extern AH_BUFFER_STATE AH_scan_string (const char *, yyscan_t scanner); 41 extern void AH_delete_buffer(AH_BUFFER_STATE, yyscan_t scanner); 36 42 37 43 @class AHMarkedHyperlink; … … 39 45 @interface AHHyperlinkScanner : NSObject 40 46 { 41 NSDictionary *urlSchemes; 42 BOOL strictChecking; 43 unsigned long stringOffset; 47 NSDictionary *m_urlSchemes; 48 NSString *m_scanString; 49 NSAttributedString *m_scanAttrString; 50 BOOL m_strictChecking; 51 unsigned long m_scanLocation; 52 unsigned long m_scanStringLength; 44 53 } 45 46 /*!47 * @brief Init48 *49 * Defaults to strict URL checking (only links with schemes are matched).50 *51 * @return A new AHHyperlinkScanner.52 */53 - (id)init;54 55 /*!56 * @brief Init57 *58 * @param flag Sets strict checking preference.59 * @return A new AHHyperlinkScanner.60 */61 - (id)initWithStrictChecking:(BOOL)flag;62 54 63 55 64 56 /*! 65 * @brief Determine the validity of a given string using the default strictness57 * @brief Allocs and inits a new lax AHHyperlinkScanner with the given NSString 66 58 * 67 * @param inString The string to be verified68 * @return Boolean59 * @param inString the scanner's string 60 * @return a new AHHyperlinkScanner 69 61 */ 70 - (BOOL)isStringValidURL:(NSString *)inString; 62 + (id)hyperlinkScannerWithString:(NSString *)inString; 63 64 /*! 65 * @brief Allocs and inits a new strict AHHyperlinkScanner with the given NSString 66 * 67 * @param inString the scanner's string 68 * @return a new AHHyperlinkScanner 69 */ 70 + (id)strictHyperlinkScannerWithString:(NSString *)inString; 71 72 /*! 73 * @brief Allocs and inits a new lax AHHyperlinkScanner with the given attributed string 74 * 75 * @param inString the scanner's string 76 * @return a new AHHyperlinkScanner 77 */ 78 + (id)hyperlinkScannerWithAttributedString:(NSAttributedString *)inString; 79 80 /*! 81 * @brief Allocs and inits a new strict AHHyperlinkScanner with the given attributed string 82 * 83 * @param inString the scanner's string 84 * @return a new AHHyperlinkScanner 85 */ 86 + (id)strictHyperlinkScannerWithAttributedString:(NSAttributedString *)inString; 71 87 72 88 /*! … … 76 92 * @param useStrictChecking Use strict rules or not 77 93 * @param index a pointer to the index the string starts at, for easy incrementing. 78 * @param validStatus a pointer to an AH_URI_VERIFICATION_STATUS which will be set to the status of the URL on return. Pass NULL if this information is not needed.79 94 * @return Boolean 80 95 */ 81 + (BOOL)isStringValidUR L:(NSString *)inString usingStrict:(BOOL)useStrictChecking fromIndex:(unsigned long *)index withStatus:(AH_URI_VERIFICATION_STATUS *)validStatus;96 + (BOOL)isStringValidURI:(NSString *)inString usingStrict:(BOOL)useStrictChecking fromIndex:(unsigned long *)index withStatus:(AH_URI_VERIFICATION_STATUS *)validStatus; 82 97 83 98 /*! 84 * @brief Fetches all the URLs from a string 85 * @param inString The NSString with potential URLs in it 99 * @brief Init 100 * 101 * Inits a new AHHyperlinkScanner object for a NSString with the set strict checking option. 102 * 103 * @param inString the NSString to be scanned. 104 * @param flag Sets strict checking preference. 105 * @return A new AHHyperlinkScanner. 106 */ 107 - (id)initWithString:(NSString *)inString usingStrictChecking:(BOOL)flag; 108 109 /*! 110 * @brief Init 111 * 112 * Inits a new AHHyperlinkScanner object for a NSAttributedString with the set strict checking option. 113 * 114 * param inString the NSString to be scanned. 115 * @param flag Sets strict checking preference. 116 * @return A new AHHyperlinkScanner. 117 */ 118 - (id)initWithAttributedString:(NSAttributedString *)inString usingStrictChecking:(BOOL)flag; 119 120 121 /*! 122 * @brief Determine the validity of the scanner's string using the set strictness 123 * 124 * @return Boolean 125 */ 126 - (BOOL)isValidURI; 127 128 /*! 129 * @brief Returns a AHMarkedHyperlink representing the next URI in the scanner's string 130 * 131 * @return A new AHMarkedHyperlink. 132 */ 133 - (AHMarkedHyperlink *)nextURI; 134 135 /*! 136 * @brief Fetches all the URIs from the scanner's string 137 * 86 138 * @return An array of AHMarkedHyperlinks representing each matched URL in the string or nil if no matches. 87 139 */ 88 - (NSArray *)allUR LsFromString:(NSString *)inString;140 - (NSArray *)allURIs; 89 141 90 142 /*! 91 * @brief Fetches all the URLs from a NSTextView 92 * @param inView The NSTextView with potential URLs in it 93 * @return An array of AHMarkedHyperlinks representing each matched URL in the textView or nil if no matches. 94 */ 95 - (NSArray *)allURLsFromTextView:(NSTextView *)inView; 96 97 /*! 98 * @brief Scans an attributed string for URLs then adds the link attribs and objects. 143 * @brief Scans an attributed string for URIs then adds the link attribs and objects. 99 144 * @param inString The NSAttributedString to be linkified 100 145 * @return An autoreleased NSAttributedString. 101 146 */ 102 - (NSAttributedString *)linkif yString:(NSAttributedString *)inString;147 - (NSAttributedString *)linkifiedString; 103 148 104 /*! 105 * @brief Scans a NSTextView's text store for URLs then adds the link attribs and objects. 106 * 107 * This scan happens in place: the origional NSTextView is modified, and nothing is returned. 108 * @param inView The NSTextView to be linkified. 109 */ 110 - (void)linkifyTextView:(NSTextView *)inView; 149 - (unsigned long)scanLocation; 150 - (void)setScanLocation:(unsigned int)location; 111 151 112 152 @end trunk/Frameworks/AutoHyperlinks Framework/Source/AHHyperlinkScanner.m
r24137 r24146 32 32 #define DEFAULT_URL_SCHEME @"http://" 33 33 34 @interface AHHyperlinkScanner (PRIVATE)35 - (AHMarkedHyperlink *)nextURLFromString:(NSString *)inString;36 @end37 38 34 @implementation AHHyperlinkScanner 39 35 40 #pragma mark Init 41 42 43 - (id)init 44 { 45 return [self initWithStrictChecking:YES]; 46 } 47 48 - (id)initWithStrictChecking:(BOOL)flag 36 #pragma mark Class Methods 37 + (id)hyperlinkScannerWithString:(NSString *)inString 38 { 39 return [[[[self class] alloc] initWithString:inString usingStrictChecking:NO] autorelease]; 40 } 41 42 + (id)strictHyperlinkScannerWithString:(NSString *)inString 43 { 44 return [[[[self class] alloc] initWithString:inString usingStrictChecking:YES] autorelease]; 45 } 46 47 + (id)hyperlinkScannerWithAttributedString:(NSAttributedString *)inString 48 { 49 return [[[[self class] alloc] initWithAttributedString:inString usingStrictChecking:NO] autorelease]; 50 } 51 52 + (id)strictHyperlinkScannerWithAttributedString:(NSAttributedString *)inString 53 { 54 return [[[[self class] alloc] initWithAttributedString:inString usingStrictChecking:NO] autorelease]; 55 } 56 57 #pragma mark Init/Dealloc 58 59 60 - (id)initWithString:(NSString *)inString usingStrictChecking:(BOOL)flag 49 61 { 50 62 if((self = [super init])){ 51 urlSchemes = [[NSDictionary alloc] initWithObjectsAndKeys: 63 m_scanString = [inString retain]; 64 m_scanAttrString = nil; 65 m_urlSchemes = [[NSDictionary alloc] initWithObjectsAndKeys: 52 66 @"ftp://", @"ftp", 53 67 nil]; 54 strictChecking = flag; 55 stringOffset = 0; 68 m_strictChecking = flag; 69 m_scanLocation = 0; 70 m_scanStringLength = [m_scanString length]; 56 71 } 57 72 … … 59 74 } 60 75 76 - (id)initWithAttributedString:(NSAttributedString *)inString usingStrictChecking:(BOOL)flag 77 { 78 if((self = [super init])){ 79 m_scanString = [[inString string] retain]; 80 m_scanAttrString = [inString retain]; 81 m_urlSchemes = [[NSDictionary alloc] initWithObjectsAndKeys: 82 @"ftp://", @"ftp", 83 nil]; 84 m_strictChecking = flag; 85 m_scanLocation = 0; 86 m_scanStringLength = [m_scanString length]; 87 } 88 89 return self; 90 } 91 61 92 - (void)dealloc 62 93 { 63 [urlSchemes release]; 94 [m_scanString release]; 95 [m_urlSchemes release]; 96 if(m_scanAttrString) [m_scanAttrString release]; 64 97 [super dealloc]; 65 98 } 66 99 67 #pragma mark primitive methods 68 69 - (BOOL)isStringValidURL:(NSString *)inString 70 { 71 return [AHHyperlinkScanner isStringValidURL:inString usingStrict:strictChecking fromIndex:nil withStatus:nil]; 72 } 73 74 + (BOOL)isStringValidURL:(NSString *)inString usingStrict:(BOOL)useStrictChecking fromIndex:(unsigned long *)index withStatus:(AH_URI_VERIFICATION_STATUS *)validStatus 75 { 76 AH_BUFFER_STATE buf; // buffer for flex to scan from 100 #pragma mark URI Verification 101 102 - (BOOL)isValidURI 103 { 104 return [AHHyperlinkScanner isStringValidURI:m_scanString usingStrict:m_strictChecking fromIndex:nil withStatus:nil]; 105 } 106 107 + (BOOL)isStringValidURI:(NSString *)inString usingStrict:(BOOL)useStrictChecking fromIndex:(unsigned long *)index withStatus:(AH_URI_VERIFICATION_STATUS *)validStatus 108 { 109 AH_BUFFER_STATE buf; // buffer for flex to scan from 110 yyscan_t scanner; // pointer to the flex scanner opaque type 77 111 const char *inStringEnc; 78 112 unsigned long encodedLength; 79 static NSLock *linkLock = nil; 80 81 82 if(!linkLock) 83 linkLock = [[NSLock alloc] init]; 84 [linkLock lock]; 85 113 86 114 if(!validStatus){ 87 115 AH_URI_VERIFICATION_STATUS newStatus = AH_URL_INVALID; … … 97 125 98 126 if (!(inStringEnc = [inString cStringUsingEncoding:stringEnc])) { 99 [linkLock unlock];100 127 return NO; 101 128 } … … 105 132 106 133 // initialize the buffer (flex automatically switches to the buffer in this function) 107 buf = AH_scan_string(inStringEnc); 134 AHlex_init(&scanner); 135 buf = AH_scan_string(inStringEnc, scanner); 108 136 109 137 // call flex to parse the input 110 *validStatus = AHlex( );111 if(index) *index += AH leng;138 *validStatus = AHlex(scanner); 139 if(index) *index += AHget_leng(scanner); 112 140 113 141 // condition for valid URI's 114 142 if(*validStatus == AH_URL_VALID || *validStatus == AH_MAILTO_VALID || *validStatus == AH_FILE_VALID){ 115 AH_delete_buffer(buf ); //remove the buffer from flex.143 AH_delete_buffer(buf, scanner); //remove the buffer from flex. 116 144 buf = NULL; //null the buffer pointer for safty's sake. 117 145 118 146 // check that the whole string was matched by flex. 119 147 // this prevents silly things like "blah...com" from being seen as links 120 if(AH leng== encodedLength){121 [linkLock unlock];148 if(AHget_leng(scanner) == encodedLength){ 149 AHlex_destroy(scanner); 122 150 return YES; 123 151 } 124 152 // condition for degenerate URL's (A.K.A. URI's sans specifiers), requres strict checking to be NO. 125 153 }else if((*validStatus == AH_URL_DEGENERATE || *validStatus == AH_MAILTO_DEGENERATE) && !useStrictChecking){ 126 AH_delete_buffer(buf );154 AH_delete_buffer(buf, scanner); 127 155 buf = NULL; 128 if(AH leng== encodedLength){129 [linkLock unlock];156 if(AHget_leng(scanner) == encodedLength){ 157 AHlex_destroy(scanner); 130 158 return YES; 131 159 } 132 160 // if it ain't vaild, and it ain't degenerate, then it's invalid. 133 161 }else{ 134 AH_delete_buffer(buf );162 AH_delete_buffer(buf, scanner); 135 163 buf = NULL; 136 [linkLock unlock];164 AHlex_destroy(scanner); 137 165 return NO; 138 166 } 139 167 // default case, if the range checking above fails. 140 [linkLock unlock];168 AHlex_destroy(scanner); 141 169 return NO; 142 170 } 143 171 144 /*! 145 * @brief Retreives the next URL from the given string 146 * 147 * Private to AHHyperlinkScanner. Calling on this externally could create some weird results. 148 * 149 * @return a AHMarkedHyperlink representing the given URL or nil, if there are no more hyperlinks. 150 */ 151 - (AHMarkedHyperlink *)nextURLFromString:(NSString *)inString fromIndex:(unsigned long)index 172 #pragma mark Accessors 173 174 - (AHMarkedHyperlink *)nextURI 152 175 { 153 176 NSString *scanString = nil; … … 207 230 // scan upto the next whitespace char so that we don't unnecessarity confuse flex 208 231 // otherwise we end up validating urls that look like this "http://www.adiumx.com/ <--cool" 209 NSScanner *preScanner = [[[NSScanner alloc] initWithString: inString] autorelease];232 NSScanner *preScanner = [[[NSScanner alloc] initWithString:m_scanString] autorelease]; 210 233 [preScanner setCharactersToBeSkipped:skipSet]; 211 [preScanner setScanLocation: index];234 [preScanner setScanLocation:m_scanLocation]; 212 235 213 236 [preScanner scanCharactersFromSet:startSet intoString:nil]; … … 232 255 233 256 // Find balanced enclosure chars 234 NSMutableArray *enclosureStack = [NSMutableArray arrayWithCapacity:2]; // totally arbitrary. 235 NSMutableArray *enclosureArray = [NSMutableArray arrayWithCapacity:2]; 257 NSMutableArray *enclosureStack = nil, *enclosureArray = nil; 236 258 NSString *matchChar = nil; 237 259 NSScanner *enclosureScanner = [[[NSScanner alloc] initWithString:scanString] autorelease]; … … 245 267 246 268 if(encScanLocation >= [[enclosureScanner string] length]) break; 269 247 270 matchChar = [scanString substringWithRange:NSMakeRange(encScanLocation, 1)]; 271 248 272 if([enclosureStartArray containsObject:matchChar]) { 249 273 encDict = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:[NSNumber numberWithUnsignedLong:encScanLocation], matchChar, nil] 250 274 forKeys:encKeys]; 275 if(!enclosureStack) enclosureStack = [NSMutableArray arrayWithCapacity:1]; 251 276 [enclosureStack addObject:encDict]; 252 277 }else if([enclosureStopArray containsObject:matchChar]) { … … 257 282 if([enclosureStopArray indexOfObjectIdenticalTo:matchChar] == encStartIndex) { 258 283 NSRange encRange = NSMakeRange(encTagIndex, encScanLocation - encTagIndex); 284 if(!enclosureStack) enclosureStack = [NSMutableArray arrayWithCapacity:1]; 285 if(!enclosureArray) enclosureArray = [NSMutableArray arrayWithCapacity:1]; 259 286 [enclosureStack removeObject:encDict]; 260 287 [enclosureArray addObject:NSStringFromRange(encRange)]; … … 267 294 } 268 295 NSRange lastEnclosureRange = NSMakeRange(0, 0); 269 if( [enclosureArray count]) lastEnclosureRange = NSRangeFromString([enclosureArray lastObject]);296 if(enclosureArray && [enclosureArray count]) lastEnclosureRange = NSRangeFromString([enclosureArray lastObject]); 270 297 while (finalStringLen > 2 && [endSet characterIsMember:[scanString characterAtIndex:finalStringLen - 1]]) { 271 298 if((lastEnclosureRange.location + lastEnclosureRange.length + 1) < finalStringLen){ … … 274 301 }else break; 275 302 } 276 277 stringOffset= scannedLocation - finalStringLen;303 304 m_scanLocation = scannedLocation - finalStringLen; 278 305 279 306 // if we have a valid URL then save the scanned string, and make a SHMarkedHyperlink out of it. … … 281 308 // parent string, its validation status (valid, file, degenerate, etc), and its range in the parent string 282 309 AH_URI_VERIFICATION_STATUS validStatus; 283 if((finalStringLen > 0) && [ AHHyperlinkScanner isStringValidURL:scanString usingStrict:strictChecking fromIndex:&stringOffsetwithStatus:&validStatus]){310 if((finalStringLen > 0) && [[self class] isStringValidURI:scanString usingStrict:m_strictChecking fromIndex:&m_scanLocation withStatus:&validStatus]){ 284 311 AHMarkedHyperlink *markedLink; 285 312 NSRange urlRange; … … 299 326 300 327 if(firstComponent) { 301 NSString *hostnameScheme = [ urlSchemes objectForKey:firstComponent];328 NSString *hostnameScheme = [m_urlSchemes objectForKey:firstComponent]; 302 329 if(hostnameScheme) scheme = hostnameScheme; 303 330 } … … 320 347 markedLink = [[AHMarkedHyperlink alloc] initWithString:scanString 321 348 withValidationStatus:validStatus 322 parentString: inString349 parentString:m_scanString 323 350 andRange:urlRange]; 324 351 return [markedLink autorelease]; … … 328 355 NSRange startRange = [scanString rangeOfCharacterFromSet:startSet]; 329 356 if (startRange.location != NSNotFound) { 330 index += startRange.location + 1;331 if( index >= [inString length])332 index--;357 m_scanLocation += startRange.length; 358 if(m_scanLocation >= m_scanStringLength) 359 m_scanLocation--; 333 360 }else{ 334 index+= [scanString length];335 if( index >= [inString length])336 index--;361 m_scanLocation += [scanString length]; 362 if(m_scanLocation >= m_scanStringLength) 363 m_scanLocation--; 337 364 } 338 [preScanner setScanLocation: index++];365 [preScanner setScanLocation:m_scanLocation]; 339 366 } 340 367 341 368 // if we're here, then NSScanner hit the end of the string 342 369 // set AHStringOffset to the string length here so we avoid potential infinite looping with many trailing spaces. 343 stringOffset = [inString length];370 m_scanLocation = m_scanStringLength; 344 371 return nil; 345 372 } 346 373 347 #pragma mark string and textview handleing 348 349 350 -(NSArray *)allURLsFromString:(NSString *)inString 351 { 352 NSMutableArray *rangeArray = nil; 374 -(NSArray *)allURIs 375 { 376 NSMutableArray *rangeArray = [NSMutableArray array]; 353 377 AHMarkedHyperlink *markedLink; 354 stringOffset = 0; //set the offset to 0. 378 unsigned long _holdOffset = m_scanLocation; // store location for later restoration; 379 m_scanLocation = 0; //set the offset to 0. 355 380 356 381 //build an array of marked links. 357 while([inString length] > stringOffset){ 358 if((markedLink = [self nextURLFromString:inString fromIndex:stringOffset])){ 359 if(!rangeArray) rangeArray = [NSMutableArray array]; 360 [rangeArray addObject:markedLink]; 361 } 362 } 363 382 while((markedLink = [self nextURI])){ 383 [rangeArray addObject:markedLink]; 384 } 385 m_scanLocation = _holdOffset; // reset scanLocation 364 386 return rangeArray; 365 387 } 366 388 367 368 -(NSArray *)allURLsFromTextView:(NSTextView *)inView 369 { 370 // since a NSTextView is really just a glorified NSMutableAttributedString, 371 // we can take the string and send it out to allURLsFromString: 372 return [self allURLsFromString:[inView string]]; 373 } 374 375 376 -(NSAttributedString *)linkifyString:(NSAttributedString *)inString 377 { 378 //build an array from the input string and get its obj. enumerator 379 NSArray *rangeArray = [self allURLsFromString:[inString string]]; 380 381 if([rangeArray count]){ 382 NSMutableAttributedString *linkifiedString; 383 NSEnumerator *enumerator; 384 AHMarkedHyperlink *markedLink; 385 386 linkifiedString = [[inString mutableCopy] autorelease]; 387 388 //for each SHMarkedHyperlink, add the proper URL to the proper range in the string. 389 enumerator = [rangeArray objectEnumerator]; 390 while((markedLink = [enumerator nextObject])){ 391 NSURL *markedLinkURL; 392 393 if((markedLinkURL = [markedLink URL])){ 394 [linkifiedString addAttribute:NSLinkAttributeName 395 value:markedLinkURL 396 range:[markedLink range]]; 397 } 389 -(NSAttributedString *)linkifiedString 390 { 391 NSMutableAttributedString *linkifiedString; 392 AHMarkedHyperlink *markedLink; 393 BOOL _didFindLinks = NO; 394 unsigned long _holdOffset = m_scanLocation; // store location for later restoration; 395 396 m_scanLocation = 0; 397 398 if(m_scanAttrString) { 399 linkifiedString = [[m_scanAttrString mutableCopy] autorelease]; 400 } else { 401 linkifiedString = [[[NSMutableAttributedString alloc] initWithString:m_scanString] autorelease]; 402 } 403 404 //for each SHMarkedHyperlink, add the proper URL to the proper range in the string. 405 while((markedLink = [self nextURI])) { 406 NSURL *markedLinkURL; 407 _didFindLinks = YES; 408 if((markedLinkURL = [markedLink URL])){ 409 [linkifiedString addAttribute:NSLinkAttributeName 410 value:markedLinkURL 411 range:[markedLink range]]; 398 412 } 399 400 return linkifiedString; 401 402 }else{ 403 //If no links were found, just return the string we were passed 404 return [[inString retain] autorelease]; 405 } 406 } 407 408 409 - (void)linkifyTextView:(NSTextView *)inView 410 { 411 NSAttributedString *newAttributedString; 412 413 // like allURLsFromTextView before it, we can just call the linkifyString: method here 414 // then replace the NSTextView's contents with it. 415 newAttributedString = [self linkifyString:[inView attributedSubstringFromRange:NSMakeRange(0,[[inView string] length])]]; 416 417 [[inView textStorage] setAttributedString:newAttributedString]; 418 } 419 413 } 414 415 m_scanLocation = _holdOffset; // reset scanLocation 416 417 return _didFindLinks? linkifiedString : 418 m_scanAttrString ? [[m_scanAttrString retain] autorelease] : [[[NSMutableAttributedString alloc] initWithString:m_scanString] autorelease]; 419 } 420 421 -(unsigned long)scanLocation 422 { 423 return m_scanLocation; 424 } 425 426 - (void)setScanLocation:(unsigned int)location 427 { 428 m_scanLocation = location; 429 } 420 430 @end trunk/Frameworks/AutoHyperlinks Framework/Source/AHLinkLexer.h
r23471 r24146 34 34 AH_MAILTO_DEGENERATE 35 35 } AH_URI_VERIFICATION_STATUS; 36 37 #define YY_EXTRA_TYPE unsigned int trunk/Frameworks/AutoHyperlinks Framework/Source/AHLinkLexer.l
r23905 r24146 43 43 * without a costly call to yymore(). 44 44 */ 45 long AHValidShift = 0;46 45 #include "AHLinkLexer.h" 47 46 %} … … 89 88 ignoreable (b\.sc|m\.in) 90 89 91 %option noyywrap nounput 8bit caseless never-interactive prefix="AH"90 %option noyywrap nounput 8bit caseless never-interactive reentrant warn prefix="AH" 92 91 93 92 %x CANONICAL 94 93 %% 95 94 96 <CANONICAL>({userAndPass}@)?{urlCSpec}|{ipURL}|{ipv6URL} { AHleng += AHValidShift;95 <CANONICAL>({userAndPass}@)?{urlCSpec}|{ipURL}|{ipv6URL} {yyleng += yyextra; 97 96 BEGIN INITIAL; 98 97 return AH_URL_VALID;} … … 124 123 notes:\/\/ | 125 124 gopher:\/\/ | 126 x-man-page:\/\/ { AHValidShift = AHleng; BEGIN CANONICAL;}125 x-man-page:\/\/ {yyextra = yyleng; BEGIN CANONICAL;} 127 126 128 127 mailto:{mailSpec} {return AH_MAILTO_VALID;} trunk/Frameworks/AutoHyperlinks Framework/UnitTests/HyperlinkContextTest.m
r24112 r24146 8 8 9 9 @implementation HyperlinkContextTest 10 - (void)testLaxContext:(NSString *)linkString withURI:(NSString *)URIString {11 AHHyperlinkScanner *scanner = [[AHHyperlinkScanner alloc] initWithStrictChecking:NO]; 10 - (void)testLaxContext:(NSString *)linkString withURI:(NSString *)URIString 11 { 12 12 NSString *testString = [NSString stringWithFormat:linkString, URIString]; 13 AHMarkedHyperlink *link = [[scanner allURLsFromString:testString] objectAtIndex:0]; 14 15 STAssertNotNil(link, @"-[SHHyperlinkScanner nextURLFromString:] found no URI in \"%@\"", testString); 13 AHHyperlinkScanner *scanner = [AHHyperlinkScanner hyperlinkScannerWithString:testString]; 14 AHMarkedHyperlink *link = [scanner nextURI]; 15 16 STAssertNotNil(link, @"-[SHHyperlinkScanner nextURL] found no URI in \"%@\"", testString); 16 17 STAssertEqualObjects([[link parentString] substringWithRange:[link range]], URIString, @"in context: '%@'", testString); 17 18 } … … 19 20 - (void)testNegativeContext:(NSString *)linkString withURI:(NSString *)URIString 20 21 { 21 AHHyperlinkScanner *scanner = [[AHHyperlinkScanner alloc] initWithStrictChecking:NO];22 22 NSString *testString = [NSString stringWithFormat:linkString, URIString]; 23 AHMarkedHyperlink *link = [[scanner allURLsFromString:testString] objectAtIndex:0]; 23 AHHyperlinkScanner *scanner = [AHHyperlinkScanner hyperlinkScannerWithString:testString]; 24 AHMarkedHyperlink *link = [scanner nextURI]; 24 25 25 26 STAssertNil(link, @"-[SHHyperlinkScanner nextURLFromString:] found no URI in \"%@\"", testString); trunk/Frameworks/AutoHyperlinks Framework/UnitTests/NegativeURLTest.h
r23421 r24146 7 7 #import "AutoHyperlinks.h" 8 8 9 #define testHyperlink(x) STAssertFalse([scanner isStringValidURL: x ], @"%@ is a valid URI and should not be", x) 9 #define testHyperlink(x) STAssertFalse([AHHyperlinkScanner isStringValidURI: x usingStrict:YES fromIndex:0 withStatus:nil], @"%@ is a valid URI and should not be", x) 10 10 11 11 12 @interface NegativeURLTest : SenTestCase { 12 AHHyperlinkScanner *scanner;13 13 } 14 14 trunk/Frameworks/AutoHyperlinks Framework/UnitTests/NegativeURLTest.m
r23863 r24146 7 7 8 8 @implementation NegativeURLTest 9 - (void)setUp {10 scanner = [[AHHyperlinkScanner alloc] initWithStrictChecking:NO];11 }12 13 - (void)tearDown {14 [scanner release];15 }16 17 9 - (void)testInvalidURI { 18 10 testHyperlink(@"adium"); trunk/Frameworks/AutoHyperlinks Framework/UnitTests/SimpleURLTest.h
r23925 r24146 7 7 #import "AutoHyperlinks.h" 8 8 9 #define testHyperlink(x) STAssertTrue([ scanner isStringValidURL: x],\9 #define testHyperlink(x) STAssertTrue([AHHyperlinkScanner isStringValidURI: x usingStrict:NO fromIndex:0 withStatus:nil],\ 10 10 @"\"%@\" Should be a valid URI.", x ) 11 11 trunk/Frameworks/AutoHyperlinks Framework/UnitTests/SimpleURLTest.m
r23863 r24146 7 7 8 8 @implementation SimpleURLTest 9 10 - (void)setUp {11 scanner = [[AHHyperlinkScanner alloc] initWithStrictChecking:NO];12 }13 14 - (void)tearDown {15 [scanner release];16 }17 9 18 10 - (void)testURLOnly { trunk/Frameworks/AutoHyperlinks Framework/UnitTests/StressTest.m
r23513 r24146 17 17 STAssertNil(error, @"stringWithContentsOfFile:encoding:error: could not read file at path '%s': %@", TEST_URIS_FILE_PATHNAME, error); 18 18 19 AHHyperlinkScanner *scanner = [ [AHHyperlinkScanner alloc] initWithStrictChecking:NO];19 AHHyperlinkScanner *scanner = [AHHyperlinkScanner hyperlinkScannerWithString:stressString]; 20 20 NSAttributedString *attrString; 21 21 22 22 int i = 5; 23 23 while(i > 0) { 24 attrString = [scanner linkif yString:[[NSAttributedString alloc] initWithString:stressString]];24 attrString = [scanner linkifiedString]; 25 25 i--; 26 26 } trunk/Frameworks/AutoHyperlinks Framework/UnitTests/ThreadedStressTest.m
r23923 r24146 11 11 12 12 #define LOOP_COUNT 10 13 #define THREAD_COUNT 813 #define THREAD_COUNT 10 14 14 15 15 @implementation ThreadedStressTest 16 16 -(void) threadedStressTest 17 17 { 18 AHHyperlinkScanner *scanner = [[AHHyperlinkScanner alloc] initWithStrictChecking:NO];19 18 20 NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(performTestWithScanner:) object:scanner]; 21 NSThread *thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(performTestWithScanner:) object:scanner]; 22 NSThread *thread3 = [[NSThread alloc] initWithTarget:self selector:@selector(performTestWithScanner:) object:scanner]; 23 NSThread *thread4 = [[NSThread alloc] initWithTarget:self selector:@selector(performTestWithScanner:) object:scanner]; 24 NSThread *thread5 = [[NSThread alloc] initWithTarget:self selector:@selector(performTestWithScanner:) object:scanner]; 25 NSThread *thread6 = [[NSThread alloc] initWithTarget:self selector:@selector(performTestWithScanner:) object:scanner]; 26 NSThread *thread7 = [[NSThread alloc] initWithTarget:self selector:@selector(performTestWithScanner:) object:scanner]; 27 NSThread *thread8 = [[NSThread alloc] initWithTarget:self selector:@selector(performTestWithScanner:) object:scanner]; 19 NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(performLinkTest:) object:nil]; 20 NSThread *thread2 = [[NSThread alloc] initWithTarget:self s