/*===========================================================================
  Copyright (C) 1995-2007 European Southern Observatory (ESO)
 
  This program is free software; you can redistribute it and/or 
  modify it under the terms of the GNU General Public License as 
  published by the Free Software Foundation; either version 2 of 
  the License, or (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public 
  License along with this program; if not, write to the Free 
  Software Foundation, Inc., 675 Massachusetts Ave, Cambridge, 
  MA 02139, USA.
 
  Correspondence concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/

/*+++++++++++++++++++++ Module MIDTERM ++++++++++++++++++++++++++++++++++++
.LANGUAGE   C
.IDENTIFICATION  MIDTERM
.AUTHOR
  Klaus Banse
.COMMENTS
 holds  MID_VMEM, MID_VMIO, MID_TINIT, MID_TDISP, MID_TPRO, MID_TTINFO
.KEYWORDS
  terminal interface routines
.ENVIRONMENT
  independant.

.VERSION [1.00] 880613: creation - without TermWindow functions
 070316		last modif

------------------------------------------------------------------------*/

#include <fileexts.h>
#include <stdio.h>
#include <stdlib.h>
#include <osterm.h>

#include <osyparms.h>

#define   BC_LEN  120			/* size of b_line */
static char   b_line[BC_LEN];

#define V_EXTNO  80			/* was 40 */

struct  VMEM
        {
        int     Vnbl[V_EXTNO];
        char    *Vpntr[V_EXTNO];
        } myVMEM;

static struct VMEM  *Vbase, *Vmem;

static int *Vindx;
static int V_MAX = 5, Vcount = -1;
/*

*/

int MID_VMEM(flag,parm2,fileid)
/*++++++++++++++++++++++++++++++++++++++++++++++++++
.KEYWORDS
  virtual memory allocation
.PURPOSE
  create an entry in the VMEM structure and allocate memory
.ALGORITHM
  use malloc
.RETURNS
   ERR_NORMAL : all o.k.
   ERR_MEMOUT : could not allocate memory
              : overflow in VMEM struct
--------------------------------------------------*/

int  flag;      /* IN: 1 = "create" memory file;
                       2 = "extend" existing memory file;
                       3 = close memory file */
int  parm2;      /* IN: no. of blocks to allocate (flag = 1,2);
			chanl (flag = 3) */
int  *fileid;   /* OUT: negative index into Vpntr array */

{
int   memsiz, nobl, idx, *vdx;
unsigned int nono;
register int  nr;

char  *cp, *cq;





if (flag == 3)				/* close a memory file */
   {
   idx = parm2;
   Vmem = Vbase + idx;

   for (nr=0; nr<V_EXTNO; nr++)
      {
      if (Vmem->Vnbl[nr] == 0) break;		/* end of chain reached */

      free(Vmem->Vpntr[nr]);
      }

   *(Vindx + idx) = 0;                   /* clear entry */
   return (ERR_NORMAL);
   }



nobl = parm2;
memsiz = nobl * OUR_BLOCK_SIZE;

if (flag == 1)                  /* create new memory frame */
   {
   struct VMEM  *newVbase, *newVmem;
   int  newmax, *newVindx, *newvdx;
   register int  mr;


   if (Vcount == -1)		/* we're here for the very first time */
      {
      nono = (unsigned int) (sizeof(myVMEM)*V_MAX + 8);
      cp = malloc((size_t)nono);	/* allocate space for V_MAX VMEMs */
      nono = (unsigned int) (sizeof(int)*V_MAX + 1);
      cq = malloc((size_t)nono);	/* allocate space for Vindx array */
      if ((cp == NULL) || (cq == NULL))
         {
         MID_ERROR("OSY","MID_VMEM",ERR_MEMOUT,0);
         return (ERR_MEMOUT);      
         }

      Vbase = (struct VMEM *) cp;
      Vindx = (int *) cq;
      vdx = Vindx;
      for (nr=0; nr<V_MAX; nr++) *vdx++ = 0;		/* clear all entries */
      Vcount = 0;
      }


   /* find free entry */

  find_free_slot:
   vdx = Vindx;
   for (nr=0; nr<V_MAX; nr++)
      {
      if (*vdx == 0)
         {
         cp = malloc((size_t)memsiz);
         if (cp == NULL)
            {
            MID_ERROR("OSY","MID_VMEM",ERR_MEMOUT,0);
            return (ERR_MEMOUT);
            }
         else
            {
            Vmem = Vbase + nr;
            Vmem->Vpntr[0] = cp;                /* save pointer to memory */
            Vmem->Vnbl[0] = nobl;               /* save no blocks */
            Vmem->Vnbl[1] = 0;                  /* indicate end of chain */
            *vdx = 1;				/* mark as used */
            *fileid = -(nr+1);                  /* fileid = neg. (index+1) */
            return ERR_NORMAL;
            }
         }
      vdx ++;
      }

   /* we're out of VMEMs, so allocate/create new ones */

   newmax = V_MAX * 2;				/* double V_MAX */
   nono = (unsigned int) (sizeof(myVMEM)*newmax + 8);
   cp = malloc((size_t)nono);               /* allocate space for V_MAX VMEMs */
   nono = (unsigned int) (sizeof(int)*newmax + 1);
   cq = malloc((size_t)nono);               /* allocate space for Vindx array */
   if ((cp == NULL) || (cq == NULL))
      {
      MID_ERROR("OSY","MID_VMEM",ERR_MEMOUT,0);
      return (ERR_MEMOUT);
      }

   newVbase = (struct VMEM *) cp;
   newVindx = (int *) cq;

   newvdx = newVindx;
   for (nr=0; nr<newmax; nr++) *newvdx++ = 0;	    /* clear all new entries */
   newvdx = newVindx;
   vdx = Vindx;						/* and copy old ones */
   for (nr=0; nr<V_MAX; nr++) *newvdx++ = *vdx++;

   Vmem = Vbase;
   newVmem = newVbase;
   for (nr=0; nr<V_MAX; nr++) 
      {
      for (mr=0; mr<V_EXTNO; mr++)
         {
         newVmem->Vnbl[mr] = Vmem->Vnbl[mr];
         newVmem->Vpntr[mr] = Vmem->Vpntr[mr];
         }
      newVmem ++;
      Vmem ++;
      }

   (void) free (Vbase);			/* free old memory */
   (void) free (Vindx);
   Vbase = newVbase;			/* and use new structure */
   Vindx = newVindx;
   V_MAX = newmax;				
   goto find_free_slot;
   }

else 					/* extend given memory frame */
   {
   cp = malloc((size_t)memsiz);
   if (cp == NULL)
      {
      MID_ERROR("OSY","MID_VMEM",ERR_MEMOUT,0);
      return (ERR_MEMOUT);
      }
   else
      {
      nr = -1 - (*fileid);
      Vmem = Vbase + nr;

      for (nr=0; nr<V_EXTNO; nr++)           /* max V_EXTNO extensions */
         {
         if (Vmem->Vnbl[nr] == 0)
            {
            Vmem->Vpntr[nr] = cp;               /* add new pointer */
            Vmem->Vnbl[nr] = nobl;              /* save no blocks */
            idx = nr + 1;
            if (idx < V_EXTNO) Vmem->Vnbl[idx] = 0;  /* indicate end of chain */
            return ERR_NORMAL;
            }
         }
      }
   }

MID_ERROR("OSY","MID_VMEM",2,0);
return (ERR_MEMOUT);                            /* no free slot found */
}
/*

*/

int MID_VMIO(flag,idx,pbuf,nobyt,vbn)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++

.PURPOSE write virtual blocks to disk or memory
.RETURNS midas error code
.REMARKS uses the os interface service osdwrite.

-------------------------------------------------------------------------*/

int   flag;	/* IN : = 1 write; = 0 read */
int   idx;	/* IN : index into Vmem struct */
char  *pbuf;    /* IN : pointer to the buffer to write */
unsigned int  nobyt;    /* IN : number of bytes to be transferred */
int   vbn;      /* IN : starting virtual block for data transfer */

{
int   kbl, mm, vsize, vbegi, vend;
register int  nr;
unsigned int  outof, amount;

char  *cp;



Vmem = Vbase + idx;
amount = outof = 0;
kbl = 0;
vbegi = 1;

for (nr=0; nr<V_EXTNO; nr++)
   {
   vsize = Vmem->Vnbl[nr];
   vend = vbegi + vsize - 1;         /* last block here */
   if (vbn <= vend)
      {
      mm = vbn - vbegi;
      cp = Vmem->Vpntr[nr] + (mm * OUR_BLOCK_SIZE);
      kbl = vsize - mm;
      amount = kbl * OUR_BLOCK_SIZE;
      if (amount > nobyt) amount = nobyt;

      if (flag == 1)				/* writing */
         memcpy(cp,pbuf+outof,(size_t)amount);
      else					/* reading */
         memcpy(pbuf+outof,cp,(size_t)amount);

      nobyt -= amount;
      if (nobyt < 1) return (ERR_NORMAL);    /* we're done */
      }

   vbn += kbl;
   vbegi += vsize;
   outof += amount;
   }

return (-1);
}
/*

*/

void MID_TINIT()

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.KEYWORDS
  terminal
.PURPOSE
  initialize constants
.ALGORITHM
.RETURNS
  status:	I*4		return status
--------------------------------------------------*/

{
register int  nr;

for (nr=0; nr<(BC_LEN-1); nr++) 
    b_line[nr] = '\b';			/* fill with back_spaces  */

b_line[BC_LEN-1] = '\0';
}
/*

*/

void MID_TDISP(string,b_count,lstr)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.KEYWORDS
  terminal
.PURPOSE
  put text on terminal and position cursor somewhere in same line
.ALGORITHM
  no big deal
.RETURNS
  nothing
--------------------------------------------------*/

char  *string;		/* IN: string to be displayed  */
int   b_count;  	/* IN: no. of backspaces to do */
int   lstr;		/* IN: length of string */

{
int  m;

char  mystr[BC_LEN];

m = BC_LEN - 1;			/* avoid buffer overflow */
if (lstr > m) 
   {
   lstr = m;
   if (b_count > m) b_count = m;
   }

(void) memcpy(mystr,string,(size_t)lstr);
mystr[lstr] = '\0';


if (b_count == m)		/* max size '\0' already in place */
   {
   printf("%s",mystr);
   printf("%s",b_line);
   }
else
   {
   printf("%s",mystr);
   b_line[b_count] = '\0';
   printf("%s",b_line);
   b_line[b_count] = '\b';
   }

fflush(stdout);			/* flush out line */
}   
/*

*/

void MID_TPRO(prompt,line,len)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.KEYWORDS
  terminal
.PURPOSE
  prompt for + get an input line from terminal
.ALGORITHM
  standard C functions
.RETURNS
  len:	I*4		length of input line
--------------------------------------------------*/

char	*prompt;	/* IN: prompt string (terminated by \0)  */
char	*line;		/* OUT: input line (terminated by \0)    */
int   len;		/* IN: length of buffer 'line'  */

{

(void) printf("%s ",prompt);
CGN_GETLINE(line,len);

}
/*

*/

void MID_TTINFO(tcols,tlines)
int  *tcols, *tlines;

{
int  tc;

struct termstatus  tstat;



*tcols = 80;                 /* default to 80 char, 24 lines window */
*tlines = 24;


/* get no. of columns in terminal window */

if (ostinfo(&tstat) == 0)
   {					/* successful call */
   tc = tstat.columns;
   if (tc < 8)				/* keep "reasonable" no. of columns */
      tc = 8;
   else if (tc > 127) 
      tc = 127;
   *tcols = tc;
   *tlines = tstat.lines;
   }

}


