/*----------------------------------------------------------------
   Functions which patterns and extract from strings the portion which
   matches wild cards in the partterns. The extracted portions
   may also be substituted for tokens in other strings.

   Development History:
      Begun: 05/09/94 - Todd King

   Version:
      @(#)p_part.c	1.2   (UCLA/IGPP)    09 May 1994
------------------------------------------------------------------*/
#include "pattern.h"
#include <string.h>	/* for strdup() */
#include <stdio.h>	/* for printf() */
#include <ctype.h>	/* for isdigit() */
#include <malloc.h>	/* For free() and calloc() */
#include <stdlib.h>	/* For atoi() */

/*----------------------------------------------------------------
  Frees a part link list and all memory allocated on behalf of the
  list.

  Entry Requirements:
     part : A link list of type PATTERN_PART to be freed.
------------------------------------------------------------------*/
pattern_part_free(part)
PATTERN_PART	*part;
{
   PATTERN_PART	*next;
   PATTERN_PART	*p;

   for(p = part; p != NULL; p = next) {
      free(p->text);
      next = p->next;
      free(p);
   } 
   return(1);

}

/*----------------------------------------------------------------
  Adds a new PATTERN_PART structure to the end of a PATTER_PART 
  link list. The PATTERN_PART structure is seeded with the given 
  value.

  Entry Requirements:
     part : The PATTERN_PART link list to add a new item to the end.
	    If 'part' is NULL a new list is created.
     string : The text to seed the added item with.

  Return Value:
     A pointer to the head of the link list.
------------------------------------------------------------------*/
PATTERN_PART *
pattern_part_push(part, string)
PATTERN_PART	*part;
char	*string;
{
   PATTERN_PART	*p;
   PATTERN_PART	*tmp;

   p = (PATTERN_PART *)calloc(1, sizeof(PATTERN_PART));

   p->text = strdup(string);
   if(part == NULL) {
      return(p);
   } else {	/* Add to end of list */
      for(tmp = part; tmp->next != NULL; tmp = tmp->next) continue;
      tmp->next = p;
   }
   return(part);
}

#define done(x) free(tmp); return(x);

/*----------------------------------------------------------------
  Extracts the portions of the string which ,match the wild card
  portion of the pattern.

  Entry Requirements:
     pattern : The pattern to use to extract wild carded portions 
	       from the text.
     string : The text to compare to the pattern.

  Return Value:
     A PATTERN_PART structure containing a list of parts matching
     the wild card portion of the string.
------------------------------------------------------------------*/
PATTERN_PART *
pattern_part(pattern, string)
PATTERN *pattern;
char string[];
{
   PATTERN *p;
   int	i;
   char *s;
   char *tmp;
   PATTERN_PART	*part = NULL;

   tmp = (char *) calloc(1, strlen(string) + 1);

   s = string;
   for(p = pattern; p != NULL; p = p->next) {
      switch(p->type) {
	 case PATTERN_TYPE_SINGLE_CHAR:
	    if(*s == '\0') { done(part); }
	    tmp[0] = *s; tmp[1] = '\0';
	    part = pattern_part_push(part, tmp);
	    s++;
	    break;
	 case PATTERN_TYPE_MULTIPLE_CHAR:
	    strcpy(tmp, s);
	    if(p->next != NULL) {	/* Compress mulitple MULTIPLE_CHAR */
	       while(p->next->type == PATTERN_TYPE_MULTIPLE_CHAR) {
		  p = p->next;
	       }
	    }
	    if(p->next != NULL) { 
	       switch(p->next->type) {
		  case PATTERN_TYPE_SINGLE_CHAR:
		     part = pattern_part_push(part, tmp);
		     continue;	/* Process this pattern */
		     break;
		  case PATTERN_TYPE_FIXED:
		     tmp[0] = '\0';
		     for( ; *s != '\0'; s++) {
			if(strncmp(s, p->next->text, p->next->text_len) == 0) { 
			   s += p->next->text_len;
			   p = p->next;	/* Skip this check - we've done it */
			   break;
			}
			tmp[i] = *s; tmp[i + 1] = '\0'; i++; 
		     }
		     break;
	       }
	    }
	    part = pattern_part_push(part, tmp);
	    break;
	 case PATTERN_TYPE_FIXED:
	    if(*s == '\0') { done(part); }
	    if(strncmp(s, p->text, p->text_len) == 0) { s += p->text_len; }
	    else { done(part); }
	    break;
	 default:
	    done(part);
      }
   }

   return(part);
}

/*----------------------------------------------------------------
   Locates a specific item in a PATTERN_PART link list given the 
   relative location index of the item.

   Entry Requirements:
      part : A PATTERN_PART link to search for a specific item.
      number : The index of the number to locate. Counting starts
	       at 1.

   Return Value:
      A pointer to the PATTERN_PART item which cooresponds to the
      given index.

------------------------------------------------------------------*/
PATTERN_PART *
pattern_part_get(part, number)
PATTERN_PART	*part;
int		number;
{
   int	n;
   PATTERN_PART	*p;

   for(n = 1, p = part; p != NULL; p = p->next, n++) {
      if(n == number) return(p);
   }
   return(NULL);
}

/*----------------------------------------------------------------
  Prints debugging information about a PATTERN_PART link list.

  Entry Requirements:
     part : The PATTERN_PART link list to dump.
------------------------------------------------------------------*/
pattern_part_dump(part)
PATTERN_PART	*part;
{
   PATTERN_PART	*p;
   int	i;

   if(part == NULL) { printf("Empty part list.\n"); }
   for(i = 1, p = part; p != NULL; p = p->next, i++) {
      printf("Part %d: text: %s\n", i, p->text);
   }
   return(1);
}

/*----------------------------------------------------------------
   Replaces all occurances of $# with part number # from the 
   link list of parts "part".

   Entry Requirements:
      pattern : The link list of parts to use to replace $#.
      source : The string from which to extract the parts from.
      dest: The string of text to replace $# with text.
      escape : The escape character to permit literal interpretation
	       of the dollar sign ($).

   Return Value:
     A pointer to a static string containing the translated
     version of 'dest'.
------------------------------------------------------------------*/
char *
pattern_replace(pattern, source, dest, escape)
PATTERN	*pattern;
char	*source;
char	*dest;
char	escape;
{
   static char	buffer[2048];
   int	end = strlen(dest);
   int	j;
   int	i;
   int	n;
   PATTERN_PART	*part;
   PATTERN_PART	*p;

   part = pattern_part(pattern, source);
   j = 0; buffer[j] = '\0';
   for(i = 0; i < end; i++) {
      if(dest[i] == escape) {
	 i++;
	 buffer[j] = dest[i]; j++; buffer[j] = '\0';
      } else {
	 switch(dest[i]) {
	    case '$':
	       n = atoi(&dest[i + 1]);
	       p = pattern_part_get(part, n);
	       if(p != NULL) { 
		  strcat(buffer, p->text); 
		  j += strlen(p->text);
	       }
	       while(isdigit(dest[i + 1])) i++;
	       break;
	    default:
	       buffer[j] = dest[i]; j++; buffer[j] = '\0';
	       break;
	 }
      }
   }
   pattern_part_free(part);
   return(buffer);
}
