/*===========================================================================
  Copyright (C) 1995-2011 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
===========================================================================*/

/*+++++++++++++++++++++++ SC interface module SCFB +++++++++++++++++++++++
.LANGUAGE C
.IDENTIFICATION Module scfb.c
.AUTHOR         K. Banse 		ESO - Garching
.KEYWORDS       standard interfaces, bulk data files
.ENVIRONMENT    VMS and UNIX
.COMMENTS 
holds SCFOPN, SCFCLO, SCFIDI, SCFMAP, SCFUNM
.REMARKS
opening modes are: F_I_MODE, F_O_MODE, F_IO_MODE, F_X_MODE.                
data types are: D_R4_FORMAT, D_I2_FORMAT, D_I1_FORMAT, D_OLD_FORMAT.         
filetype no's are: F_IMA_TYPE, F_TBL_TYPE, F_FIT_TYPE.              

.VERSION  [1.00] 920212: pulled over from scf.c

 110202
----------------------------------------------------------------------------*/

#include <stdio.h>
#include  <fcntl.h>
#include <stdlib.h>

#include <fileexts.h>
#include <fitsdef.h>
#include <computer.h>
#include <fsydef.h>
#include <osyparms.h>



static struct FCT_STRUCT  *fctpntr;

/*

*/

int SCFOPN(name,dattype,newopn,filtype,imno)

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
open a frame + return its file no.
.ALGORITHM
use CGN_CLEANF + MID_ACCFRM to do the job
.RETURNS
return status ( 0 = o.k )
-----------------------------------------------------------------------*/

char	*name;     	/* IN: name of data frame */
int dattype;     	/* IN: data types as defined in Module header  */
int   newopn;		/* IN: new_open_flag:
                               = 0, open normally   
                               = 1, open same file again + get new imno */
int  filtype;      	/* IN: filetype, e.g. F_IMA_TYPE, ... */
int   *imno;		/* IN/OUT: file no. of the frame, if `imno' given on
				   input, try to return the same no. ...  */

{
int   i, status, sta[3], end[3], newsize, iext;
int   tno, mm, fctnew, namtyp, part_no;
static int   subcount=0;			/* for extracted frames */

float  rbuf;

double dbuf;

char   temp[200], cbuf[44];

struct FCB_STRUCT  *fcbp;




/*
printf("entering SCFOPN with name = %s\n",name);
*/


/*  check file name */
 
status = CGN_CLEANF(name,filtype,temp,FCT_NAME_LEN,&namtyp,&part_no);
if (status != 0) 
   {
   status = ERR_FILNAM;			/* invalid syntax */
   MID_E1(3,name,status,1);
   return status; 
   }


/*  access bulk data frame + get FCB in  */

if (part_no < 0) 			/* we access a FITS extension */
   {
   fctnew = 0;
   mm = - part_no;			/* extension after name[mm] */
   i = CGN_CNVT(&name[mm+1],1,1,&iext,&rbuf,&dbuf);
   if (i != 1)
      {
      status = ERR_FITEXT;
      MID_E1(3,temp,status,1);
      return status;
      }

   /*
   printf("SCFOPN: call ACCFITS(%s,..) with extension = %d\n",temp,iext);
   */
   status = MID_ACCFITS(temp,newopn,iext,imno);
   if (status != ERR_NORMAL) 
      {
      MID_E1(3,temp,status,1);
      return status; 
      }
   }
    
else
   {
   if (newopn > 0) 			/* open file again for other work */
      mm = 1;
   else
      mm = 0;
   /*
   printf("SCFOPN: call ACCFRM(%s,...\n",temp);
   */
   status = MID_ACCFRM(temp,mm,imno,&fctnew);	/* get file into FCT */
   if (status != ERR_NORMAL)
      {
      /*
      printf("SCFOPN: call ACCFITS(%s,...\n",temp);
      */
      if (status == ERR_VERNOR)		/* if Version problem, try FITS */
         status = MID_ACCFITS(temp,newopn,-1,imno);
      if (status != ERR_NORMAL) 
         {
         MID_E1(3,temp,status,1);
         return status; 
         }
      else
         MID_POPERR();		/* pop ACCFRM error from stack again */
      }
   }

fctpntr = FCT.ENTRIES + (*imno);
fcbp = fctpntr->FZP;


/* if not F_OLD_TYPE, test if file types match  */

if (filtype != F_OLD_TYPE)
   {
   if (fcbp->BDTYPE[0] == 'F')
      mm = F_FIT_TYPE;
   else if (fcbp->BDTYPE[0] == 'T')
      mm = F_TBL_TYPE;
   else
      mm = F_IMA_TYPE;

   /* for old FIT files we still have fcbp->BDTYPE[0] = 'I'   */

   if ((filtype != mm) && (filtype != F_FIT_TYPE))
      SCTPUT("Warning: file type of frame + of SCFOPN don't match...!");
   }

   
/* store required data type + default access mode  */

if (fctnew == 0)		/* file not already open,  */
   {				/* so we update DATTYP + ACCESS */
   fctpntr->ACCESS = 'I';
   if (dattype == D_OLD_FORMAT) 
      dattype = fctpntr->FORMAT;		/* take current data type  */
   fctpntr->DATTYP = dattype;
   }
else
   {
   if (fctpntr->DATTYP == D_OLD_FORMAT)
      {
      if (dattype == D_OLD_FORMAT) dattype = fctpntr->FORMAT;
      fctpntr->DATTYP = dattype;
      }

   else if ((dattype != D_OLD_FORMAT) && (dattype != fctpntr->DATTYP))
      {
      if ((fctpntr->FILTYP > 0) && (fctpntr->FITSOUT != 'X'))
         {		 /* it's a FITS file and we didn't get data yet */
         int data_bytes;		/* so change data format */

         fctpntr->DATTYP = dattype;		/* set to new type */
         data_bytes = get_byte(dattype);	/* no. of bytes needed */

         /*  why this? it changes the data format of a FITS file...
         fcbp->NOBYT = data_bytes;	
         fcbp->DFORMAT = dattype;
         fcbp->PIXPBL = OUR_BLOCK_SIZE / data_bytes;
         fcbp->DATAINFO[4] = fcbp->DFORMAT;
         */

         fctpntr->NOBYTE = fcbp->NOBYT;
         fctpntr->FORMAT = fcbp->DFORMAT;
         fctpntr->PIXPBL = fcbp->PIXPBL;
         }
      else
         {
         status = ERR_INPINV;
         (void) snprintf(cbuf,(size_t)44," ... old, new dattype = %d, %d",
                        fctpntr->DATTYP,dattype);
         (void) strcat(temp,cbuf);
         MID_E1(3,temp,status,1);
         return status; 
         }
      }
   }


/* test for subframe option */

if (part_no > 0) 
   {
   status = Fextcor(*imno,&name[part_no],sta,end,&newsize);
   if (status != ERR_NORMAL) 
      {
      MID_E1(3,&name[part_no],status,1);
      return status; 
      }

   (void) snprintf(cbuf,(size_t)44,"MIDas%dX%d.bdf",subcount++,*imno);
   status = SCFCRE(cbuf,dattype,F_O_MODE,F_IMA_TYPE,newsize,&tno);

   if (status != ERR_NORMAL) 
      {
      MID_E1(3,cbuf,status,1);
      return status; 
      }

   fctpntr->LINK[0] = 1;		/* declare as father  */
   fctpntr->LINK[1] ++;			/* increase count of sons  */

   fctpntr = FCT.ENTRIES + tno;
   fctpntr->LINK[0] = 2;		/* declare as son */
   fctpntr->LINK[1] = *imno;		/* and link it to father */
   if (newopn == -1) fctpntr->LINK[0] = 3;	/* only descriptors... */

   status = Fextfr(*imno,sta,end,tno);
   if (status != ERR_NORMAL) 
      {
      (void) strcpy(temp,"actual extraction...");
      MID_E1(3,temp,status,1);
      return status; 
      }

   fctpntr->ACCESS = 'I';		/* SCFCRE had set it to 'O' before.. */
   fctpntr->CATALOG[1] = 'N';
   *imno = tno;				/* return imno of son ...  */
   }

if ((filtype == F_OLD_TYPE) && (fctnew == 0))	/* first time access */
   {
   fctpntr = FCT.ENTRIES + (*imno);
   fctpntr->CATALOG[0] = 'O';	       /* avoid going thru TCTCLO in SCSEPI! */
   }


/* intl FITS table files need special treatment...  */

if (fctpntr->FILTYP > 1)
   {
   char  *datpntr, origname[FCT_NAME_LEN];

   datpntr = fctpntr->BDADDR[0];
   if (fctpntr->O_NAMLEN == 0)
       (void) strcpy(origname,fctpntr->NAME);
   else					/* internal FITS file */
       {
       (void) strcpy(origname,fctpntr->NAME+4);
       mm = fctpntr->O_NAMLEN - 4;		/* we just removed leading "FITZ" */
       origname[mm] = '\0';
       }
   status = MID_fitsin(2,origname,-1,"",datpntr,imno,&i);
   status = TCTFIX(*imno);		/* write table control descriptors */
   fctpntr->ACCESS = 'I';		/* reset */
   fctpntr->KAUX[2] = 0;
   }


fctpntr->CR_FLAG = 2;			/* mark as just opened */
return status;
}
/*

*/

int SCFCLO(imno)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
release a frame
.ALGORITHM
find frame entry + add frame to catalogue, if FCT_CATALOG[1] = Y, 
.RETURNS
return status ( 0 = o.k )
--------------------------------------------------*/

int   imno;	  /* IN: file no. of data frame */

{
int   i, mm, fitsout, fitsupdate, status;

char  cc, temp[200], cbuf[88];
char  origname[FCT_NAME_LEN], *nampntr;

struct FCB_STRUCT  *fcbp;

struct FCT_STRUCT  *fctpntrz;

struct LDB_STRUCT  *ldbp;



/*
printf("entering SCFCLO(%d)\n",imno);
*/

if ( (imno < 0) || (imno >= FCT.MAXENT) )
   {
   status = ERR_INPINV;
   MID_E2(1,imno,"...",status,1);
   return status;
   }

fctpntr = FCT.ENTRIES + imno;
if (fctpntr->NAME[0] == ' ') return ERR_NORMAL;     /*  nothing to do ...  */


if (fctpntr->ACCESS == 'X')		/* if scratch file, not much to do */
   {		
   if (fctpntr->BDADDR[0] != (char *) 0)
      {
      free(fctpntr->BDADDR[0]);
      fctpntr->BDADDR[0] = (char *) 0;
      free(fctpntr->FZP);
      }
   fctpntr->NAME[0] = ' ';
   fctpntr->LINK[0] = 0;
   fctpntr->LINK[1] = 0;
   return ERR_NORMAL;
   }

/*
printf("SCFCLO: %s with descr_access = %d\n",fctpntr->NAME,fctpntr->KAUX[2]);
*/


fcbp = fctpntr->FZP;
if ( (fctpntr->PROT != 2) && (fctpntr->KAUX[2] == 1) )
   {
   (void) cacheLDB(3,fctpntr->IOCHAN,-1,&ldbp); /* write out last LDB */
   (void) OSY_WVB(fctpntr->IOCHAN,(char *)fcbp,512,1);	/* fixed size (512) */
   }
else
   (void) clearLDB(fctpntr->IOCHAN);         /* clear LDB cache */


/* if catalog is enabled, add this entry */

if (fctpntr->CATALOG[1] != 'N')                 /*  check catalog flag  */
   {
   int  e_c, e_d, e_l, n0=0, n1=1;

   mm = OFF_CATAL;
   i = KIWORDS[OFF_CATINF+10];       /* length of catalog file name  */
   cc = fctpntr->CATALOG[0];

   if (cc == 'T')
      mm += i;
   else if (cc == 'F')
      mm += (i+i);

   (void) memcpy(cbuf,&KCWORDS[mm],(size_t)i);
   cbuf[i] = '\0';
   mm = CGN_INDEXC(cbuf,' ');                   /* truncate file name  */
   if (mm > 0) cbuf[mm] = '\0';

   SCECNT("GET",&e_c,&e_d,&e_l);
   SCECNT("PUT",&n1,&n0,&n0);                   /* disable SC errors */

   status = SCCADD(cbuf,fctpntr->NAME,"         ");

   SCECNT("PUT",&e_c,&e_d,&e_l);
   fctpntr->CATALOG[1] = 'N';
   }


/* if we have subframes, these have to be treated first... */

if ((fctpntr->LINK[0] == 1) && (fctpntr->LINK[1] > 0))
   {                                    /* we're the main frame */
   fctpntrz = FCT.ENTRIES;

   /* 
   printf("for %s LINK[0,1] = %d, %d - we have sons...\n",
   fctpntr->NAME,fctpntr->LINK[0],fctpntr->LINK[1]);  
   */

   for (i=0; i<FCT.MAXENT; i++) /* look for all the sons  */
      {
      if ((fctpntrz->NAME[0] != ' ') &&         /* only filled entries */
          (fctpntrz->LINK[0] == 2) && (fctpntrz->LINK[1] == imno) &&
          (fctpntrz->ACCESS == 'O'))
         {
         if (fctpntrz->BDADDR[0] != (char *) 0)       /* release memory */
            {
            if (fctpntrz->DATTYP == fctpntrz->FORMAT)
               (void) wrdisk(i,fctpntrz->KAUX[0],fctpntrz->KAUX[1],
                             fctpntrz->BDADDR[0]);
            else
               (void) conv_dat(2,i,fctpntrz->KAUX[0],fctpntrz->KAUX[1],
                               &mm,fctpntrz->BDADDR);
            }
         Finsfr(imno,i);
         fctpntrz->ACCESS = 'I';        /* clear access mode of son */
         }
      fctpntrz ++;
      }
   fctpntr->LINK[1] = 0;                /* all possible sons processed */
   }


/* check, if we close the memory based version of an existing FITS file 
   if yes, test if it has been updated/overwritten */

fitsout = 0;
fitsupdate = 0;				/* default to update=NO */


/* process a FITS file */

if (fctpntr->FILTYP > 0)
   {
   if (fctpntr->O_NAMLEN == 0)
       (void) strcpy(origname,fctpntr->NAME);
   else					/* internal FITS file */
       {
       (void) strcpy(origname,fctpntr->NAME+4);
       i = fctpntr->O_NAMLEN - 4;             /* we removed leading "FITZ" */
       origname[i] = '\0';
       }
   nampntr = origname;
   }
else
   nampntr = fctpntr->NAME;

if (fctpntr->FILTYP > 0)
   {
   if (fctpntr->FITSEXT == 0)		/* only process, if no FITS extension */
      {
      fitsupdate = KIWORDS[OFF_AUX+13];	/* get FITS update flag */
      if (fitsupdate == 1) 	/* o.k. - we write a FITS file, so test */
         {			/* if descr and/or data has changed */
         if ((fctpntr->ACCESS == 'O') &&
             (fctpntr->BDADDR[0] != (char *) 0)) 
            {				/* BDADDR[0] only set for images */
            fctpntr->KAUX[2] = 0;	/* avoid only updating descrs */
            }

         else if (fctpntr->KAUX[2] != 1) /* skip writing a FITS file */
            goto set_ACCESS;

         status = SCFSAV(imno,1);	/* dump descr or descr+data to FITS */
         if (status != ERR_NORMAL)
            fitsout = -1;		/* indicate FITS trouble */
         else
            fitsout = 1;		/* rename also tables in SCFCLO */
         }
      }

  set_ACCESS:
   fctpntr->ACCESS = 'I';		/* avoid writing to disk again */
   }

else			/* check, if we store new frames in FITS format */
   {
   if (fctpntr->ACCESS == 'O') 
      fitsout = KIWORDS[OFF_AUX+12];		/* get FITS output flag */

   if (fitsout == 1)
      {
      mm = fctpntr->NAMLEN - 4;
      if (fctpntr->CATALOG[0] == 'T')
         {
         if (strncmp(fctpntr->NAME+mm,".tbl",4) == 0) 
            {
            fitsout = 0;
	    goto write_to_disk;
            }

         fitsout = -99;				/* set flag for TCTCLO ... */
         }
      else
         {
         if (strncmp(fctpntr->NAME+mm,".bdf",4) == 0) 
            {
            fitsout = 0;
	    goto write_to_disk;
            }

         if (fctpntr->BDADDR[0] != (char *) 0)	/* for images convert to */
            {					/* FITS format right away */
            if (fctpntr->DATTYP == fctpntr->FORMAT)
               status = wrdisk(imno,fctpntr->KAUX[0],fctpntr->KAUX[1],
                               fctpntr->BDADDR[0]);
            else                           /* mismatched frame + writing data */
               status = conv_dat(2,imno,fctpntr->KAUX[0],fctpntr->KAUX[1],
                                 &mm,fctpntr->BDADDR);
            if (status != ERR_NORMAL) goto end_2;
            }


         status = SCFSAV(imno,0);		/* dump descr+data to FITS */
         if (status != ERR_NORMAL) fitsout = -1;
         }

      fctpntr->ACCESS = 'I';		/* avoid saving anything */
      }
   }

	
write_to_disk:
status = ERR_NORMAL;
if (fctpntr->BDADDR[0] != (char *) 0)		/* release allocated memory */
   {				
   if (fctpntr->ACCESS == 'O')			/* so, no FITS files here... */
      { 
      if (fctpntr->DATTYP == fctpntr->FORMAT)
         status = wrdisk(imno,fctpntr->KAUX[0],fctpntr->KAUX[1],
                         fctpntr->BDADDR[0]);
      else				/* mismatched frame + writing data */
         status = conv_dat(2,imno,fctpntr->KAUX[0],fctpntr->KAUX[1],
                           &mm,fctpntr->BDADDR);
      }

   free(fctpntr->BDADDR[0]);			/* also for the FITS guys */
   fctpntr->BDADDR[0] = (char *) 0;
   if (status != ERR_NORMAL) goto end_2;
   }


/* if we are a subframe of somebody else, we must first update the father */

if (fctpntr->LINK[0] > 1) 
   {					/* we're the subframe */
   if (fctpntr->ACCESS == 'O')
      {
      i = fctpntr->LINK[1];
      Finsfr(i,imno);
      fctpntrz = FCT.ENTRIES + i;
      fctpntrz->LINK[1] --;		/* decrement count of sons */
      fctpntr->ACCESS = 'I';
      }
   if (FCT.PARM[2] == 1) 
      {					/* delete temp file */
      status = osfdelete(fctpntr->NAME);
      if (status != 0)
         {
         status = ERR_INPINV;
         (void) snprintf(temp,(size_t)200,
                "SCFCLO/osfdelete: %s ",fctpntr->NAME);
         MID_ERROR("MID",temp,status,0);
         }
      else
         status = ERR_NORMAL;
      }
   }


/* close the file on disk*/
 
status = OSY_DASSGN(imno,0);			/* 2nd par. not used */
if (status != ERR_NORMAL) goto end_2;		/* skip the rest... */

if (fitsout != 0)			/* some FITS stuff to handle... */
   {
   if (fitsout == 1)			/* we have to rename temp. FITS file */
      {
      status = osfrename("midFITS.mt",nampntr);
      if (status != 0)
         {
         status = ERR_INPINV;
         (void) snprintf(temp,(size_t)200,
                "SCFCLO/osfrename: %s ",nampntr);
         MID_ERROR("MID",temp,status,0);
         }
      }
   else if (fitsout == -1) 	/* we had a problem writing the FITS file */
      status = ERR_FILBAD;
   }

else if ((fctpntr->COMPRESS != 0) && (KIWORDS[OFF_AUX+20] == 0))
   {						/* compress frame again */
   char  *Nullptr = (char *) 0;
			/* AUX_MODE(21) for recompressing or not */
   if (fctpntr->COMPRESS == 1)
      (void)snprintf(temp,(size_t)200,"compress %s",nampntr);
   else
      (void)snprintf(temp,(size_t)200,"gzip %s",nampntr);
   oshcmd(temp,Nullptr,Nullptr,Nullptr);
   }


/* now free allocated memory as much as we can */

if (fctpntr->FILTYP > 0)                     /* its a FITS file */
   {
   BFDEF  *bfdefptr;
   TXDEF  *txptr;
   char   *cpntr;

   if (fctpntr->FITSADDR[2] != (char *) 0)
      {
      free((char *) fctpntr->FITSADDR[2]);
      fctpntr->FITSADDR[2] = (char *) 0;
      }
   if (fctpntr->FITSADDR[1] != (char *) 0)
      {
      free((char *) fctpntr->FITSADDR[1]);
      fctpntr->FITSADDR[1] = (char *) 0;
      }
   if (fctpntr->FITSADDR[0] != (char *) 0)
      {
      bfdefptr = (BFDEF *) fctpntr->FITSADDR[0];
      cpntr = bfdefptr->extd;
      if (cpntr != (char *) 0)
         {
         txptr = (TXDEF *) cpntr;
         free((char *) txptr->col);
         free(cpntr);
         }
      free((char *) fctpntr->FITSADDR[0]);
      fctpntr->FITSADDR[0] = (char *) 0;
      }
   status = 0;
   }


end_2:
fctpntr->NAME[0] = ' ';
fctpntr->NAME[1] = '\0';
fctpntr->LINK[0] = 0;
fctpntr->LINK[1] = 0;
free(fctpntr->FZP);


/* make sure, old_imno is reset in MID_DSCDIR... */

temp[0] = ' ';
MID_DRESET();

if (status != ERR_NORMAL) MID_E2(1,imno,"...",status,1);


/***************

OSY_COUNT(&i,&mm);
printf("OSY_RVB %d times	OSY_WVB %d times\n",i,mm);

***************/


if (fitsout == -99)		/* we still have to convert  a table to FITS */
   return fitsout;
else
   return status;
}
/*

*/

int SCFMAP(imno,iomode,felem,size,actsize,pntr)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
map a new data frame into memory for writing/reading 
or just get virtual memory (iomode = 9)

.ALGORITHM
return pointer to first element which is required

.RETURNS
return status ( 0 = o.k )

.REMARKS
parameter 'iomode' may be: 
0 for input (read only), 
1 for output (write), 
2 for in/output (read + write),
9 for scratch file = get virtual memory 

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

int   imno;	/* IN : file no. of data frame */
int   iomode;	/* IN: opening mode, e.g. F_O_MODE, ... */
int   felem;	/* IN : 1st pixel to be accessed in data space */
int   size;	/* IN : number of data values (pixels) to be mapped */
int   *actsize;	/* OUT: actual no. of pixels mapped */
char  **pntr;	/* OUT: pointer to data in memory */

{
char  *mypntr, *errpntr;

int   nbytes, nopix;
int   i, mm, status;

unsigned int  allbytes;





mypntr = (char *) 0;
if ( (imno < 0) || (imno >= FCT.MAXENT) )	/*  check 'imno' + 'felem' */
   {
   status = ERR_INPINV;
   goto sect_2000;
   }

fctpntr = FCT.ENTRIES + imno;

if ( (fctpntr->NAME[0] == ' ') || (felem <= 0) )
   {
   status = ERR_INPINV;
   goto sect_2000;
   }


status = ERR_NORMAL;
if (size < 1) 				/* if no size given, map all pixels  */
   nopix = fctpntr->SIZE;		/* no. of pixels required by user  */
else
   nopix = size;

*actsize = nopix;


if (fctpntr->BDADDR[0] != (char *) 0)
   {
   if (fctpntr->FILTYP > 0)			/* its a FITS file */
      {
      nbytes = get_byte(fctpntr->DATTYP);	/* data format we want */
      *actsize = size;				/* we mapped everything */
      felem --;					/* at the first call...*/
      mm = felem * nbytes;
      *pntr = fctpntr->PNTR + mm;
      return (ERR_NORMAL);	
      }

   if ((felem == fctpntr->KAUX[0]) &&
       (size == fctpntr->KAUX[1]))
      {
      *actsize = size;
      *pntr = fctpntr->PNTR;
      return (ERR_NORMAL);		/* repeated call */
      }

   if (fctpntr->ACCESS == 'O')		/* write out previous data */
      {
      if (fctpntr->DATTYP == fctpntr->FORMAT)
         status = wrdisk(imno,fctpntr->KAUX[0],fctpntr->KAUX[1],
                         fctpntr->BDADDR[0]);
      else                          /* mismatched frame + writing data */
         status = conv_dat(2,imno,fctpntr->KAUX[0],fctpntr->KAUX[1],
                           &mm,fctpntr->BDADDR);
      }
   (void) free(fctpntr->BDADDR[0]);	/* and release previous memory */
   fctpntr->BDADDR[0] = (char *) 0;
   fctpntr->PNTR = (char *) 0;

   if (status != ERR_NORMAL) return status;
   }

	


/***************************************************
  iomode = F_X_MODE,  just allocate virtual memory  
****************************************************/
	
	
if (iomode == F_X_MODE)
   {
   nbytes = fctpntr->NOBYTE;		/* no. of bytes per pixel */
   allbytes = (unsigned int) (nopix * nbytes);
   mypntr = malloc((size_t)allbytes);				/* ANSI C */

   if (mypntr == (char *) 0) 
      {
      status = ERR_MEMOUT;
      goto sect_2000;
      }
   fctpntr->BDADDR[0] = mypntr;
   fctpntr->ACCESS = 'X';
   }
	

/************************************************************	
   normal mode - allocate memory + read data in
*************************************************************/	
	

else
   {
   if (fctpntr->FILTYP > 0)			/* its a FITS file */
      {
      char dum[2];
      int  nono;
 

      if (nopix < fctpntr-> SIZE)
         nono = 1;			/* we asked for sub_area */
      else
         nono = 0;			/* we asked for everything */


      /* always map everything */

      nbytes = get_byte(fctpntr->DATTYP);	/* data format we want */
      allbytes = (unsigned int) (fctpntr-> SIZE * nbytes);
      mypntr = malloc((size_t)allbytes);
      if (mypntr == (char *) 0)
         {
         status = ERR_MEMOUT;
         goto sect_2000;
         }

      if (fctpntr->FILTYP != 22)	/* if it was not mapped as */
         {				/* a table yet... (dummyPUT)  */
         char  origname[FCT_NAME_LEN];

         dum[0] = '\0';
	 if (fctpntr->O_NAMLEN == 0)
	     (void) strcpy(origname,fctpntr->NAME);
	 else					/* internal FITS file */
	     {
	     (void) strcpy(origname,fctpntr->NAME+4);
	     mm = fctpntr->O_NAMLEN - 4;        /* we just removed leading "FITZ" */
	     origname[mm] = '\0';
	     }
         mm = imno;                             /* get data as real */
         status = MID_fitsin(2,origname,-1,dum,mypntr,&mm,&i);
         /*
         printf("SCFMAP: called fitsin(%s,..) with mm = %d\n",origname,mm);
         MID_SHOWFCT2(mm);
         */
         }

 
      fctpntr->BDADDR[0] = mypntr;
      if (iomode != F_I_MODE)
         fctpntr->ACCESS = 'O';
      else
         fctpntr->ACCESS = 'I';

      fctpntr->KAUX[0] = 1;;
      fctpntr->KAUX[1] = fctpntr->SIZE;
      fctpntr->PNTR = mypntr;

      if (nono == 1)			/* we have to update the pointer */
         {
         felem --;
         mypntr = fctpntr->BDADDR[0] + (felem * nbytes);
        }
      *pntr = mypntr;
      return status;
      }

   else
      {
      if (fctpntr->DATTYP != fctpntr->FORMAT)
         {					/* cannot be F_O_MODE ...  */
         status = conv_dat(1,imno,felem,nopix,&mm,fctpntr->BDADDR);
         mypntr = fctpntr->BDADDR[0];		     /* was set in conv_dat */
         }
      else
         {
         nbytes = fctpntr->NOBYTE;		/* no. of bytes per pixel */
         allbytes = (unsigned int) (nopix * nbytes);
         mypntr = malloc((size_t)allbytes);

         if (mypntr == (char *) 0)
            {
            status = ERR_MEMOUT;
            goto sect_2000;
            }
         fctpntr->BDADDR[0] = mypntr;

         if (iomode != F_O_MODE)
            status = rddisk(imno,felem,nopix,&mm,mypntr);
         }

      if (status != ERR_NORMAL) goto sect_2000;

      if (iomode != F_I_MODE)
         {
         fctpntr->ACCESS = 'O';
         if (fctpntr->PROT == 2)
            {
            status = ERR_FILPRO;
            goto sect_2000;
            }
         }
      }
   }

fctpntr->KAUX[0] = felem;
fctpntr->KAUX[1] = nopix;
fctpntr->PNTR = mypntr;
*pntr = mypntr;

return status;


/* here if problems...  */

sect_2000:
errpntr = (char *) malloc((size_t) 44);
if (status == ERR_MEMOUT)
   {
   nbytes = get_byte(fctpntr->DATTYP);		/* data format we want */
   allbytes = (unsigned int) (nopix * nbytes);
   (void) snprintf(errpntr,(size_t)44,"file size = %d bytes",(int)allbytes);
   }
else
   {
   (void) snprintf(errpntr,(size_t)44,"with iomode = %d",iomode);
   free(mypntr);
   }
MID_E2(2,imno,errpntr,status,1);
free(errpntr);
return (status);
}
/*

*/

int SCFUNM(imno)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
release mapped memory of a data frame
.ALGORITHM
.RETURNS
integer return status ( 0 = o.k )
--------------------------------------------------------*/

int   imno		/* IN: file of data frame */;

{
int  mm, status;


if ( (imno < 0) || (imno >= FCT.MAXENT) )
   status = ERR_INPINV;

else
   {
   fctpntr = FCT.ENTRIES + imno;
   if (fctpntr->NAME[0] == ' ')
      status = ERR_INPINV;


   /*  input o.k. - release allocated memory + update frame if necessary */
   
   else
      {
      status = ERR_NORMAL;
      if (fctpntr->BDADDR[0] != (char *) 0) 
         {
         if (fctpntr->ACCESS == 'O') 
            {
            if (fctpntr->DATTYP == fctpntr->FORMAT)
               status = wrdisk(imno,fctpntr->KAUX[0],fctpntr->KAUX[1],
                               fctpntr->BDADDR[0]);
            else                          /* mismatched frame + writing data */
               status = conv_dat(2,imno,fctpntr->KAUX[0],fctpntr->KAUX[1],
                                 &mm,fctpntr->BDADDR);
            } 
         (void) free(fctpntr->BDADDR[0]);
         fctpntr->BDADDR[0] = (char *) 0;
         fctpntr->PNTR = (char *) 0;
         }
      }
   }

if (status != ERR_NORMAL)
   MID_E2(3,imno,"...",status,1);

return (status);
}


