#include <stdio.h>
#include <string.h>
#include <regex.h>

regex_t regex;
#define MAX_MATCH 5
// This is the number of capture groups + 1
#define RESET "\x1b[0m"

int regmatch( regex_t *preg, const char * string, size_t nmatch, regmatch_t pmatch[], int eflags) {
    // returns number of matches found.  (Max nmatch)
    int matches = 0;
    int offset = 0;
    int ret;

    while (matches < nmatch) {
        ret = regexec( preg, string + offset, nmatch - matches, pmatch + matches, eflags);
        if (!ret) {
            int current = offset;
            offset += pmatch[matches].rm_eo;
            pmatch[matches].rm_so += current;
            pmatch[matches].rm_eo += current;
            matches++;
        } else if (ret == REG_NOMATCH ) {
            break;
        } else {
            break;
        }
    }
    return matches;
} 

const char * clean_string(const char * badansi) {
    static char buffer[1024];
    char * cp;

    strcpy(buffer, badansi);
    cp = buffer;
    while ( (cp = strstr(cp, "\x1b")) != NULL )
    {
        *cp = '~';
    };
    return buffer;
}

void test(const char * trythis) {
    regmatch_t regmatches[MAX_MATCH];
    int matches, x;
    const char * clean = clean_string(trythis);
    printf("TEST (%s)\n", clean);

    matches = regmatch(&regex, trythis, MAX_MATCH, regmatches, 0);
    if (matches == 0) {
        printf("No matches.\n");
    } else {
        printf("%d matches:\n", matches);
        for( x = 0; x < matches; x++) {
            printf("%d (%d - %d)\n", x, regmatches[x].rm_so, regmatches[x].rm_eo);
            printf("    %*s [%.*s]\n", regmatches[x].rm_so, "", regmatches[x].rm_eo - regmatches[x].rm_so, clean + regmatches[x].rm_so);
        }
    }
}

void test_( const char * trythis) {
    int ret;
    char msgbuf[100];
    const char * p = trythis;

    // safe printing (maybe)
    strcpy(msgbuf, trythis);
    char * fixup = msgbuf;
    while ( ( fixup = strstr(fixup, "\x1b") ) != NULL ) {
        *fixup = '^';
    };

    printf("Test: [%s]%s\n", msgbuf, RESET);

    regmatch_t matches[ MAX_MATCH ];
    while (1) {
        ret = regexec( &regex, p, MAX_MATCH, matches, 0 );

        if (!ret) {
            printf("MATCH!\n");
            for (int i = 0; i < MAX_MATCH; i++) {
                int start, finish;
                if (matches[i].rm_so == -1 )
                    break;

                start = matches[i].rm_so;
                finish = matches[i].rm_eo;
		// %.*s  = length to print, char * to use
                strncpy(msgbuf, p+start, (finish-start));
                msgbuf[finish-start] = 0;
                fixup = msgbuf;
                while ( ( fixup = strstr(fixup, "\x1b") ) != NULL ) {
                    *fixup = '^';
                };

                // printf("'%.*s'%s %d : %d - %d\n", (finish - start), p + start, RESET, i, start, finish);
                printf("'%s' %d : %d - %d\n", msgbuf, i, start, finish);
            };
            p += matches[0].rm_eo;
        }
        else if (ret == REG_NOMATCH) {
            printf("Sorry, no matches.\n");
            break;
        }
        else {
            regerror( ret, &regex, msgbuf, sizeof(msgbuf));
            fprintf(stderr, "Regex match failed: %s\n", msgbuf);
        }
    }
    return;
}

int main(int argc, char * argv[]) {
    // char RX[] = "(\x1b\[(?:\\d+|;)+[a-zA-Z])";
    //char RX[] = "([a-z][a-z]([0-9]+))";
    char RX[] = "([a-z][a-z]([0-9]+))";
    char msgbuf[100];
    int ret;

    if ( ret = regcomp( &regex, RX, REG_EXTENDED|REG_NEWLINE ) ) {
        regerror( ret, &regex, msgbuf, sizeof(msgbuf));
        fprintf(stderr, "Regex compile failed: %s\n", msgbuf);
        return 1;
    }

    test("this will fail.");
    test("this has ab5 ab55 zd3 three matches.");

    regfree(&regex);
    // if ( regcomp( &regex, "(\x1b\[(?:[0-9]|;)+[a-zA-Z])", REG_EXTENDED|REG_NEWLINE ) ) {
    // if ( regcomp( &regex, "(\x1b\[([0-9]+|;)+[a-zA-Z])", REG_EXTENDED|REG_NEWLINE ) ) {
    // if ( regcomp( &regex, "\x1b\[[0-9]+(;[0-9]+)+?[a-zA-Z]", REG_EXTENDED|REG_NEWLINE ) ) {
    if ( regcomp( &regex, "\x1b\[[0-9]+(;[0-9]+)*?[a-zA-Z]", REG_EXTENDED|REG_NEWLINE ) ) {
        regerror( ret, &regex, msgbuf, sizeof(msgbuf));
        fprintf(stderr, "Regex compile failed: %s\n", msgbuf);
        return 1;
    };

    test("\x1b[1;1H\x1b[2J\x0cMystic BBS\x1b[6n");
    test("\x1b[5;1HMEEP.");
    test("\x1b[0;1;34;47mHello");
    regfree(&regex);

    //   \s matches space, FORM FEED.  Ouch!  NO!

    if ( regcomp( &regex, "[a-zA-Z]+( [a-zA-Z]+)+", REG_EXTENDED|REG_NEWLINE ) ) {
        regerror( ret, &regex, msgbuf, sizeof(msgbuf));
        fprintf(stderr, "Regex compile failed: %s\n", msgbuf);
        return 1;
    };

    test("\x1b[1;1H\x1b[2J\x0cMystic BBS\x1b[6n");
    test("\x1b[5;1HMEEP is cool for cats.");
     
    regfree(&regex);
    return 0;
}