/*
   mass string substituter

   Intended for efficient implementation of things
   like the jivering



   Takes as input: A string, an integer mode value,
   and a list of alternating source, destination values.

   It replaces all occurences of each source value with
   each destination value, _in order_, so that they can
   replace on top of each other--that is, it substitutes
   all occurences of the first pattern, and then takes
   the result of that and applies the second, etc.

   The mode value is used to control boundary conditions:
   0   substitute on any match
   1   substitute only at beginning of word
   2   substitute only at end of word
   3   substitute only exactly this word

*/

#include <stdio.h>
#include <ctype.h>
#include "lint.h"
#include "interpret.h"

char *strstr();

#ifndef __ANSI__
#ifdef NO_STRSTR

/*
   If they don't have a strstr, do our own... may not be
   most efficient way without a host strstr.
*/

char *strstr(src, pattern)
char *src;
char *pattern;
{
   for(;*src;++src)
      if (*src == *pattern)
         if (!strcmp(src, pattern))
            return src;
   return (char *) 0;
}

#endif
#endif


#define ok(c)      (!isalnum(c))


char *strsub(src, arr, mode)
char *src;
struct vector *arr;
int mode; 
{
   extern char *malloc(), *realloc();
   char *result, *find, *tmp;
   int nlen, mlen;
   int i,offset, len;

   char *subsrc, *subdest;
   int ssrclen, sdestlen, delta;

   len = arr->size;

   if (len % 2)
      error("Odd length array given to strsub.\n");
   for (i=0; i < arr->size; ++i)
      if (arr->item[i].type != T_STRING)
         error("Invalid type in array, given to strsub.\n");

   nlen = strlen(src);
   result = malloc(mlen = (3*nlen+1));
   if (!result) return NULL;
   strcpy(result, src);

   for (i=0; i+1<len; i+=2) {
      subsrc = arr->item[i].u.string;
      subdest = arr->item[i+1].u.string;

      ssrclen = strlen(subsrc);
      sdestlen = strlen(subdest);
      delta = sdestlen - ssrclen;

      if (!ssrclen) break;

      offset = 0;      /* place to start looking */
      while (offset + ssrclen <= nlen) {
         find = strstr(result + offset, subsrc);
         if (!find) break;

               /* calc next place to check */
         offset = find - result + 1;

               /* check boundary conditions */
         if (mode == 1 &&
            ((find > result && !ok(find[-1])) ||
               ok(find[ssrclen])))
            continue;
         if (mode == 2 && (find == result || ok(find[-1])
               || !ok(find[ssrclen])))
            continue;
         if (mode == 3 && ((find > result && !ok(find[-1]))
               || !ok(find[ssrclen])))
            continue;

               /* make room for copy */
         if (nlen + delta >= mlen) {
            mlen *= 2;
            if (nlen + delta >= mlen)
               mlen += delta + 1;

            result = realloc(result, mlen+2);
            if (!result)
               return NULL;
         }

/*  
 * Bcopy handles overlapping string correctly.  On systems without 
 * bcopy, memmove is used (lint.h #defines it correctly).
 */
  
         bcopy(find + ssrclen, find + sdestlen,
            nlen - (offset + ssrclen) + 2);

         memcpy(find, subdest, sdestlen);

         nlen += delta;
         offset += sdestlen-1;
      }
   }
   result = realloc(result, nlen + 4);
   return result;   /* Checks for null in the caller */
}