#import "NSString+Regex.h"
#include <regex.h>

@implementation NSString (Regex)

static void raise_reg_error_exception(const char* name, int errorcode, regex_t* regex) {
    NSMutableData*  errorString = [NSMutableData data];
    
    [errorString setLength:regerror(errorcode, regex, NULL, 0)];

    size_t errorSize = regerror(errorcode, regex, [errorString mutableBytes], [errorString length]);

    regfree(regex);

    NSCAssert2(errorSize == [errorString length],
               @"Unexpected size in raise_reg_error_exception: %d, %d",
               errorSize, [errorString length]);

    [NSException raise: NSInvalidArgumentException
                format: @"%s: %s", name, [errorString bytes]];
}
- (NSArray *) findRegularExpression:(NSString *)re ignoreCase:(BOOL)ignoreCase; {
    regex_t regex;
    int regCompFlags = REG_EXTENDED;
    int regExecFlags = 0;
    int err = 0;

    //NSLog(@"@\"%@\": findRegularExpression:@\"%@\" ignoreCase:%s", self, re, (ignoreCase ? "YES" : "NO"));

    if (ignoreCase)
    {
        regCompFlags |= REG_ICASE;
    }

    // Compile the regular expression
    if ((err = regcomp(&regex, [re UTF8String], regCompFlags)) != 0)
    {
        // Failed to compile the RE, issue a diagnostic message
        raise_reg_error_exception("regcomp", err, &regex);
        return nil;
    }

    //NSLog(@"match count: %d", 1 + regex.re_nsub);

    NSMutableData*  matchData = [NSMutableData dataWithCapacity: (1 + regex.re_nsub) * sizeof (regmatch_t)];
    regmatch_t*     matches   = [matchData mutableBytes];

    // Execute the compiled regular expression
    if ((err = regexec(&regex, [self UTF8String], 1 + regex.re_nsub, matches, regExecFlags)) != 0)
    {
        if (err != REG_NOMATCH)
        {
            raise_reg_error_exception("regexec", err, &regex);
        }

        // The "nil" return indicates there was no match.  No need for a diagnostic.
        regfree(&regex);
        return nil;
    }

    // Place the matches in an array and return them
    NSMutableArray *matchArray = [NSMutableArray arrayWithCapacity: 1 + regex.re_nsub];
    int m;

    for (m = 0; m <= regex.re_nsub; m++)
    {
        if (matches[m].rm_so == -1)
        {
            [matchArray addObject: [NSNull null]];
        }
        else
        {
            NSRange matchRange = NSMakeRange(matches[m].rm_so, (matches[m].rm_eo - matches[m].rm_so));
            
            [matchArray addObject:[self substringWithRange:matchRange]];
        }
    }

    regfree(&regex);

    return matchArray;
}

@end