/*	trigram_util		Mar 1999				*/
/*	  Image interface to trigram/untrigram subrs in outer_utils.c	*/

/*  Input:								*/
/*	1st arg (optional)						*/
/*	  -trigram	trigram the following string			*/
/*	  -untrigram	untrigram the following string			*/
/*	  -un		synonym for untrigram				*/
/*	    If unspecified, defaults to -trigram			*/
/*	Next arg (required)						*/
/*	  string to be trigrammed or untrigrammed.  Special characters	*/
/*	  must be protected from shell					*/
/*	Next arg pair (optional - 2nd required if first spec'd)		*/
/*	  -key char, where char is the character that introduces a	*/
/*			a trigram.  If pair unspec'd, defaults to %	*/
/*	If -trigram, next arg pair is optional - 2nd required if first	*/
/*	spec'd.  May interchange in order with previous optional arg	*/
/*	pair								*/
/*	  -replace	string of characters to be replaced by trigrams	*/
/*			special characters must be protected from shell	*/
/*			If pair unspec'd, defaults to blank		*/

/*  Output:								*/
/*	Trigrammed/untrigrammed string or error message written to	*/
/*	stdout without trailing newline.  error messages all begin with	*/
/*	"*** ERROR"							*/

/*  Exit statuses (assuming default value for ERROR_EXIT_STATUS in	*/
/*		   error_exit_defn.h):					*/
/*	  0	OK							*/
/*	241	Required arg missing (see input, above)			*/
/*	242	Incomplete arg pair (see opt pair inputs, above)	*/
/*	243	Dynamic memory allocation failure			*/
/*	244	During untrigram, 2 characters after some trigram key	*/
/*		  were not hex digits					*/
/*	245	Too many args (check special character protection)	*/
/*		  Could also be misspelled -key or -replace or		*/
/*		  specifying -replace twice				*/
/*	246	-key spec'd twice w/different values or -replace spec'd	*/
/*		  with -untrigram					*/
/*	247	Length of key arg != 1 char				*/

/*  Examples:								*/
/*	trigram_util "a b"						*/
/*		produces string a%20b					*/
/*	trigram_util -trigram "a+b=c" -replace "+=" -key "#"		*/
/*		produces string a#2bb#3c (if quotes work!)		*/
/*	trigram_util -un a%20eq%20b					*/
/*		produces    a eq b					*/
/************************************************************************/

#define ID "trigram_util version 1.2  24 Apr 2004"
/* 24 Apr 2004.  v 1.2.  WJS						*/
/*	error_exit_defn.h defs now in core.h.  As part of this, get	*/
/*    core.h version ID string into this program's binary image		*/
/*	[Needs outer_utils.c v 1.0]					*/
/*	[Needs core.h v 1.0]						*/
/*	[Begin 1.1]							*/
/* 22 Apr 1999.  v 1.1.  WJS						*/
/*	[Needs outer_utils.c v 1.0]					*/
/*	[Needs error_exit_defn.h v 1.0]					*/
/*	[Begin 1.1]							*/
/*  2 Mar 1999.  v 1.0.  WJS						*/
/*	[Needs outer_utils.c v 1.0]					*/
/*	[Begin 1.0]							*/

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

  /*  Next is also defined in outer.h, but so what?  This is just a	*/
  /*  default...							*/
#define TRIGRAM_KEY '%'

#define TRIGRAM 1
#define UNTRIGRAM 2

  /*  Exit statuses.  Don't use 0					*/
#define NOARGS ERROR_EXIT_STATUS-9
#define MISSING_ARG ERROR_EXIT_STATUS-8
#define NOMEM ERROR_EXIT_STATUS-7
#define BADFMT ERROR_EXIT_STATUS-6
#define UNPROCESSED_ARGS ERROR_EXIT_STATUS-5
#define EXTRA_SWITCH ERROR_EXIT_STATUS-4
#define ILLEGAL_KEY ERROR_EXIT_STATUS-3
#if ILLEGAL_KEY <= 0
#error "ERROR_EXIT_STATUS defn produces illegal status in trigram_util"
#endif

char *trigram_util_return_vers()
/*  Routine exists mostly to force .h file version string into this	*/
/*  module, but we could call it if we want.  Note string must not be	*/
/*  global or we'll have conflicts if another routine similarly		*/
/*  includes the version string						*/
{
  static char version[] = ID"/"COREH_VERSION;
  return version;
}

void err (s,status)
char *s;
int status;
{
  printf ("*** ERROR: %s (%s)",s,ID);
  exit (status);
}

main(argc,argv)
char *argv[];
int argc;
{
  char *trigram(),*un_trigram();
  char *s,*repl,*t;
  char key;
  int len,iarg,operation;

  iarg = 1;		/*  argv[0] is the image name		*/
  if (argc <= iarg) err("not enough args",NOARGS);

  if (  (strcmp(argv[iarg],"-un") == 0)		||
	(strcmp(argv[iarg],"-untrigram") == 0)    ) {
    operation = UNTRIGRAM;
    iarg++;
  } else {
    operation = TRIGRAM;
    if (strcmp(argv[iarg],"-trigram") == 0) iarg++;
  }

  if (argc <= iarg) err("not enough args",NOARGS);

  s = argv[iarg++];

  repl = " ";
  key = '\0';

    /*  Lazy way of allowing optional switches in either order...	*/
  if (argc > iarg)
    if (strcmp("-key",argv[iarg]) == 0) {
      if (argc <= ++iarg) err ("Missing arg after -key",MISSING_ARG);
      if (strlen(argv[iarg]) == 1) key = *argv[iarg++];
      else err ("Key length != 1 char",ILLEGAL_KEY);
    }
  if (argc > iarg)
    if (strcmp("-replace",argv[iarg]) == 0)
      if (operation == TRIGRAM) {
	if (argc <= ++iarg) err ("Missing arg after -replace",MISSING_ARG);
	repl = argv[iarg++];
      } else
	err ("-replace specified with -untrigram",EXTRA_SWITCH);
  if (argc > iarg)
    if (strcmp("-key",argv[iarg]) == 0) {
      if (argc <= ++iarg) err ("Missing arg after -key",MISSING_ARG);
      if (strlen(argv[iarg]) == 1) {
	t = argv[iarg++];
	if ((key != '\0') && (key != *t))
	  err ("-key specified twice",EXTRA_SWITCH);
	key = *t;
      } else
	err ("Key length != 1 char",ILLEGAL_KEY);
    }
    /*  Worth diagnosing this since improper handling of embedded	*/
    /*  blanks in argv can be expected.					*/
  if (iarg != argc) err("unprocessed args",UNPROCESSED_ARGS);

  if (key == '\0') key = TRIGRAM_KEY;

  if (operation == TRIGRAM) {
    t = trigram(s,repl,key,&len);
    if (t == NULL) err ("no memory",NOMEM);
  } else {
    t = un_trigram(s,key,&len);
    if (t == NULL) 
      if (len < 0) err ("no memory",NOMEM);
      else {
	printf("*** ERROR %s: bad format at %s",ID,s+len);
	exit (BADFMT);
      }
  }

  printf("%s",t);
  exit(0);
}
