/*
 * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/exp.c,v 1.9 2004/04/30 13:41:56 aleigh Exp $ 
 */

/*
 * Copyright (c) 2004 Alex Leigh, All Rights Reserved
 * 
 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright
 * notice above does not evidence any actual or intended publication of such
 * source code.
 * 
 * Disclosure, copying, distribution, or transmission of of this code without
 * express permission is prohibited.
 */


#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <pthread.h>

#include "mecha.h"
#include "pcre.h"

#define OVECCOUNT 30            /* should be a multiple of 3 */

void expFregexp_free(expTregexp * re)
{
    pcre_free(re);
}

expTregexp *expFregexp_compile(const char *pattern)
{
    pcre *re;
    const char *error;
    int erroffset;

    re = pcre_compile(pattern,  /* the pattern */
                      0,        /* default options */
                      &error,   /* for error message */
                      &erroffset,       /* for error offset */
                      NULL);    /* use default character tables */
    return (expTregexp *) re;
}

int expFregexp_match(const expTregexp * regexp, const char *subject)
{
    return expFregexp_match_len(regexp, subject, strlen(subject));
}

/*
 * Parts of this code derived from code written by Henry Spencer.
 * 
 * The rest is written by Eric Lindvall.
 * 
 */
int expFregexp_replace(const expTregexp * regexp, const char *subject,
                       size_t subject_length, const char *replace,
                       MECHA_UNUSED_ARGUMENT size_t replace_length, char *output,
                       size_t output_length)
{
    pcre *re = (pcre *) regexp;
    int ovector[OVECCOUNT];
    int rc;
    register const char *src;
    register char *dst;
    register char c;

    rc = pcre_exec((pcre *) re, /* the compiled pattern */
                   NULL,        /* no extra data - we didn't study the
                                 * pattern */
                   subject,     /* the subject string */
                   subject_length,      /* the length of the subject */
                   0,           /* start at offset 0 in the subject */
                   0,           /* default options */
                   ovector,     /* output vector for substring information */
                   OVECCOUNT);  /* number of elements in the output vector */

    if (rc < 0) {
        switch (rc) {
        case PCRE_ERROR_NOMATCH:
            return 0;
        default:
            return -1;
        }
    }
    
    src = replace;
    dst = output;

    while ((c = *src++) != '\0' && output_length > 0) {
        register int no;

        if (c == '&') {
            no = 0;
        } else if ((c == '\\' || c == '$') && '0' <= *src && *src <= '9') {
            no = *src++ - '0';
        } else {
            no = -1;
        }

        if (no < 0) {           /* Ordinary character. */
            if (c == '\\' && (*src == '\\' || *src == '&')) {
                c = *src++;
            }
            *dst++ = c;
            output_length--;
        } else if (no <= rc) {
            int len =
                pcre_copy_substring(subject, ovector, rc, no, dst,
                                    output_length);

            if (len < 0) {
                return (len);
            }
            output_length -= len;
            dst += len;
        }
    }

    if (output_length < 1) {
        return (-1);
    }
    *dst++ = '\0';
    output_length--;

    return 1;
}

int expFregexp_match_len(const expTregexp * regexp, const char *subject,
                         size_t subject_length)
{
    pcre *re = (pcre *) regexp;
    int ovector[OVECCOUNT];
    int rc;

    rc = pcre_exec((pcre *) re, /* the compiled pattern */
                   NULL,        /* no extra data - we didn't study the
                                 * pattern */
                   subject,     /* the subject string */
                   subject_length,      /* the length of the subject */
                   0,           /* start at offset 0 in the subject */
                   0,           /* default options */
                   ovector,     /* output vector for substring information */
                   OVECCOUNT);  /* number of elements in the output vector */

    if (rc < 0) {
        switch (rc) {
        case PCRE_ERROR_NOMATCH:
            return 0;
        default:
            return -1;
        }
    }
    return 1;
}

int expFmatch(const char *pattern, const char *subject)
{

    assert(pattern!=NULL);
    assert(subject!=NULL);

    return expFmatch_len(pattern, subject, strlen(subject));
}

int expFmatch_len(const char *pattern, const char *subject,
                  size_t subject_length)
{
    pcre *re;
    const char *error;
    int erroffset;
    int ovector[OVECCOUNT];
    int rc;

    assert(pattern!=NULL);
    assert(subject!=NULL);
    
    /*************************************************************************
    * Now we are going to compile the regular expression pattern, and handle *
    * and errors that are detected.                                          *
    *************************************************************************/

    re = pcre_compile(pattern,  /* the pattern */
                      0,        /* default options */
                      &error,   /* for error message */
                      &erroffset,       /* for error offset */
                      NULL);    /* use default character tables */

    if (re == NULL) {
        return -1;
    }
    
    /*************************************************************************
    * If the compilation succeeded, we call PCRE again, in order to do a     *
    * pattern match against the subject string. This just does ONE match. If *
    * further matching is needed, it will be done below.                     *
    *************************************************************************/

    rc = pcre_exec(re,          /* the compiled pattern */
                   NULL,        /* no extra data - we didn't study the
                                 * pattern */
                   subject,     /* the subject string */
                   subject_length,      /* the length of the subject */
                   0,           /* start at offset 0 in the subject */
                   0,           /* default options */
                   ovector,     /* output vector for substring information */
                   OVECCOUNT);  /* number of elements in the output vector */

    pcre_free(re);

    if (rc < 0) {
        switch (rc) {
        case PCRE_ERROR_NOMATCH:
            return 0;
        default:
            return -1;
        }
    }
    return 1;
}

int expFapply(const char *pattern, const char *subject, lstTset * output)
{
    pcre *re;
    const char *error;
    int erroffset;
    int ovector[OVECCOUNT];
    int subject_length;
    int rc, i;

    assert(pattern != NULL);
    assert(subject != NULL);
    assert(output != NULL);

    subject_length = (int) strlen(subject);

    /*************************************************************************
    * Now we are going to compile the regular expression pattern, and handle *
    * and errors that are detected.                                          *
    *************************************************************************/

    re = pcre_compile(pattern,  /* the pattern */
                      0,        /* default options */
                      &error,   /* for error message */
                      &erroffset,       /* for error offset */
                      NULL);    /* use default character tables */

    /* Compilation failed: print the error message and exit */

    if (re == NULL) {
        return -1;
    }
    /*************************************************************************
    * If the compilation succeeded, we call PCRE again, in order to do a     *
    * pattern match against the subject string. This just does ONE match. If *
    * further matching is needed, it will be done below.                     *
    *************************************************************************/

    rc = pcre_exec(re,          /* the compiled pattern */
                   NULL,        /* no extra data - we didn't study the
                                 * pattern */
                   subject,     /* the subject string */
                   subject_length,      /* the length of the subject */
                   0,           /* start at offset 0 in the subject */
                   0,           /* default options */
                   ovector,     /* output vector for substring information */
                   OVECCOUNT);  /* number of elements in the output vector */

    /* Matching failed: handle error cases */

    if (rc < 0) {
        switch (rc) {
        case PCRE_ERROR_NOMATCH:
            return 0;
        default:
            return -1;
        }
    }
    
    /*************************************************************************
    * We have found the first match within the subject string. If the output *
    * vector wasn't big enough, set its size to the maximum. Then output any *
    * substrings that were captured.                                         *
    *************************************************************************/

    /* The output vector wasn't big enough */

    if (rc == 0) {
        rc = OVECCOUNT / 3;
        /* Output vector not big enough */
        return -2;
    }
    /*
     * Show substrings stored in the output vector by number. Obviously, in a
     * real application you might want to do things other than print them.
     */

    for (i = 0; i < rc; i++) {
        char *substring_start = (char *) subject + ovector[2 * i];
        int substring_length = ovector[2 * i + 1] - ovector[2 * i];
        char back;

        logFmsg(3, "length is %d", substring_length);

        back = substring_start[substring_length + 1];
        substring_start[substring_length + 1] = '\0';

        lstFset_add(output, utlFshort_to_str(i), substring_start);

        substring_start[substring_length + 1] = back;

        /* printf("%2d: %.*s\n", i, substring_length, substring_start); */

    }

    return 1;
}
