/*  outer_utils.c							*/
/*    Standalone utility programs used by outer.  These routines	*/
/*    call no jgofs routines, have no "knowledge" of jgofs system, etc.	*/
/*    They can (and probably should) go into a general library		*/
/*									*/
/*	char *htmlescape(str)						*/
/*	  Takes string destined for stdout in an html environment.	*/
/*	  Does necessary conversion so that all characters in the	*/
/*	  string are output "as-is"; ie, arranges that no character is	*/
/*	  interpreted as "requiring action" by html interpreter		*/
/*	char *trigram(s,replacement_list,trigram_key,len_result)	*/
/*	  Replaces selected characters in a string with their hex	*/
/*	  equivalents; eg, replace blank with string %20		*/
/*	char *un_trigram(s,trigram_key,len_result)			*/
/*	  Reverses action of trigram					*/
/*									*/
#define OUTER_UTILS_VERSION "outer_utils  version 1.0  4 Dec 98"
/*  4 Dec 98.			WJS					*/
/*		[Begin 1.0]						*/

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

#ifndef VMS
#include <malloc.h>
#endif

  /*  Force inclusion of version string in image.  Probably doesn't	*/
  /*  work if optimizing compiler is good, since variable isn't used	*/
char *outer_version_utils = OUTER_UTILS_VERSION;

char *htmlescape(str)
char *str;
{
char *i,*o,*htmlcode,*htmlstuff,*tmp;

i=str;

htmlstuff=(char *)malloc(strlen("</")+strlen(i+1)+1);	/* See code	*/
if (htmlstuff == NULL) return NULL;
tmp=(char *)malloc(5*strlen(str)+1);	/* Assume str is all ampersands	*/
if (tmp == NULL) return NULL;

o=tmp;
*o=0;
while(*i){
  switch(*i){
  case '<':
    if(htmlcode=strpbrk(i," >")){
      strcpy(htmlstuff,"</");
      strcat(htmlstuff,i+1);
      htmlcode=strpbrk(htmlstuff," >");
      *htmlcode='>';
      *(htmlcode+1)=0;
      if((htmlcode=strstr(i,htmlstuff))){
	htmlcode +=strlen(htmlstuff);
	*htmlstuff = *htmlcode;
	*htmlcode=0;
	strcpy(o,i);
	o += strlen(i);
	i += strlen(i)-1;
	*htmlcode = *htmlstuff;
	break;
      };
    };
    strcpy(o,"&lt;");
    o += 4;
    break;
  case '&':
    strcpy(o,"&amp;");
    o += 5;
    break;
  case '>':
    strcpy(o,"&gt;");
    o += 4;
    break;
  default:
    *(o++) = *i;
    break;
  };
  i++;
};
*o = 0;
free (htmlstuff);
return tmp;
}

char *trigram(s,replacement_list,trigram_key,len_result)
  /*  Given a string s, replace selected characters with 3 characters.	*/
  /*  The selected characters are supplied by argument replacement_list. */
  /*  The first replacement character is the supplied trigram key.  The	*/
  /*  next 2 replacement characters are the hex value of the replace-	*/
  /*  ment list character.						*/
  /*    The return value is the address of a dynamically allocated	*/
  /*  string containing the original string with replacement trigrams.	*/
  /*  NULL is returned if the dynamic allocation fails.			*/
  /*  If the argument len_result is non-NULL, the length of the		*/
  /*  returned string is placed in the address pointed to by len_result	*/
  /*    Note that if the trigram key character is present in the input	*/
  /*  string, it is user responsibility to be sure that it is followed	*/
  /*  by 2 appropriate hex digits (assuming that the output string will	*/
  /*  be un-trigrammed at some point)					*/
  /*    Characters in the replacement list may not be quoted or		*/
  /*  escaped; that is, it is not possible for these characters to	*/
  /*  appear in the returned string (unless these characters are hex	*/
  /*  digits, in which case they may appear as part of a trigram)	*/
char *s,*replacement_list,trigram_key;
int *len_result;
{
  char *in,*out,*out_str;
  int i;

    /*  Assume all characters are replaced by trigrams			*/
  out_str = (char *) malloc (3*strlen(s) + 1);

  if ( (out = out_str) != NULL ) {
    in = s;
    while (*in != '\0') {
      i = strcspn(in,replacement_list);
      strncpy (out,in,i);
      out += i;
      in += i;
      if (*in != '\0') {
	*(out++) = trigram_key;
	sprintf(out,"%02x",*(in++));
	out += 2;
      }
    }
    *out = '\0';
  }

  if (len_result != NULL) *len_result = out-out_str;
  return out_str;
}

char *un_trigram(s,trigram_key,len_result)
  /*  The string s is searched for the character trigram_key.  When	*/
  /*  found, the key and the following 2 characters are replaced by a	*/
  /*  single ASCII character.  This character is the one defined by the	*/
  /*  2 characters following the key, assuming that those 2 characters	*/
  /*  are hex digits.							*/
  /*    If all trigrams are successfully converted, the return value is	*/
  /*  the address of a dynamically allocated string containing the	*/
  /*  original string with trigrams replaced.	Otherwise, NULL is	*/
  /*  returned.								*/
  /*    If len_result is non-NULL and all conversions are successful,	*/
  /*  the length of the converted string is returned.  If there was an	*/
  /*  unsuccessful conversion, the offset to the key prefixing the	*/
  /*  problem trigram is returned.  If an output buffer could not be	*/
  /*  allocated, -1 is returned						*/
  /*    The trigram key character may not be quoted or escaped; that is	*/
  /*  it is not possible for the returned string to include the	tri-	*/
  /*  gram key unless it itself was present as a trigram in the input	*/

char *s,trigram_key;
int *len_result;
{
  char *in,*out,*out_start;
  int i;

  in = s;
  out_start = (char *) malloc (strlen(s)+1);
  if (  (out = out_start) == NULL  ) {
    if (len_result != NULL) *len_result = -1;
    return NULL;
  }

  while (*in != '\0') {
    if (*in == trigram_key) {
      i = 1000;	/*  Anything not representable in 2 hex digits		*/
	/*  Use scanf instead of strtol so we can confine the trans-	*/
	/*  lation to a max of 2 chars.  Error in sscanf should not be	*/
	/*  possible, but if occurs, won't set i anyway			*/
      if (    isxdigit( *(++in) )    )
	if (    isxdigit( *(in+1) )    )
	  sscanf (in,"%2x",&i);
      if (i == 1000) {	/*  == means could not convert; means error	*/
	if (len_result != NULL) *len_result = in-s-1;
	free (out_start);
	return NULL;
      } else {
	in += 2;
	*(out++) = i; /*  Need to worry about sign?  Don't think so	*/
      }
    } else
      *(out++) = *(in++);
  }
  *out = '\0';

  if (len_result != NULL) *len_result = out-out_start;
  return out_start;
}
