/*===========================================================================
  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
===========================================================================*/

/*+++++++++++++++++++++ Module MIDDSCA +++++++++++++++++++++++++++++++++++++++
.LANGUAGE   C
.IDENTIFICATION  MIDDSCA.C
.AUTHOR   Klaus Banse		ESO - Garching
.COMMENTS
holds  INITDS, WDSCRI, WDSCRR, WDSCRC, RDSCRI, RDSCRR, RDSCRC,
       CLONEDS
.KEYWORDS MIDAs Descriptors
.ENVIRONMENT VMS and UNIX
.VERSION  [1.30]  861110: creation from FORTRAN version
.VERSION  [2.50]  910718: initialize some variables in the next_descr branch

 080521		last modif

------------------------------------------------------------------------*/
 
#include <fileexts.h>
 
#define   BIT_0   0x1
 
#define  READ         0
#define  WRITE        1
#define  READ_WRITE   2
#define  APPEND       3
 
void LDBinfo();
 
/*

*/
 
int MID_CLONEDS(fcbp,iochan,fctpntri)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
clone the descr. blocks (LDBs) of imnoa to imnob
.ALGORITHM
use OSY_RVB, OSY_WVB
.RETURNS
status: I*4             return status
--------------------------------------------------*/

struct FCB_STRUCT  *fcbp;	/* IN: pointer to FCB of result frame */
int  iochan;			/* IN: channel of frame */
struct FCT_STRUCT  *fctpntri;	/* IN: pointer to FCT of source data frame */

{
register int  nr, mr;
int  status, ichan;
int  count, firsty;

char  *cptr;

struct LDB_STRUCT  *ldbp;

struct FCB_STRUCT  *fcbpi;



status = cacheLDB(22,iochan,fcbp->PTRLDB,&ldbp);	/* create cache */

ichan = fctpntri->IOCHAN;
fcbpi = fctpntri->FZP;

fcbp->DIRENTRY = YENTRY_SIZE;     /* entry in descr. direc. = 100 chars */
fcbp->DIREXT = 6000;         /* one extension = 60 entries (6000 chars) */

fcbp->INLDB[0] = fcbpi->INLDB[0]; 
fcbp->INLDB[1] = fcbpi->INLDB[1]; 
fcbp->ENDLDB = fcbpi->ENDLDB; 
fcbp->ENDLDB_OFF = fcbpi->ENDLDB_OFF; 
fcbp->DSIZE = fcbpi->DSIZE;
fcbp->DFILLED = fcbpi->DFILLED;

cptr = (char *) ldbp;
nr = mr = fcbp->PTRLDB;
firsty = count = 0;

while (nr > 0)
   {
   status = OSY_RVB(ichan,cptr,LDB_SIZE,nr);
   if (status != ERR_NORMAL) goto end_of_it;
   nr = ldbp->NEXT;				/* -> next source LDB */

   ldbp->BLKNUM = mr;
   status = OSY_WVB(iochan,cptr,LDB_SIZE,ldbp->BLKNUM);
   if (status != ERR_NORMAL) goto end_of_it;
   count ++;
   mr = nr;
   }

/*
printf("%d LDBs cloned\n",count);
*/

fcbp->CLONY = 1;			/* descr. were cloned */

/* move 1st LDB into cache */

ldbp->BLKNUM = fcbp->PTRLDB;
status = OSY_RVB(iochan,cptr,LDB_SIZE,ldbp->BLKNUM);
status = cacheLDB(3,iochan,ldbp->BLKNUM,&ldbp);      /* write to disk */
if (status == ERR_NORMAL) return ERR_NORMAL;


end_of_it:
status = ERR_FRMNAC;
MID_ERROR("MIDAS","MID_CLONEDS:",status,0);
return (status);
}

/*

*/
 
int MID_INITDS(fcbp,iochan)
 
/*++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
initialize the descr. directory + update the FCB accordingly
.ALGORITHM
set up the descr. directory exactly like any other descriptor
reserve already LDB's (= 12 blocks) for directory + standard descriptors
.RETURNS
status:	I*4		return status
--------------------------------------------------*/
 
struct FCB_STRUCT  *fcbp;  /* IN: pointer to FCB of frame */
int  iochan;		   /* IN: channel of frame */
 
{
int   kldb, nn, dscdsiz;
int   n, mm, status;
register int  nr;

char   *cpntrb, *dscpntr;

struct LDB_STRUCT  *ldbp;



status = cacheLDB(22,iochan,fcbp->PTRLDB,&ldbp);	/* create cache */

dscdsiz = fcbp->DBEGIN; 
kldb = fcbp->INLDB[0];		/* no. of LDBs needed for dscdir  */
mm = (kldb * LDB_DATA);	/* size in bytes */
n = mm - dscdsiz;		/* space left in `kldb' LDBs  */
nn = (kldb << 2) - 2;		/* (*4 - 2), so blockno.s like 2, 6, 10, 14 */


/*  set up endpointers to include already 1. entry of descr. directory */
 
if (n > 0)
   {
   fcbp->ENDLDB = nn;		/* dscdir fits with extra space */
   mm -= LDB_DATA;			/* no_bytes in full first blocks */
   n = (dscdsiz - mm) / II_SIZE;	/* move to 4-byte  words  */
   fcbp->ENDLDB_OFF = n + 1;		/* offset is in 4-byte words ...  */
   }
else
   {
   fcbp->ENDLDB = nn + 4;		/* dscdir fits with no extra space */
   fcbp->ENDLDB_OFF = 1;
   }

fcbp->DSIZE = dscdsiz - 12;		/* just drop the 12 byte header stuff */

 
/*  calculate initial no. of LDBs and initialize them  */
 
ldbp->LDBWORDS.IWORD[0] = fcbp->DSIZE;
ldbp->LDBWORDS.IWORD[1] = -1;	/* indicate that it's contiguous */
ldbp->LDBWORDS.IWORD[2] = 0;	/* no index into extension block, yet */
	
fcbp->CLONY = 0;                        /* descr. are created from scratch */


/* handle decriptor directory entries */

fcbp->DIRENTRY = YENTRY_SIZE;     /* entry in descr. direc. = 100 chars */
fcbp->DIREXT = 6000;		/* one extension = 60 entries (6000 chars) */
 
YDSC_PNTR->NAMELEN = 
        (short int) CGN_COPY(YDSC_PNTR->NAMESTR,"DESCRIPTOR.DIRECTORY");
YDSC_PNTR->TYPE = 'C';				/* type of descr. */
YDSC_PNTR->HELPLEN = (short int) 0;			/* no help text */
YDSC_PNTR->UNIT = (short int) 0;
YDSC_PNTR->BYTELEM = (short int) 1;
YDSC_PNTR->NOELEM =  fcbp->DSIZE;
YDSC_PNTR->START = fcbp->PTRLDB;	  /* start in 1. LDB (block 2) */
YDSC_PNTR->INDEX = 1;			/* in first data word  */
dscpntr = (char *) &YDSCDIR_ENTRY;
nn = fcbp->DIRENTRY;

fcbp->DFILLED = nn;			/* first entry used for direc. itself */

cpntrb = (char *) &ldbp->LDBWORDS;
cpntrb += (3*II_SIZE);		/* skip 3 integers (= LDB.LDBWORDS.CWORD[12]) */
CGN_COPYALL(cpntrb,dscpntr,nn);		  /* put chardata into word 4,5,6,... */
 
 
/*  
already reserve + link the first LDBs together from no. 2 on 
remember, 4 blocks form an LDB and block 1 = FCB
the descr directory is included
*/
 
nn = fcbp->INLDB[0] + fcbp->INLDB[1];		/* total no. of inital LDBs */

ldbp->BLKNUM = fcbp->PTRLDB;
for (nr=1; nr<nn; nr++)
   {
   ldbp->NEXT = ldbp->BLKNUM + 4;
   status = cacheLDB(3,iochan,ldbp->BLKNUM,&ldbp);	/* write to disk */
   if (status != ERR_NORMAL) goto end_of_it;
   ldbp->BLKNUM = ldbp->NEXT;			/* chain LDBs */
   }

ldbp->NEXT = 0;					/* mark end of LDB list  */
status = cacheLDB(3,iochan,ldbp->BLKNUM,&ldbp);	/* write last LDB to disk */
if (status == ERR_NORMAL) 
   return (status);				 /*  that's it folks... */
 
 
/*  store error codes  */
 
end_of_it:
status = ERR_FRMNAC;
MID_ERROR("MIDAS","MID_INITDS:",status,0);
return (status);
}

/*

*/
 
int MID_RDSCRC(iochan,start_block,start_indx,first,total,cvals,nullo)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
read the contents of a descriptor and its extensions as 
integer/real/character data
.ALGORITHM
The values of a descriptor are returned as integer/real/char. data.
No more than MAXVAL values will be returned, but ACTVAL will
be set to the actual no. of values associated with the
descriptor, starting from the position which is specified as 1. element
.RETURNS 
nothing
--------------------------------------------------*/

int    iochan		/* IN : channel of frame */;
int   start_block	/* IN : start block no. of descriptor */;
int   start_indx	/* IN : start index in that block */;
int   first		/* IN : position of 1. element to be accessed */;
int   total		/* IN : no. of values to return */;
char   *cvals		/* OUT: array to hold descriptor data */;
int   *nullo		/* IO : no. of null values in data */;
  
{
int   bldb, ildb, extens[2];
int   off, begin, end, tval, rval;
int   status;

char    *cpntra;

struct LDB_STRUCT  *ldbp;




/*  set up pointers:
                 begin, end   point to begin + end of descr. data
                 off          points to offset within descr. data  */
  
end = 0;
bldb = start_block;
ildb = start_indx;

status = cacheLDB(1,iochan,bldb,&ldbp);		/* get starting LDB in */


/*  1. loop - look for start descriptor element  */
	
loop_1:
LDBinfo(iochan,ldbp,ildb,&rval,extens);
 
begin = end + 1;				/* keep start index */
end += rval;					/* update end */
	
if (first > end) 
   {
   bldb = extens[0];
   ildb = extens[1] - 1;		   /* indices are counted in FORTRAN */
   if (bldb != ldbp->BLKNUM) 
      status = cacheLDB(1,iochan,bldb,&ldbp);
   goto loop_1;
   }
 

/*  2. loop - fill data with descriptor data  */
	
tval = 0;
off = first - begin + 1;
cpntra = cvals;

/*
nulflag = *nullo;		/. save null flag, -1 means do not check...  ./

				   feature not implemented yet 
if (nulflag >= 0)
   {
   register char  *kpntr;
   register int  nr;

   while (tval < total)
      {
      if (bldb != ldbp->BLKNUM) 
         status = cacheLDB(1,iochan,bldb,&ldbp);
   
      rval = total - tval;
      (void) MID_RDcLDB(iochan,ldbp,ildb,cpntra,off,&rval,extens);

      kpntr = cpntra;			/. handle NULL checks ./
      for (nr=0; nr<rval; nr++)
         {
         if (*kpntr++ == NUL_CVAL) (*nullo) ++;
         }

      tval += rval;
      cpntra += rval;			/. update pointers  ./
      bldb = extens[0];
      ildb = extens[1] - 1;
      off = 1;
      } 
   } 

else
   {
*/

   while (tval < total)
      {
      if (bldb != ldbp->BLKNUM)
         status = cacheLDB(1,iochan,bldb,&ldbp);

      rval = total - tval;
      (void) MID_RDcLDB(iochan,ldbp,ildb,cpntra,off,&rval,extens);

      tval += rval;
      cpntra += rval;			/* update pointers  */
      bldb = extens[0];
      ildb = extens[1] - 1;
      off = 1;
      } 
/*
   } 
*/

*nullo = 0;
return 0;
}

/*

*/
 
int MID_RDSCRI(iochan,start_block,start_indx,first,total,ivals,nullo)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
read the contents of a descriptor and its extensions as
integer/real/character data
.ALGORITHM
The values of a descriptor are returned as integer/real/char. data.
No more than MAXVAL values will be returned, but ACTVAL will
be set to the actual no. of values associated with the
descriptor, starting from the position which is specified as   1. element
.RETURNS 
nothing
--------------------------------------------------*/

int   iochan		/* IN : channel of frame */;
int   start_block	/* IN : start bldb no. of descriptor */;
int   start_indx	/* IN : start index in that bldb */;
int   first		/* IN : position of 1. element to be accessed */;
int   total		/* IN : no. of values to return */;
int   *ivals		/* OUT: array to hold descriptor data */;
int   *nullo		/* IO : no. of null values in data */;
 
{
int   bldb, ildb, extens[2];
int   off, begin, end, tval, rval;
int   status;
int   *ipntr;

float   rdummy;

struct LDB_STRUCT  *ldbp;




/*  set up pointers:
                 begin, end   point to begin + end of descr. data
                 off          points to offset within descr. data  */
  
end = 0;
bldb = start_block;
ildb = start_indx;

status = cacheLDB(1,iochan,bldb,&ldbp);

 
/*  1. loop - look for start descriptor element  */
	
loop_1:
LDBinfo(iochan,ldbp,ildb,&rval,extens);
 
begin = end + 1;				/* keep start index */
end += rval;					/* update end */
	
if (first > end) 
   {
   bldb = extens[0];
   ildb = extens[1] - 1;		   /* indices are counted in FORTRAN */
   if (bldb != ldbp->BLKNUM) 
      status = cacheLDB(1,iochan,bldb,&ldbp);
   goto loop_1;
   }

 
/*  2. loop - fill data with descriptor data  */
	
tval = 0;
off = first - begin + 1;
ipntr = ivals;

/*
nulflag = *nullo;		/. save null flag, -1 means do not check...  ./
 
				   feature not implemented yet 
if (nulflag >= 0)
   {
   register int nr;
   register int *hpntr;

   while (tval < total)
      {
      if (bldb != ldbp->BLKNUM)
         status = cacheLDB(1,iochan,bldb,&ldbp);

      rval = total - tval;
      (void) MID_RDLDB(iochan,ldbp,ildb,1,ipntr,&rdummy,off,
                       &rval,extens);

      hpntr = ipntr;
      for (nr=0; nr<rval; nr++)
         {
         if (*hpntr++ == NUL_IVAL) (*nullo) ++;
         }

      tval += rval;
      ipntr += rval;                       /. update pointers  ./
      bldb = extens[0];
      ildb = extens[1] - 1;
      off = 1;
      }
   }

else
   {
*/

  loop2:
   if (bldb != ldbp->BLKNUM) status = cacheLDB(1,iochan,bldb,&ldbp);

   rval = total - tval;
   (void) MID_RDLDB(iochan,ldbp,ildb,1,ipntr,&rdummy,off,
                    &rval,extens);

   tval += rval;
   if (tval < total)
      {
      ipntr += rval;			/* update pointers  */
      bldb = extens[0];
      ildb = extens[1] - 1;
      off = 1;
      goto loop2;
      } 
/*
   } 
*/

*nullo = 0;
return 0;
}

/*

*/
 
int MID_RDSCRR(iochan,start_block,start_indx,first,total,rvals,nullo)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
read the contents of a descriptor and its extensions as
integer/real/character data
.ALGORITHM
The values of a descriptor are returned as integer/real/char. data.
No more than MAXVAL values will be returned, but ACTVAL will
be set to the actual no. of values associated with the
descriptor, starting from the position which is specified as   1. element
.RETURNS 
nothing
--------------------------------------------------*/

int   iochan		/* IN : channel of frame */;
int   start_block	/* IN : start bldb no. of descriptor */;
int   start_indx	/* IN : start index in that bldb */;
int   first		/* IN : position of 1. element to be accessed */;
int   total		/* IN : no. of values to return */;
float  *rvals		/* OUT: array to hold descriptor data */;
int   *nullo		/* IO : no. of null values in data */;
  
{
int   bldb, ildb, extens[2];
int   off, begin, end, tval, rval;
int   status, idummy;

float   *rpntr;

struct LDB_STRUCT  *ldbp;




/*  set up pointers:
                 begin, end   point to begin + end of descr. data
                 off          points to offset within descr. data  */
  
end = 0;
bldb = start_block;
ildb = start_indx;

status = cacheLDB(1,iochan,bldb,&ldbp);

 
/*  1. loop - look for start descriptor element  */
	
loop_1:
LDBinfo(iochan,ldbp,ildb,&rval,extens);
 
begin = end + 1;				/* keep start index */
end += rval;				/* update end */
	
if (first > end) 
   {
   bldb = extens[0];
   ildb = extens[1] - 1;		    /* indices are counted in FORTRAN */
   if (bldb != ldbp->BLKNUM) 
      status = cacheLDB(1,iochan,bldb,&ldbp);
   goto loop_1;
   }

 
/*  2. loop - fill data with descriptor data  */
	
tval = 0;
off = first - begin + 1;
rpntr = rvals;

/*
nulflag = *nullo;		/. save null flag, -1 means do not check...  ./
 
				   feature not implemented yet 
if (nulflag >= 0)
   {
   register int nr;
   register float *fpntr;

   while (tval < total)
      {
      if (bldb != ldbp->BLKNUM)
         status = cacheLDB(1,iochan,bldb,&ldbp);

      rval = total - tval;
      (void) MID_RDLDB(iochan,ldbp,ildb,2,&idummy,rpntr,
                       off,&rval,extens);

      fpntr = rpntr;
      for (nr=0; nr<rval; nr++)
         {
         if (*fpntr++ == NUL_RVAL) (*nullo) ++;
         }

      tval += rval;
      rpntr += rval;                       /. update pointers  ./
      bldb = extens[0];
      ildb = extens[1] - 1;
      off = 1;
      }
   }

else
   {
*/

  loop2:
   if (bldb != ldbp->BLKNUM) status = cacheLDB(1,iochan,bldb,&ldbp);

   rval = total - tval;
   (void) MID_RDLDB(iochan,ldbp,ildb,2,&idummy,rpntr,off,
                    &rval,extens);

   tval += rval;
   if (tval < total)
      {
      rpntr += rval;			/* update pointers  */
      bldb = extens[0];
      ildb = extens[1] - 1;
      off = 1;
      goto loop2;
      } 
/*
   } 
*/

*nullo = 0;
return 0;
}

/*

*/
 
int MID_WDSCRI(iochan,start_block,start_indx,ivals,conflg,first,nval)

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
Write a descriptor + its values as integer/real/character data
to the LDB.
.ALGORITHM
Descriptor data is written into atoms which are already created -
so no checks for overflow are necessary.
.RETURNS 
nothing
------------------------------------------------------------------*/

int   iochan		/* IN : channel no of frame */;
int   start_block	/* IN : start LDB no */;
int   start_indx	/* IN : starting index in bldb */;
int   *ivals		/* IN : integer descriptor data */;
int   conflg		/* IN : constant flag = 1/0 (Yes/No) */;
int   first		/* IN : pos. of 1st desc. value to be accessed \
				if 1st = -1, desc. values are appended \
                                to existing ones */;
int   nval		/* IN : no. of data values */;

{
int   *ipntr;
int   bldb, ildb, extens[2];
int   off, begin, end, tval, rval;
int   status;

char  cdummy[4];

float   rdummy;

struct LDB_STRUCT  *ldbp;




/*  get starting LDB  */
 
bldb = start_block;
ildb = start_indx;
end = 0;

status = cacheLDB(1,iochan,bldb,&ldbp);


/*  1. loop - look for start descriptor element  */
	
loop_1:
LDBinfo(iochan,ldbp,ildb,&rval,extens);
 
begin = end + 1;				/* keep start index */
end += rval;					/* update end */
	
if (first > end) 
   {
   bldb = extens[0];
   ildb = extens[1] - 1;		   /* indices are counted in FORTRAN */
   if (bldb != ldbp->BLKNUM) 
      status = cacheLDB(1,iochan,bldb,&ldbp);
   goto loop_1;
   }

 
/*  2. loop - fill descriptor data  */
	
tval = 0;
off = first - begin + 1;
ipntr = ivals;

loop2:
if (bldb != ldbp->BLKNUM) status = cacheLDB(1,iochan,bldb,&ldbp);

rval = nval - tval;
(void) MID_WRLDB(iochan,ldbp,ildb,1,ipntr,&rdummy,cdummy,
                 conflg,off,&rval,extens);
 
tval += rval;
if (tval < nval)
   {
   if (conflg == 0) ipntr += rval; 		/* update pointer */
   bldb = extens[0];
   ildb = extens[1] - 1;
   off = 1;
   goto loop2;
   } 

return 0;
}

/*

*/
 
int MID_WDSCRR(iochan,start_block,start_indx,rvals,conflg,first,nval)

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  Write a descriptor + its values as integer/real/character data
  to the LDB.
.ALGORITHM
  Descriptor data is written into atoms which are already created -
 so no checks for overflow are necessary.
.RETURNS 
nothing
--------------------------------------------------------------------------*/

int   iochan		/* IN : channel no of frame */;
int   start_block	/* IN : start LDB no */;
int   start_indx	/* IN : starting index in bldb */;
float  *rvals		/* IN : real descriptor data */;
int   conflg		/* IN : constant flag = 1/0 (Yes/No) */;
int   first		/* IN : pos. of 1st desc. value to be accessed \
				if 1st = -1, desc. values are appended \
                                to existing ones */;
int   nval		/* IN : no. of data values */;
 
{
int   bldb, ildb, extens[2];
int   off, begin, end, tval, rval;
int   status, idummy;

char  cdummy[4];

float  *rpntr;

struct LDB_STRUCT  *ldbp;




bldb = start_block;				/*  get starting LDB  */
ildb = start_indx;
end = 0;

status = cacheLDB(1,iochan,bldb,&ldbp);


/*  1. loop - look for start descriptor element  */
	
loop_1:
LDBinfo(iochan,ldbp,ildb,&rval,extens);
 
begin = end + 1;				/* keep start index */
end += rval;					/* update end */
	
if (first > end) 
   {
   bldb = extens[0];
   ildb = extens[1] - 1;		   /* indices are counted in FORTRAN */
   if (bldb != ldbp->BLKNUM) 
      status = cacheLDB(1,iochan,bldb,&ldbp);
   goto loop_1;
   }

 
/*  2. loop - fill descriptor data  */
	
tval = 0;
off = first - begin + 1;
rpntr = rvals;

loop2:
if (bldb != ldbp->BLKNUM) status = cacheLDB(1,iochan,bldb,&ldbp);

rval = nval - tval;
(void) MID_WRLDB(iochan,ldbp,ildb,2,&idummy,rpntr,cdummy,
                 conflg,off,&rval,extens);
 
tval += rval;
if (tval < nval)
   {
   if (conflg == 0) rpntr += rval;		/* update pointer */
   bldb = extens[0];
   ildb = extens[1] - 1;
   off = 1;
   goto loop2;
   } 

return 0;
}

/*

*/
 
int MID_WDSCRC(iochan,start_block,start_indx,cvals,conflg,first,nval)

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  Write a descriptor + its values as integer/real/character data
  to the LDB.
.ALGORITHM
  Descriptor data is written into atoms which are already created -
 so no checks for overflow are necessary.
.RETURNS 
nothing
-------------------------------------------------------------------*/

int   iochan		/* IN : channel no of frame */;
int   start_block	/* IN : start LDB no */;
int   start_indx	/* IN : starting index in bldb */;
char   *cvals		/* IN : character descriptor data */;
int   conflg		/* IN : constant flag = 1/0 (Yes/No) */;
int   first		/* IN : pos. of 1st desc. value to be accessed \
				if 1st = -1, desc. values are appended \
                                to existing ones */;
int   nval		/* IN : no. of data values */;
 
{
int   bldb, ildb, extens[2];
int   off, begin, end, tval, rval;
int   status, idummy;

char   *cpntra;

float   rdummy;

struct LDB_STRUCT  *ldbp;




/*  get starting LDB  */
 
bldb = start_block;
ildb = start_indx;
end = 0;

status = cacheLDB(1,iochan,bldb,&ldbp);


/*  1. loop - look for start descriptor element  */
	
loop_1:
LDBinfo(iochan,ldbp,ildb,&rval,extens);
 
begin = end + 1;				/* keep start index */
end += rval;					/* update end */
	
if (first > end) 
   {
   bldb = extens[0];
   ildb = extens[1] - 1;		   /* indices are counted in FORTRAN */
   if (bldb != ldbp->BLKNUM) 
      status = cacheLDB(1,iochan,bldb,&ldbp);
   goto loop_1;
   }

 
/*  2. loop - fill descriptor data  */
	
tval = 0;
off = first - begin + 1;
cpntra = cvals;

loop2:
if (bldb != ldbp->BLKNUM) status = cacheLDB(1,iochan,bldb,&ldbp);

rval = nval - tval;
(void) MID_WRLDB(iochan,ldbp,ildb,3,&idummy,&rdummy,cpntra,
                 conflg,off,&rval,extens);
 
tval += rval;
if (tval < nval)
   {
   if (conflg == 0) cpntra += rval;		/* update pointer */
   bldb = extens[0];
   ildb = extens[1] - 1;
   off = 1;
   goto loop2;
   } 

return 0;
}
