#include <stdio.h>
#include <string.h>
#include <assert.h>

static char space[15][256];
static int point = -1;

char *imp_concat (char *lhs, char *rhs)
{
   point = (point + 1) & 15;
   strcpy (space[point], lhs);
   strcat (space[point], rhs);
   return space[point];
}
int imp_resolve (char *origlhs, char *dest1, char *exp, char *dest2)
{
   int l1;
   char *s1, *lp;
   char lhs[256];

   strcpy (lhs, origlhs);
   s1 = strstr (lhs, exp);
   if (s1 == NULL)
      return 1;
   s1[0] = 0;
   l1 = strlen (lhs) + strlen (exp);
   if (dest1 != NULL)
      strcpy (dest1, lhs);
   lp = (char *) lhs + l1;
   if (dest2 != NULL)
      strcpy (dest2, lp);
   return 0;
}
char *imp_tostring (int sym)
{
   static char aa[2];

   aa[0] = sym;
   aa[1] = 0;
   return aa;
}
void imp_stop ()
{
   printf ("\n\n IMP %%stop Called\n\n");
   exit (0);
}
char *imp_substring (char *source, int from, int to)
{
   static char lhs[256];
   int i, j;

   i = 0;
   for (j = from; j <= to; j++)
      lhs[i++] = source[j];
   lhs[i] = 0;
   return lhs;
}
void imp_strjam (char *lhs, char *rhs, int max)
{
   lhs[0] = 0;
   strncat (lhs, rhs, max);
}
void s__cstring (char *impstring, char *cstring)
{
   /* dummy version for when strings are already cstring */
   strcpy (cstring, impstring);
}
char *itos (int val)
{
   static char sp[20];

   sprintf (sp, "%d", val);
   return sp;
}
void phex (int val)
{
   printf ("%8x", val);
}
char *htos (int val, int places)
{
/*GT: */
   static char sp[9];		/* even as a static this is bad practise */

   switch (places) {
   case 1:
      sprintf (sp, "%1x", val);
      break;
   case 2:
      sprintf (sp, "%2x", val);
      break;
   case 3:
      sprintf (sp, "%3x", val);
      break;
   case 4:
      sprintf (sp, "%4x", val);
      break;
   case 5:
      sprintf (sp, "%5x", val);
      break;
   case 6:
      sprintf (sp, "%6x", val);
      break;
   case 7:
      sprintf (sp, "%7x", val);
      break;
   default:
      sprintf (sp, "%8x", val);
      break;
   }
   return sp;
}

/*

   Additions for FILE * I/O
   Conventions:

   Input: 0  console or controlling file
   1  stdin
   2  /dev/null
   other:  arbitrary FILE *

   Output: 0 console or log file
   1 stdout
   2 stderr
   other: arbitrary FILE *

   This is a crude hack based on some of the Comp Sci systems.

   These are defaults and will be overridden by use of procedures
   such as "open input" and "open output"

 */

FILE *_ttyin;
FILE *_nullin;
FILE *_ttyout;
FILE *_nullout;

static int _initstreams = 0;

FILE *inmap[128];
FILE *outmap[128];

int instream, outstream;

static void _init_streams (void)
{
   _initstreams = 1;		/* Done. */

   inmap[0] = _ttyin = fopen ("/dev/tty", "r");
   inmap[1] = stdin;		/* or /dev/stdin */
   inmap[2] = _nullin = fopen ("/dev/null", "r");

   outmap[0] = _ttyout = fopen ("/dev/tty", "w");
   outmap[1] = stdout;		/* or /dev/stdout */
   outmap[2] = stderr;		/* or /dev/stderr */

   instream = 0;
   outstream = 0;

}

void selectinput (int stream)
{
   if (_initstreams == 0) {
      _init_streams ();
   }
   assert ((((int) stream) >= 0) && (((int) stream) < 128));
   instream = stream;
   assert (inmap[instream] != NULL);
}

void selectoutput (int stream)
{
   if (_initstreams == 0) {
      _init_streams ();
   }
   assert ((((int) stream) >= 0) && (((int) stream) < 128));
   outstream = stream;
   assert (outmap[outstream] != NULL);
}

int openinput (int stream, char *filename)
{
   if (_initstreams == 0) {
      _init_streams ();
   }
   /* Could warn if inmap[stream] != NULL ??? */
   /* Doing a freopen is not quite what's wanted in that case */
   inmap[stream] = fopen (filename, "r");
   return (0);			/* WHAT SHOULD openinput RETURN??? */
}

int openoutput (int stream, char *filename)
{
   if (_initstreams == 0) {
      _init_streams ();
   }
   /* Could warn if outmap[stream] != NULL ??? */
   /* Doing a freopen is not quite what's wanted in that case */
   outmap[stream] = fopen (filename, "w");
   return (0);			/* WHAT SHOULD openoutput RETURN??? */
}

void closeinput (void)
{
   int old = instream;

   selectinput (0);
   assert (inmap[instream] != NULL);
   if (old == 0)
      return;			/* Won't allow to close console */
   fclose (inmap[old]);
   inmap[old] = NULL;
}

void closeoutput (void)
{
   int old = outstream;

   selectoutput (0);
   assert (outmap[outstream] != NULL);
   if (old == 0)
      return;			/* Won't allow to close console */
   fclose (outmap[old]);
   outmap[old] = NULL;
}

void setinput (int pos)
{
   assert (inmap[instream] != NULL);
   fseek (inmap[instream], pos, SEEK_SET);
}

void setoutput (int pos)
{
   assert (outmap[outstream] != NULL);
   fseek (outmap[outstream], pos, SEEK_SET);
}
