/*
 * -------------------------------------------------------------------------
 * Copyright (C) 2005 TJ Saunders <tj@castaglia.org>
 *
 * 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.
 *
 * -------------------------------------------------------------------------
 *  $Id: regex.c,v 1.2 2005/10/08 21:29:45 tj Exp tj $
 */

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

#define PROGRAM		"regex"
#define MAX_MATCHES 10

#define FALSE 0
#define TRUE  1

int main(int argc, char *argv[]) {
  char string[1024] = {'\0'}, re_error[1024] = {'\0'};
  char *re_pattern = NULL, *ptr = NULL;
  regex_t *re_buf = NULL;
  regmatch_t re_matches[MAX_MATCHES];
  int res = -1, nsubs = 0;
  register unsigned int i = 0;
  long offset = 0, position = 0;
  unsigned char invert = FALSE, have_match = FALSE;

  if (argc-1 != 2) {
    fprintf(stderr,
      PROGRAM ": missing required parameters: <string> <pattern>\n");
    return -1;
  }

  memset(re_matches, '\0', sizeof(regmatch_t) * MAX_MATCHES);

  /* Allocate memory for a string.  It has to be an allocated string,
   * not a string literal (eg 'char *string = "blah"') so that the string
   * elements can be manipulated; string literals are read-only.
   */
  memset(string, '\0', sizeof(string));
  strncat(string, argv[1], sizeof(string));

  re_pattern = argv[2];

  /* Look for the "!" prefix. */
  if (*re_pattern == '!') {
    /* Reverse the expected return value from regexec. */
    invert = TRUE;

    re_pattern++;    
  }

  re_buf = (regex_t *) calloc(1, sizeof(regex_t));

  res = regcomp(re_buf, re_pattern, REG_EXTENDED);
  if (res != 0) {
    regerror(res, re_buf, re_error, 1024);
    regfree(re_buf);
    fprintf(stderr, PROGRAM ": error compiling pattern '%s': %s\n", re_pattern,
      re_error);

    return -1;
  }

  nsubs = re_buf->re_nsub + 1;
  fprintf(stdout, PROGRAM ": compiled pattern '%s' (%u %s)\n",
    re_pattern, nsubs, nsubs != 1 ? "expressions" : "expression");

  ptr = string;

  while ((res = regexec(re_buf, ptr, MAX_MATCHES, re_matches, 0)) == 0) {
    have_match = TRUE;

    for (i = 0; i < MAX_MATCHES; i++) {
      if (re_matches[i].rm_so != -1) {
        char tmp;
        long rm_so = re_matches[i].rm_so + position,
          rm_eo = re_matches[i].rm_eo + position;

        offset = re_matches[i].rm_eo;

        tmp = string[rm_eo];
        string[rm_eo] = '\0';

        fprintf(stdout, PROGRAM ": substring[%u]: '%s' [%ld-%ld]\n",
          i + 1, &string[rm_so], (long) rm_so, (long) rm_eo);

        string[rm_eo] = tmp;
      }
    }

    if (invert)
      break;

    if (i == 0)
      break;

    if (offset <= 0)
      offset = 1;

    position += offset;

    ptr = string + position;

    if (ptr > (string + strlen(string)) ||
        *ptr == '\0')
      break;

    fprintf(stdout, PROGRAM ": now comparing string '%s'\n", ptr);
  }

  regfree(re_buf);

  if (invert)
    have_match = !have_match;

  if (have_match) {
    fprintf(stdout, PROGRAM ": pattern '%s' matched string '%s'\n",
      argv[2], string);

  } else {
    fprintf(stdout, PROGRAM ": pattern '%s' did NOT match string '%s'\n",
      argv[2], string);
  }

  return 0;
}
