/* ** PCREParser.m ** ** Copyright (c) 2002, 2003 ** ** Author: Yen-Ju Chen ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "PCREParser.h" @implementation RangeObject - (id) init { self = [super init]; [self setLocation: NSNotFound]; [self setLength: 0]; return self; } - (unsigned int) location { return _location; } - (void) setLocation: (unsigned int) location; { _location = location; } - (unsigned int) length { return _length; } - (void) setLength: (unsigned int) length; { _length = length; } - (NSRange) range; { NSRange _range = NSMakeRange(_location, _length); return _range; } - (void) setRange: (NSRange) range; { [self setLocation: range.location]; [self setLength: range.length]; } - (NSString *) description { return [NSString stringWithFormat: @"location = %u, length = %u", _location, _length]; } @end static NSMutableDictionary *patternsCache; @implementation PCREPattern + (PCREPattern *) pcrePattern: (NSString *) pattern { id object; if (patternsCache == nil) { patternsCache = [NSMutableDictionary new]; } if ((object = [patternsCache objectForKey: pattern])) { return object; } object = [[PCREPattern alloc] initWithPattern: pattern options: PCRE_STUDY]; [patternsCache setObject: object forKey: pattern]; return AUTORELEASE(object); } - (void) dealloc { pcre_free([self pattern]); pcre_free([self patternExtra]); [super dealloc]; } - (id) initWithPattern: (NSString *) pattern options: (unsigned int) mask { self = [super init]; _mask = 0; if (mask & NSCaseInsensitiveSearch) { _mask |= PCRE_CASELESS; } if (mask & NSAnchoredSearch) { _mask |= PCRE_ANCHORED; } _pcre = pcre_compile([pattern cString], _mask, &error, &erroffset, NULL); if (_pcre == NULL) { NSLog(@"PCRE compilation failed at offset %d: %s", erroffset, error); } if (mask & PCRE_STUDY) { _pcreExtra = pcre_study(_pcre, 0, &error); if (_pcreExtra == NULL) { if (error != NULL) NSLog(@"PCRE study failed: %s", error); } } return self; } - (pcre *) pattern { return _pcre; } - (pcre_extra *) patternExtra { return _pcreExtra; } /** Don't count the full match string. * Ex. "(dog|cat)" will return 1, "dog|cat" will return 0 */ - (int) numberOfSubpattern { int result, number; result = pcre_fullinfo(_pcre, _pcreExtra, PCRE_INFO_CAPTURECOUNT, &number); if (result != 0) return 0; return number; } @end @implementation PCREParser + (NSRange) rangeOfString:(NSString *) pattern inString: (NSString *) string { return [PCREParser rangeOfString: pattern inString: string range: NSMakeRange(0, [string length])]; } + (NSRange) rangeOfPattern: (PCREPattern *) pattern inString: (NSString *) string { return [PCREParser rangeOfPattern: pattern inString: string range: NSMakeRange(0, [string length])]; } + (NSRange) rangeOfString: (NSString *) pattern inString: (NSString *) string range: (NSRange) range; { return [PCREParser rangeOfPattern: [PCREPattern pcrePattern: pattern] inString: string range: range]; } + (NSRange) rangeOfPattern: (PCREPattern *) pattern inString: (NSString *) string range: (NSRange) range { int result; int location, length; int mask = 0; int ovector[3]; NSAssert(range.location != NSNotFound, @"\nRange can't be NSNotFound"); NSAssert(range.location + range.length <= [string length], @"\nRange can't longer than string length"); NSAssert(range.location >= 0, @"\nRange can't less than 0"); /* Considering the situation of beginning line */ if (range.location != 0) mask = mask | PCRE_NOTBOL; if ((range.location + range.length) != [string length]) mask = mask | PCRE_NOTEOL; result = pcre_exec([pattern pattern], [pattern patternExtra], [string cString], NSMaxRange(range), range.location, 0, ovector, 3); if (result < 0) { return NSMakeRange(NSNotFound, 0); } location = ovector[0]; length = ovector[1]-ovector[0]; NSAssert (length >= 1, @"\nRegEx can't return null string"); return NSMakeRange(location, length); } #if 0 - (id) initWithPattern: (NSString *) string options: (unsigned int)mask { PCREPattern *pattern = [[PCREPattern alloc] initWithPattern: string options: mask]; return [self initWithPattern: pattern]; } - (id) initWithPattern: (PCREPattern *) pattern { self = [super init]; ASSIGN(_pattern, pattern); _string = nil; _range = NSMakeRange(NSNotFound, 0); _originalRange = NSMakeRange(NSNotFound, 0); _lastMatch = NSMakeRange(NSNotFound, 0); return self; } - (void) dealloc { RELEASE(_pattern); RELEASE(_string); [super dealloc]; } - (PCREPattern *) pattern { return _pattern; } - (void) setString: (NSString *)string range: (NSRange) range { ASSIGN(_string, string); _originalRange = range; [self reset]; } - (NSString *) string { return _string; } - (NSRange) range { return _originalRange; } - (void) reset { _range = _originalRange; _lastMatch = NSMakeRange(NSNotFound, 0); } - (NSRange) rangeOfNextMatch { NSRange range; if (_lastMatch.location != NSNotFound) // Not a first match { _range.location = NSMaxRange(_lastMatch) + 1; _range.length = NSMaxRange(_originalRange) - _range.location; if (_range.location > NSMaxRange(_originalRange)) // The end of string { return NSMakeRange(NSNotFound,0); } } range = [[self string] rangeOfPattern: _pattern range: _range]; if (range.location != NSNotFound) { _lastMatch = range; } return range; } - (NSRange) rangeOfPreviousMatch { NSRange range; if (_lastMatch.location != NSNotFound) // Not a first match { _range.location = _originalRange.location; _range.length = _lastMatch.location - _originalRange.location + 1; } range = [[self string] rangeOfLastPattern: _pattern range: _range]; if (range.location != NSNotFound) { _lastMatch = range; } return range; } - (NSString *) stringOfNextMatch { NSRange range; range = [self rangeOfNextMatch]; if (range.location == NSNotFound) return nil; return [[self string] substringFromRange: range]; } - (NSString *) stringOfPreviousMatch { NSRange range; range = [self rangeOfPreviousMatch]; if (range.location == NSNotFound) return nil; return [[self string] substringFromRange: range]; } - (NSArray *) rangesOfNextSubpattern { NSRange range = [self rangeOfNextMatch]; NSArray *rangeArray = [[self string] rangesOfSubpattern: _pattern range: range]; return rangeArray; } - (NSArray *) rangesOfPreviousSubpattern { NSRange range = [self rangeOfPreviousMatch]; NSArray *rangeArray = [[self string] rangesOfSubpattern: _pattern range: range]; return rangeArray; } - (NSArray *) stringsOfNextSubpattern { int i, count; NSRange range; NSMutableArray *stringArray = [NSMutableArray new]; NSArray *rangeArray = [self rangesOfNextSubpattern]; RETAIN(rangeArray); count = [rangeArray count]; for (i = 0; i < count; i++) { range = [[rangeArray objectAtIndex: i] range]; if (range.location == NSNotFound) [stringArray addObject: @""]; else [stringArray addObject: [[self string] substringFromRange: range]]; } RELEASE(rangeArray); AUTORELEASE(stringArray); return stringArray; } - (NSArray *) stringsOfPreviousSubpattern { int i, count; NSRange range; NSMutableArray *stringArray = [NSMutableArray new]; NSArray *rangeArray = [self rangesOfPreviousSubpattern]; RETAIN(rangeArray); count = [rangeArray count]; for (i = 0; i < count; i++) { range = [[rangeArray objectAtIndex: i] range]; if (range.location == NSNotFound) [stringArray addObject: @""]; else [stringArray addObject: [[self string] substringFromRange: range]]; } RELEASE(rangeArray); AUTORELEASE(stringArray); return stringArray; } #endif @end