/*===========================================================================
  Copyright (C) 1995-2008 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 SCDC +++++++++++++++++++++++
.LANGUAGE C
.IDENTIFICATION Module SCDC.C
.AUTHOR         K. Banse 		ESO - Garching
.KEYWORDS       standard interfaces, descriptors
.ENVIRONMENT    VMS and UNIX
.COMMENTS
holds   SCDDEL, SCDCOP, SCDGETC, SCDFND, SCDINF, YSCDINF

.VERSION  [1.00] 920211:  pulled out from scd.c
080521		last modif
 
----------------------------------------------------------------------------*/

#include <fileexts.h>

#include <stdlib.h>
#include <string.h>


/*

*/

int SCDDEL(imno,descr)

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  delete a descriptor 
.ALGORITHM
  the descriptor directory is scanned for the specified name and if found,
  that name is marked as deleted 
  If descriptor = ' ', reinitialize descriptor area.
.RETURNS
return status  ( 0 = o.k. )
-----------------------------------------------------------------------*/

int imno;     		/* IN : no. of data frame */
char	*descr;		/* IN : descriptor name */

{
int   status, bytelem, noelem, dblock, dindx, dunit, dsclen;

char   dtype[4];
char   realdescr[52], help[72];

struct FCB_STRUCT  *fcbp;

struct FCT_STRUCT  *fctpntr;




if ( (imno < 0) || (imno >= FCT.MAXENT) )
   {
   status = ERR_INPINV;
   goto end_of_it;
   }

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


/*  if descriptor name is '*', reinitialize descriptor area  */
 
if (*descr == '*')
   status = MID_INITDS(fcbp,fctpntr->IOCHAN);   /* do the rest via MID_INITDS */
 
else
   {				 /*  otherwise delete single descriptor  */
   dsclen = DSCNAM_COPY(realdescr,descr);        /* build uppercase name */
   dtype[0] = ' ';
   status = MID_YDSCDIR(imno,'F',realdescr,dtype,
                       &bytelem,&noelem,&dunit,&dblock,&dindx,help);
   if (status == ERR_NORMAL) 
      status = MID_YDSCDIR(imno,'D',realdescr,dtype,
                          &bytelem,&noelem,&dunit,&dblock,&dindx,help);
   }

fctpntr->KAUX[2] = 1;		/* set descriptor-modified flag */
 

end_of_it:				/*  test for info/warnings again  */
if (status != ERR_NORMAL) 
   MID_E2(4,imno,descr,status,1);
 
return (status);
}

/*

*/

int SCDCOP(from,to,mask,dsc)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
Copy descriptors from one frame to another
.ALGORITHM
Depending on 'mask' the relevant descriptors are read from
the source frame + written to the destination frame.
.REMARKS
mask for copying: = 1 , copy all descriptors
                  = 2 , copy only standard desc.
                  = 3 , copy all but standard descriptors
                  = 4 , copy descriptor specified by DSClist
                  = 5 , copy all but extended list of standard descriptors
.RETURNS
return status  ( 0 = o.k. )
--------------------------------------------------*/

int   from;             /* IN: no. of source frame  */
int   to;               /* IN: no. of destination frame  */
int   mask;             /* IN: copy_mask  */
char    *dsc;           /* IN: name of descr. to copy (if mask = 4) */

{
struct FCT_STRUCT  *fctpntri, *fctpntro;



fctpntri = FCT.ENTRIES + from;
if (fctpntri->LINK[0] >= 2)		/* use father frame */
   {
   from = fctpntri->LINK[1];
   fctpntri = FCT.ENTRIES + from;
   }

fctpntro = FCT.ENTRIES + to;
if (fctpntro->LINK[0] >= 2)		/* use father frame */
   {
   to = fctpntro->LINK[1];
   fctpntro = FCT.ENTRIES + to;
   }

if (from != to) 
   {
   if (fctpntro->PROT == 2) 
      return ERR_FILPRO;		/* destination is write protected */

   return YSCDCOP(from,to,mask,dsc);
   }
return ERR_NORMAL;			/* nothing to be done ... */
}

/*

*/

int SCDGETC(imno,descr,felem,maxvals,actvals,values)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
get data from character descriptor and terminate with Null (no trailing blanks)
.ALGORITHM
use SCDRDC
.RETURNS
return status  ( 0 = o.k. )
--------------------------------------------------*/

int   imno	  /* IN : no. of data frame */;
char    *descr    /* IN : descriptor name */;
int felem	  /* IN : position of 1st element to be accessed */;
int maxvals  /* IN : max. no. of characters to be returned */;
int *actvals /* OUT: actual no. of characters returned */;
char    *values   /* OUT: array for descriptor data */;

{
int   status, mynull, myuni;
register int  nr;

register char    mychar;



mynull = -1;
status = SCDRDC(imno,descr,1,felem,maxvals,actvals,values,&myuni,&mynull);



if (status == ERR_NORMAL)
   {				/* get rid of trailing blanks/nulls */
   maxvals = (*actvals) - 1;
   for (nr=maxvals; nr>=0; nr--)
      {
      mychar = values[nr];
      if ((mychar != ' ') && (mychar != '\0'))
         {
         *actvals = ++nr;
         values[nr] = '\0';		/* add null terminator  */
         return (status);
         }
      }
   }

values[0] = '\0';
*actvals = 0;
return (status);
}

/*

*/

int SCDFND(imno,descr,type,noelem,bytelem)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
provide info about descriptor 'descr'
.ALGORITHM
use MID_xDSCDIR to find descr. + related info
.RETURNS
return status  ( 0 = o.k. )
--------------------------------------------------*/

int   imno	/* IN: no. of data frame  */;
char   *descr   /* IN:	descriptor name  */;
char   *type	/* OUT: type of descr - I, R, C, D or ' ' on output */;
int   *noelem	/* OUT: no. of elements  */;
int   *bytelem	/* OUT: no. of bytes per element  */;

{ 	
int   dblock, dindx, snoel, sbytel;
int   dsclen, dunit, status, e_c, e_l;

char  realdescr[52];
char  help[72];

struct FCB_STRUCT  *fcbp;

struct FCT_STRUCT  *fctpntr;



	
/* disable error abort  */

e_c = ERRO_CONT; e_l = ERRO_LOG;  ERRO_CONT = 1; ERRO_LOG = 0;


/*  check imno + type  */
 
if ( (imno < 0) || (imno >= FCT.MAXENT) ) 
   {
   status = ERR_INPINV;
   goto end_of_it;
   }

fctpntr = FCT.ENTRIES + imno;
if (fctpntr->LINK[0] >= 2)			/* use father frame */
   {
   imno = fctpntr->LINK[1];
   fctpntr = FCT.ENTRIES + imno;
   }

dsclen = DSCNAM_COPY(realdescr,descr);	/* build uppercase name */

*type = ' ';
fcbp = fctpntr->FZP;

status = MID_YDSCDIR(imno,'F',realdescr,type,&sbytel,&snoel,&dunit,
                     &dblock,&dindx,help);

if (status != ERR_DSCNPR)
   {
   *noelem = snoel;
   *bytelem = sbytel;
   }

ERRO_CONT = e_c;  ERRO_LOG = e_l;		/* reset error flags  */
return ERR_NORMAL;	
 
end_of_it:
ERRO_CONT = e_c;  ERRO_LOG = e_l;		/* reset error flags  */
MID_E2(7,imno,"SCDFND: ",status,1);
return status;
}

/*

*/

int SCDINF(imno,npos,fno,buf,lbuf,numbuf)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
provide info about descriptor at position 'npos'
.ALGORITHM
go through the descriptor directory and provide the desired info
.RETURNS
return status  ( 0 = o.k. )
--------------------------------------------------*/

int  imno	/* IN : no. of data frame  */;
int  npos	/* IN : position of descriptor, beginning with 1 
			use 0 for the descr. directory itself    */;
int  fno	/* IN : specify desired info, 
                        1 = NAME, 2 = TYPE, 3 = SIZE  
                        4 = NAME,TYPE separated by a comma in `buf'
			    and SIZE in `numbuf'
                        5 = NAME,TYPE separated by a comma in `buf'
			    and SIZE,BYTELEM in `numbuf'
		       98 = return total no. of descriptors (except Help-d.)
		       99 = return total no. of descriptors */;
char   *buf	/* IN : buffer for character descriptor info */;
int lbuf	/* IN : max. length of buffer above  */;
int *numbuf	/* IN : return buffer for numerical data  */;

{ 	
int   status, chanl;
int   snpos;

struct FCT_STRUCT  *fctpntr;

struct FCB_STRUCT  *fcbp;




if ( (imno < 0) || (imno >= FCT.MAXENT) ) 
   {
   status= ERR_INPINV;			/* wrong argument `npos'  */
   goto end_of_it;
   }

snpos = npos + 1;	/* real index is at NPOS+1 because of directory */
if ( (snpos < 1) || (fno < 0) )
   {
   status= ERR_INPINV;			/* wrong argument `npos'  */
   goto end_of_it;
   }

status = ERR_NORMAL;
 
fctpntr = FCT.ENTRIES + imno;
if (fctpntr->LINK[0] >= 2)                      /* use father frame */
   {
   imno = fctpntr->LINK[1];
   fctpntr = FCT.ENTRIES + imno;
   }

chanl = fctpntr->IOCHAN;
fcbp = fctpntr->FZP;

return  YSCDINF(chanl,imno,snpos,fno,buf,lbuf,numbuf);

end_of_it:
MID_E2(7,imno,"SCDINF: ",status,1);
return status;
}

/*

*/

int XSCDINF(chanl,imno,snpos,fno,buf,lbuf,numbuf)

int  chanl;
int  imno; 
int  snpos; 
int  fno;  
char   *buf;
int lbuf;  
int *numbuf;

{
struct FCT_STRUCT  *fctpntr;

struct FCB_STRUCT  *fcbp;


fctpntr = FCT.ENTRIES + imno;
if (fctpntr->LINK[0] >= 2)                      /* use father frame */
   {
   imno = fctpntr->LINK[1];
   fctpntr = FCT.ENTRIES + imno;
   }

chanl = fctpntr->IOCHAN;
fcbp = fctpntr->FZP;

return YSCDINF(chanl,imno,snpos,fno,buf,lbuf,numbuf);

}

/*

*/

int YSCDINF(chanl,imno,snpos,fno,buf,lbuf,numbuf)
/*++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
provide info about descriptor at position 'npos'
.ALGORITHM
go through the descriptor directory and provide the desired info
.RETURNS
return always 0 (checks already done in SCDINF)
--------------------------------------------------*/

int  chanl;	/* IN: I/O chanl of frame */
int  imno	/* IN: no. of data frame  */;
int  snpos	/* IN: incremented position of descriptor */;
int  fno	/* IN: specify desired info, 
                        1 = NAME, 2 = TYPE, 3 = SIZE  
                        4 = NAME,TYPE separated by a comma in `buf'
                        5 = NAME,TYPE separated by a comma in `buf'
                            and SIZE,BYTELEM in `numbuf'
		       99 = return total no. of descriptors */;
char   *buf	/* IN: buffer for character descriptor info */;
int lbuf	/* IN: max. length of buffer above  */;
int *numbuf	/* IN: return buffer for numerical data  */;

{ 	
int   ext, dirfirst, dirused, dirsize, dirlen, diroff, totext;
int   nullo;
int   mm, npos;
register int  nr, direntry;


char  *dscpntr;
register char  *cpt;

struct FCT_STRUCT  *fctpntr;

struct FCB_STRUCT  *fcbp;

static int  mapdscdir = -1;
static char  *dscdir;



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

dirused = fcbp->DFILLED;
dirsize = fcbp->DSIZE;
totext = dirsize/fcbp->DIREXT;      /* total no. of extensions for directory */
dscpntr = (char *) &YDSCDIR_ENTRY;
direntry = fcbp->DIRENTRY;

ext = 1;
npos = 0;
diroff = 0;


pos_loop:
dirfirst = diroff + 1;
dirlen = dirused - diroff;
if (fcbp->DIREXT < dirlen) 
   dirlen = fcbp->DIREXT;    /* read max. 2500/6000 chars. */


if (mapdscdir < 0)                      /* allocate working buffer */
   {                                    /* for descr. directory */
   dscdir = (char *)malloc((size_t)fcbp->DIREXT);	/* 2500/6000 bytes */
   mapdscdir = 1;
   }


if (fno > 90)
   {
   nullo = -1;
   (void) MID_RDSCRC(chanl,fcbp->PTRLDB,0,dirfirst,dirlen,dscdir,&nullo);
   cpt = dscdir;

   nr = 0;
   while (nr < dirlen)
      {
      if (*cpt != '\0') npos ++;	/* test if entry is used */
      cpt += direntry;  nr += direntry;
      }


   /*  maybe we need another segment (next extension) of descr. directory  */

   if (ext < totext)
      {
      ext ++ ;             /* prepare reading of next directory segment */
      diroff += fcbp->DIREXT;
      if (diroff < dirused) goto pos_loop;	/* and loop more... */
      }

   *numbuf = --npos;		/* remove descriptor directory itself */
   return (ERR_NORMAL);
   }


/*  here for all the other functions */

nullo = -1;
(void) MID_RDSCRC(chanl,fcbp->PTRLDB,0,dirfirst,dirlen,dscdir,&nullo);
cpt = dscdir;

nr = 0;
while (nr < dirlen)
   {
   if (*cpt != '\0')              /* test if entry is used */
      {
      if (++npos == snpos) 		/* always increment `npos' */
         {
         (void) memcpy(dscpntr,cpt,(size_t)fcbp->DIRENTRY);
         goto descr_found;
         }
      }
   cpt += direntry;  nr += direntry;
   }


/*  we need another segment (next extension) of descr. directory  */

if (ext < totext)
   {
   ext ++ ;             /* prepare reading of next directory segment */
   diroff += fcbp->DIREXT;
   if (diroff < dirused) goto pos_loop;	/* and loop more... */
   }

memset((void *)buf,32,(size_t)lbuf);	/* npos too large */
*numbuf = 0;
return (ERR_NORMAL);


descr_found:
switch(fno)
   {
   case 1:
   mm = YDSC_PNTR->NAMELEN;
   if (mm > lbuf) mm = lbuf;
   (void) memcpy(buf,YDSC_PNTR->NAMESTR,(size_t)mm);
   break;

   case 2:
   (void) MID_TYPINFO(YDSC_PNTR->TYPE,YDSC_PNTR->BYTELEM,buf,lbuf);
   break;

   case 3:
   if (snpos == 1)
      *numbuf = dirused;
   else
      *numbuf = YDSC_PNTR->NOELEM;
   break;

   case 4:
   mm = YDSC_PNTR->NAMELEN;
   if (mm >= lbuf)
      (void) memcpy(buf,YDSC_PNTR->NAMESTR,(size_t)lbuf);
   else
      {
      (void) memcpy(buf,YDSC_PNTR->NAMESTR,(size_t)(mm+1));
      lbuf -= mm;
      if (lbuf > 1)
         {
         buf[mm] = ',';
         lbuf --;
         (void) MID_TYPINFO(YDSC_PNTR->TYPE,YDSC_PNTR->BYTELEM,
                            buf+mm+1,lbuf);
         }
      }
   break;

   default:				/* case 5 */
   mm = YDSC_PNTR->NAMELEN;
   if (mm >= lbuf)
      (void) memcpy(buf,YDSC_PNTR->NAMESTR,(size_t)lbuf);
   else
      {
      (void) memcpy(buf,YDSC_PNTR->NAMESTR,(size_t)(mm+1));
      lbuf -= mm;
      if (lbuf > 1)
         {
         buf[mm] = ',';
         lbuf --;
         (void) MID_TYPINFO(YDSC_PNTR->TYPE,YDSC_PNTR->BYTELEM,
                            buf+mm+1,lbuf);
         }
      
      if (snpos == 1)
         *numbuf++ = dirused;
      else
         *numbuf++ = YDSC_PNTR->NOELEM;
      *numbuf = YDSC_PNTR->BYTELEM;
      }
   }

return (ERR_NORMAL);
}
