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.