This is NSString+MessageUtils.m in view mode; [Download] [Up]
//--------------------------------------------------------------------------------------- // NSString+MessageUtils.m created by erik on Sun 23-Mar-1997 // This code is part of the Alexandra Newsreader Project. For copyright details see // GNU public license version 2 or above. No warranties implied. Use at own risk. // More information can be found at <http://www.object-factory.com/Alexandra>. // @(#)$Id: NSString+MessageUtils.m,v 1.4 1998/09/28 12:28:41 erik Exp $ //--------------------------------------------------------------------------------------- #import "Utilities.h" #import "NSString+MessageUtils.h" //--------------------------------------------------------------------------------------- @implementation NSString(MessageUtilities_Alexandra) //--------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------- // STANDARD STUFF //--------------------------------------------------------------------------------------- - (NSString *)stringByRemovingSurroundingWhitespace { static NSCharacterSet *iwsSet = nil; NSRange start, end, result; if(iwsSet == nil) iwsSet = [[[NSCharacterSet whitespaceCharacterSet] invertedSet] retain]; start = [self rangeOfCharacterFromSet:iwsSet]; if(start.length == 0) return @""; // string is empty or consists of whitespace only end = [self rangeOfCharacterFromSet:iwsSet options:NSBackwardsSearch]; if((start.location == 0) && (end.location == [self length] - 1)) return self; result = NSMakeRange(start.location, end.location + end.length - start.location); return [self substringWithRange:result]; } //--------------------------------------------------------------------------------------- // EXTRACTING SUBSRUCTURES //--------------------------------------------------------------------------------------- - (BOOL)isValidArticleID; { return [self hasPrefix:@"<"] && [self hasSuffix:@">"] && ([self rangeOfString:@"@"].length != 0); } - (NSString *)getURLFromArticleID; { NSScanner *scanner; NSString *articleId; scanner = [NSScanner scannerWithString:self]; if([scanner scanString:@"<" intoString:NULL]) if([scanner scanUpToString:@">" intoString:&articleId]) return [NSString stringWithFormat:@"news:%@", articleId]; return nil; } - (NSString *)realnameFromEMailAddress; { static NSCharacterSet *skipChars = nil; NSRange charPos, char2Pos, nameRange; if(skipChars == nil) skipChars = [[NSCharacterSet characterSetWithCharactersInString:@"\"' "] retain]; if((charPos = [self rangeOfString:@"@"]).length == 0) { nameRange = NSMakeRange(0, [self length]); } else if((charPos = [self rangeOfString:@"<"]).length > 0) { nameRange = NSMakeRange(0, charPos.location); } else if((charPos = [self rangeOfString:@"("]).length > 0) { char2Pos = [self rangeOfString:@")"]; if((char2Pos.length > 0) && (char2Pos.location > charPos.location)) nameRange = NSMakeRange(charPos.location + 1, char2Pos.location - charPos.location - 1); else nameRange = NSMakeRange(0, [self length]); } else { nameRange = NSMakeRange(0, [self length]); } while((nameRange.length > 0) && [skipChars characterIsMember:[self characterAtIndex:nameRange.location]]) { nameRange.location += 1; nameRange.length -= 1; } while((nameRange.length > 0) && [skipChars characterIsMember:[self characterAtIndex:nameRange.location + nameRange.length - 1]]) { nameRange.length -= 1; } return [self substringWithRange:nameRange]; } //--------------------------------------------------------------------------------------- // TRIM ID LISTS //--------------------------------------------------------------------------------------- - (NSArray *)messageIDsFromFieldBody; { NSRange gluedIDRange; NSMutableString *temp; NSMutableArray *list; int i; NSString *refs, *articleID; // this is not really efficient, but it works fairly well even with badly // mangled headers and we usually only work with small numbers of elements. // first pass: some agents don't put blanks between the references. if((gluedIDRange = [self rangeOfString:@"><"]).length > 0) { temp = [[self mutableCopy] autorelease]; while((gluedIDRange = [temp rangeOfString:@"><"]).length > 0) [temp insertString:@" " atIndex:gluedIDRange.location + 1]; refs = temp; } else { refs = self; } // second pass: we remove all invalid ids and all "empty" ids (resulting from // more than one space inbetween.) list = [NSMutableArray arrayWithArray:[refs componentsSeparatedByString:@" "]]; for(i = [list count] - 1; i >= 0; i--) { articleID = [list objectAtIndex:i]; if([articleID isValidArticleID] == NO) [list removeObjectAtIndex:i]; } return list; } /* we should be able to pass in a list of ids that must not be removed (because they appear in the body) */ + (NSString *)fieldBodyFromMesageIDs:(NSArray *)idList maxLength:(unsigned int)length; { NSMutableArray *newList; unsigned int newLength; int i, n; if((n = [idList count]) == 0) return @""; newList = [NSMutableArray arrayWithArray:idList]; newLength = -1; // first id doesn't have a leading space... for(i = 0; i < [idList count]; i++) newLength += [[idList objectAtIndex:i] length] + 1; // one for space // we remove ids until the resulting string is short enough. note that // the first and the last three ids are not deleted even if the string // remains too long. (cf. son-of-1036) while(newLength > length) { if([newList count] < 5) return nil; newLength -= [[newList objectAtIndex:1] length] + 1; [newList removeObjectAtIndex:1]; } return [newList componentsJoinedByString:@" "]; } - (NSString *)stringByTrimmingReferencesToLength:(unsigned int)maxLength; { return [NSString fieldBodyFromMesageIDs:[self messageIDsFromFieldBody] maxLength:maxLength]; } //--------------------------------------------------------------------------------------- // CONVERSIONS //--------------------------------------------------------------------------------------- - (NSString *)stringByApplyingROT13; { NSString *result; unsigned int length, i; unichar *buffer, *cp; length = [self length]; buffer = NSZoneMalloc([self zone], length * sizeof(unichar)); [self getCharacters:buffer range:NSMakeRange(0, length)]; for(i = 0, cp = buffer; i < length; i++, cp++) if((*cp >= (unichar)'a') && (*cp <= (unichar)'z')) *cp = (((*cp - 'a') + 13) % 26) + 'a'; else if((*cp >= (unichar)'A') && (*cp <= (unichar)'Z')) *cp = (((*cp - 'A') + 13) % 26) + 'A'; result = [NSString stringWithCharacters:buffer length:length]; NSZoneFree([self zone], buffer); return result; } //--------------------------------------------------------------------------------------- // REFORMATTING //--------------------------------------------------------------------------------------- - (NSString *)stringByUnwrappingParagraphs; { NSCharacterSet *forceBreakSet, *separatorSet; NSMutableString *buffer; NSEnumerator *lineEnum; NSString *currentLine, *nextLine; separatorSet = [NSCharacterSet characterSetWithCharactersInString:@" -\t"]; forceBreakSet = [NSCharacterSet characterSetWithCharactersInString:@" \t.?!:-·1234567890>}#%|"]; buffer = [[[NSMutableString allocWithZone:[self zone]] init] autorelease]; lineEnum = [[self componentsSeparatedByString:@"\n"] objectEnumerator]; currentLine = [lineEnum nextObject]; while((nextLine = [lineEnum nextObject]) != nil) { [buffer appendString:currentLine]; // if any of these conditions isn't met we don't unwrap if(([currentLine isEqualToString:@""]) || ([nextLine isEqualToString:@""]) || ([currentLine length] < 55) || ([forceBreakSet characterIsMember:[nextLine characterAtIndex:0]])) { [buffer appendString:@"\n"]; } // if the line didn't end with a whitespace or hyphen we insert a space else if([separatorSet characterIsMember:[currentLine characterAtIndex:[currentLine length] - 1]] == NO) { [buffer appendString:@" "]; } currentLine = nextLine; } [buffer appendString:currentLine]; return buffer; } - (NSString *)stringByWrappingToLineLength:(unsigned int)length; { NSCharacterSet *breakSet, *textSet; NSMutableString *buffer; NSEnumerator *lineEnum; NSString *originalLine, *prefix, *spillOver, *lastPrefix; NSMutableString *mcopy; NSRange textStart, endOfLine; unsigned int lineStart, nextLineStart, prefixLength; breakSet = [NSCharacterSet characterSetWithCharactersInString:@" \t-"]; textSet = [[NSCharacterSet characterSetWithCharactersInString:@" \t>}#%|"] invertedSet]; buffer = [[[NSMutableString allocWithZone:[self zone]] init] autorelease]; spillOver = nil; lineEnum = [[self componentsSeparatedByString:@"\n"] objectEnumerator]; while((originalLine = [lineEnum nextObject]) != nil) { if((textStart = [originalLine rangeOfCharacterFromSet:textSet]).length == 0) textStart.location = [originalLine length]; prefix = [originalLine substringToIndex:textStart.location]; prefixLength = textStart.location; lineStart = textStart.location; if(spillOver != nil) if(([lastPrefix isEqualToString:prefix] == NO) || (textStart.length == 0)) { [buffer appendAsLine:spillOver withPrefix:lastPrefix]; } else { originalLine = mcopy = [[originalLine mutableCopy] autorelease]; [mcopy insertString:@" " atIndex:lineStart]; [mcopy insertString:spillOver atIndex:lineStart]; } // note that this doesn't work properly if length(prefix) > length!, so... NSAssert(prefixLength <= length, @"line prefix too long."); if([originalLine length] - lineStart > length - prefixLength) { do { endOfLine = [originalLine rangeOfCharacterFromSet:breakSet options:NSBackwardsSearch range:NSMakeRange(lineStart, length - prefixLength)]; if(endOfLine.length > 0) { if([originalLine characterAtIndex:endOfLine.location] == (unichar)'-') endOfLine.location += 1; nextLineStart = endOfLine.location; while((nextLineStart < [originalLine length]) && ([originalLine characterAtIndex:nextLineStart] == (unichar)' ')) nextLineStart += 1; } else { endOfLine = [originalLine rangeOfComposedCharacterSequenceAtIndex:lineStart + length - prefixLength]; nextLineStart = endOfLine.location; } [buffer appendAsLine:[originalLine substringWithRange:NSMakeRange(lineStart, endOfLine.location - lineStart)] withPrefix:prefix]; lineStart = nextLineStart; } while([originalLine length] - lineStart > length - prefixLength); spillOver = [originalLine substringFromIndex:lineStart]; } else { [buffer appendString:originalLine]; [buffer appendString:@"\n"]; spillOver = nil; } lastPrefix = prefix; } if(spillOver != nil) [buffer appendAsLine:spillOver withPrefix:lastPrefix]; return buffer; } - (NSString *)stringByPrefixingLinesWithString:(NSString *)prefix; { NSMutableString *buffer; NSEnumerator *lineEnum; NSString *line; buffer = [[[NSMutableString allocWithZone:[self zone]] init] autorelease]; lineEnum = [[self componentsSeparatedByString:@"\n"] objectEnumerator]; while((line = [lineEnum nextObject]) != nil) { [buffer appendAsLine:line withPrefix:prefix]; } return buffer; } //--------------------------------------------------------------------------------------- @end //--------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------- @implementation NSMutableString(MessageUtilities_Alexandra) //--------------------------------------------------------------------------------------- - (void)appendAsLine:(NSString *)line withPrefix:(NSString *)prefix { [self appendString:prefix]; [self appendString:line]; [self appendString:@"\n"]; } //--------------------------------------------------------------------------------------- @end //---------------------------------------------------------------------------------------
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.