/*

  pgp server people - try not to look in this code please!  It was something
  I had around for another project under development, and it was useful
  enough to pinch for the pgp key server.  However the code is an abomination
  and I'd rather people just worked on the pgp*.c modules.  -- gtoal@gtoal.com


 */
 
#ifdef DBMAIN
#define SUPPLY_SCAN_REGERROR
#define DEBUG
#endif

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

#include "sscanr.h"
#include "regexp.h"

#ifndef TRUE
#define TRUE (0==0)
#endif

#ifndef FALSE
#define FALSE (0!=0)
#endif

#ifdef SUPPLY_SCAN_REGERROR
void regerror(char *s)
{
  fprintf(stderr, "sscanr: %s\n", s);
}
#endif

/* Remove trailing spaces from s - maybe useful later to
   also remove leading spaces, and conflate multiple
   spaces into one.  We'll do it if needed... */
int trim(char *s)
{
  int i = strlen(s);
  while (i > 0) {
    i -= 1;
    if (s[i] == ' ') {
      s[i] = '\0';
    } else break;
  }
}

static unsigned char *savepattern = NULL;
static int savepatternallocsize = 0;
static unsigned char *savedata = NULL;
static int savedataallocsize = 0;
static regexp *saver = NULL;

/* Returns TRUE or FALSE */
int sscanr(
  char *pattern, char *data,
  char *extractpattern, char *result)
{
  regexp *r;
  int i;
  if (pattern == NULL && data == NULL &&
      extractpattern == NULL && result == NULL) {
    /* A special for conscientious users to clean up with */
    if (saver != NULL) {
#ifdef DEBUG
      fprintf(stderr, "free(r)\n");
#endif
      free(saver); saver = NULL;
    }
    if (savepattern != NULL) {
#ifdef DEBUG
      fprintf(stderr, "free(\"%s\")\n", savepattern);
#endif
      free(savepattern); savepattern = NULL; savepatternallocsize = 0;
    }
    if (savedata != NULL) {
#ifdef DEBUG
      fprintf(stderr, "free(\"%s\")\n", savedata);
#endif
      free(savedata); savedata = NULL; savedataallocsize = 0;
    }
    return(TRUE);
  }
  if (pattern == NULL) {
    regerror("Invalid NULL pattern argument");
    return(FALSE);
  }
  if (data == NULL) {
    regerror("Invalid NULL data argument");
    return(FALSE);
  }
  if (*pattern == '\0') {
    if (*data == '\0') return(TRUE); /* I guess we can allow "" to match "" */
    regerror("Invalid empty pattern argument");
    return(FALSE);
  }
  if (savepattern != NULL && strcmp(pattern, (char *)savepattern) == 0) {
    /* A strcmp is much cheaper than a regcomp */
    r = saver;
    if (savedata != NULL && strcmp(data, (char *)savedata) == 0) {
      /* And *definitely* much much cheaper than a regexec */
      i = TRUE;
    } else {
      /* I *hope* a previous regexec hasn't undone anything in the regcomp */
#ifdef DEBUG
      fprintf(stderr, "regexec(r, \"%s\")\n", data);
#endif
      i = regexec(r, data);
    }
  } else {
    if (saver != NULL) {
#ifdef DEBUG
      fprintf(stderr, "free(r)\n");
#endif
      free(saver); saver = NULL;
    }
#ifdef DEBUG
    fprintf(stderr, "r = regcomp(\"%s\")\n", pattern);
#endif
    saver = r = regcomp(pattern);
    if (savepattern != NULL && savepatternallocsize < strlen(pattern)+1) {
#ifdef DEBUG
      fprintf(stderr, "free(\"%s\")\n", savepattern);
#endif
      free(savepattern); savepattern = NULL; savepatternallocsize = 0;
    }
    if (savepattern == NULL) {
      savepatternallocsize = strlen(pattern)+1;
      savepattern = malloc(savepatternallocsize);
      if (savepattern == NULL) {
        regerror("cannot malloc pattern string cache");
        return(FALSE);
      }
#ifdef DEBUG
      fprintf(stderr, "malloc(\"%s\")\n", pattern);
#endif
    }
    strcpy((char *)savepattern, pattern);
#ifdef DEBUG
      fprintf(stderr, "save(\"%s\")\n", pattern);
#endif
    if (savedata != NULL && savedataallocsize < strlen(data)+1) {
#ifdef DEBUG
      fprintf(stderr, "free(\"%s\")\n", savedata);
#endif
      free(savedata); savedata = NULL; savedataallocsize = 0;
    }
    if (savedata == NULL) {
      savedataallocsize = strlen(data)+1;
      savedata = malloc(savedataallocsize);
      if (savedata == NULL) {
        regerror("cannot malloc data string cache");
        return(FALSE);
      }
#ifdef DEBUG
      fprintf(stderr, "malloc(\"%s\")\n", data);
#endif
    }
    strcpy((char *)savedata, data);
#ifdef DEBUG
      fprintf(stderr, "save(\"%s\")\n", data);
#endif
#ifdef DEBUG
    fprintf(stderr, "i = regexec(\"%s\")\n", data);
#endif
    i = regexec(r, data);
  }
  if (i && extractpattern && result) {
#ifdef DEBUG
    fprintf(stderr, "i = regsub(r, \"%s\", result)\n", extractpattern);
#endif
    i = regsub(r, extractpattern, result);
  }
  return(i);
}

#ifdef DBMAIN
int main(int argc, char **argv)
{
  char numstr[128];
  char line[128];
  char pattern[128];
  char *s;
  
  for (;;) {
    fprintf(stderr, "regexp: "); fflush(stderr);
    if (fgets(pattern, 128, stdin) == NULL) break;
    if ((s = strchr(pattern, '\n')) != NULL) *s = '\0'; 
    fprintf(stderr, "text:   "); fflush(stderr);
    if (fgets(line, 128, stdin) == NULL) break;
    if ((s = strchr(line, '\n')) != NULL) *s = '\0'; 
    if (sscanr(pattern, line, "\\0", numstr)) {
      fprintf(stdout, "Yep, '%s' fits!\n", numstr);
    } else {
      fprintf(stderr, "Nope, no joy from '%s'\n", line);
    }
  }
  (void)sscanr(NULL, NULL, NULL, NULL);
  exit(0);
  return(1);
}
#endif
