/*
{GT:}
   The Imp to C generator has two modes of operation.  It can either
   work in "imp mode" or "c mode".

   In imp mode, it generates code to treat strings as proper Imp strings
   with a preceding length byte.  Programs should always work correctly
   in this mode.

   It also treats Imp streams as low-level FD channels.

   In c mode it assumes that string use is simple and maps strings to C
   strings.

   It treats Imp streams as FILE * files, with a little tweaking

   Ideally the compiler flags should be changed to separate the treatment
   of strings and the treatment of streams.

   However at the moment that is not so.  It's not at all obvious which
   style the translator is generating but this file seems to implement
   C strings, but no support for FILE I/O.

   NOTE: the current default mode for the compiler is to generate C
   strings and FILE streams.

   This whole area is undergoing a consistency audit at the moment and
   hopefully the final implementation will preserve the option for
   imp vs c strings, but move exclusively to FILE I/O.

 */

#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);
}

