
/**********************************/
/* C API for xsm file support     */
/* author: A. Hebert (30/04/2002) */
/**********************************/

/*
   Copyright (C) 2002 Ecole Polytechnique de Montreal

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.
 */

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

#define iprim 3
#define iwrd 3
#define klong 5+iwrd+(3+iwrd)*iofmax
#if !defined(min)
#define min(A,B)  ((A) < (B) ? (A) : (B))
#endif
#define TRUE 1     /* valeur boolenne TRUE */
#define FALSE 0    /* valeur boolenne FALSE */

static char AbortString[80];

/* Table of constant values */

static int_32 c__0 = 0;
static int_32 c__1 = 1;
static int_32 c__2 = 2;
static int_32 c__3 = 3;
static char *bl12="                                  ";

void xsmkep(db1 *ipkeep, int_32 imode, xsm **iplist)
/*
 *-----------------------------------------------------------------------
 *
 * keep the addresses of the open active directories.
 *
 * input parameters:
 *  ipkeep : address of the database handle (always the same).
 *  imode  : =1: add to the database; =2: remove from the database.
 *  iplist : address of an active directory.
 *
 * output parameter:
 *  iplist : last active directory in the database. =0 if the
 *           database is empty.
 *
 * database handle structure:
 *  0 : number of addresses in the database.
 *  1 : maximum slots in the database.
 *  2 : address of the database.
 *
 *-----------------------------------------------------------------------
 */
{
   char *nomsub="xsmkep";
   int_32 n = ipkeep->nad;
   if (imode == 1) {
      int_32 i;
      xsm **my_parray;
      if ((*iplist)->header != 200) {
         sprintf(AbortString,"%s: WRONG HEADER(1).",nomsub);
         xabort_c(AbortString);
      } else if (ipkeep->nad + 1 > ipkeep->maxad) {
         ipkeep->maxad += maxit;
         my_parray = (xsm **) malloc((ipkeep->maxad)*sizeof(*my_parray));
         for (i = 0; i < n; ++i) my_parray[i]=ipkeep->idir[i];
         if (n > 0) free(ipkeep->idir);
         ipkeep->idir=my_parray;
      }
      ++ipkeep->nad;
      ipkeep->idir[n] = *iplist;
   } else if (imode == 2) {
      int_32 i, i0=0;
      for (i = n; i >= 1; --i) {
         if (ipkeep->idir[i-1] == *iplist) {
            i0 = i;
            goto L30;
         }
      }
      sprintf(AbortString,"%s: UNABLE TO FIND AN ADDRESS.",nomsub);
      xabort_c(AbortString);
L30:
      for (i = i0; i <= n-1; ++i)
         ipkeep->idir[i-1]=ipkeep->idir[i];
      --ipkeep->nad;
      if (ipkeep->nad == 0) {
         *iplist = NULL;
         free(ipkeep->idir);
         ipkeep->maxad=0;
         ipkeep->idir=NULL;
      } else {
         *iplist = ipkeep->idir[n-1];
         if ((*iplist)->header != 200) {
            sprintf(AbortString,"%s: WRONG HEADER(2).",nomsub);
            xabort_c(AbortString);
         }
      }
   } else {
      sprintf(AbortString,"%s: INVALID VALUE OF IMODE.",nomsub);
      xabort_c(AbortString);
   }
   return;
}

void xsmdir(int_32 *ind, block2 *my_block2)
/*
 *-----------------------------------------------------------------------
 *
 * import or export a directory using the kdi utility.
 *
 * input parameters:
 *  ind   : =1 for import ; =2 for export.
 *  my_block2 : address of memory-resident xsm structure (block 2).
 *
 *-----------------------------------------------------------------------
 */
{
   char *nomsub="xsmdir";
   int_32 i,j,irc,ibuf,ipos,iofma2,iname[3];
   char hbuf[5];
   ipos = my_block2->idir;
   if (*ind == 1) {
      irc = kdiget_c(my_block2->ifile, &ibuf, ipos, c__1);
      if (irc != 0) goto L40;
      strncpy(hbuf,(char*)&ibuf,4);
      hbuf[4]='\0';
      if (strcmp(hbuf,"$$$$") != 0) goto L30;
      ipos += 1;
      irc = kdiget_c(my_block2->ifile, &iofma2, ipos, c__1);
      ipos += 1;
      irc = kdiget_c(my_block2->ifile, &(my_block2->nmt), ipos, c__1);
      if (my_block2->nmt > iofmax) goto L30;
      ipos += 1;
      irc = kdiget_c(my_block2->ifile, &(my_block2->link), ipos, c__1);
      ipos += 1;
      irc = kdiget_c(my_block2->ifile, &(my_block2->iroot), ipos, c__1);
      ipos += 1;
      irc = kdiget_c(my_block2->ifile, iname, ipos, c__3);
      strncpy(my_block2->mynam,(char*)iname,sizeof(iname));
      my_block2->mynam[sizeof(iname)]='\0';
      for(i=sizeof(iname)-1; i>0; i--) {
         if(my_block2->mynam[i] != ' ') break;
         my_block2->mynam[i]='\0';
      }
      if (my_block2->nmt == 0) return;
      ipos += iwrd;
      irc = kdiget_c(my_block2->ifile, my_block2->iofs, ipos, my_block2->nmt);
      ipos += iofma2;
      irc = kdiget_c(my_block2->ifile, my_block2->jlon, ipos, my_block2->nmt);
      ipos += iofma2;
      irc = kdiget_c(my_block2->ifile, my_block2->jtyp, ipos, my_block2->nmt);
      ipos += iofma2;
      for(i=0; i<my_block2->nmt; i++) {
         irc = kdiget_c(my_block2->ifile, iname, ipos, c__3);
         strncpy(my_block2->cmt[i],(char*)iname,sizeof(iname));
         my_block2->cmt[i][sizeof(iname)]=' ';
         for(j=sizeof(iname); j>0; j--) {
            if(my_block2->cmt[i][j] != ' ') break;
            my_block2->cmt[i][j]='\0';
         }
         ipos += iwrd;
      }
      if (irc != 0) goto L40;
   } else if (*ind == 2) {
      my_block2->modif = 0;
      strncpy((char*)&ibuf,"$$$$",sizeof(ibuf));
      irc = kdiput_c(my_block2->ifile, &ibuf, ipos, c__1);
      if (irc != 0) goto L50;
      ipos += 1;
      i = iofmax;
      irc = kdiput_c(my_block2->ifile, &i, ipos, c__1);
      ipos += 1;
      irc = kdiput_c(my_block2->ifile, &(my_block2->nmt), ipos, c__1);
      if (my_block2->nmt > iofmax) goto L30;
      ipos += 1;
      irc = kdiput_c(my_block2->ifile, &(my_block2->link), ipos, c__1);
      ipos += 1;
      irc = kdiput_c(my_block2->ifile, &(my_block2->iroot), ipos, c__1);
      ipos += 1;
      strncpy((char*)iname,bl12,sizeof(iname));
      strncpy((char*)iname,my_block2->mynam,min(sizeof(iname),strlen(my_block2->mynam)));
      irc = kdiput_c(my_block2->ifile, iname, ipos, c__3);
      if (my_block2->nmt == 0) return;
      ipos += iwrd;
      irc = kdiput_c(my_block2->ifile, my_block2->iofs, ipos, my_block2->nmt);
      ipos += iofmax;
      irc = kdiput_c(my_block2->ifile, my_block2->jlon, ipos, my_block2->nmt);
      ipos += iofmax;
      irc = kdiput_c(my_block2->ifile, my_block2->jtyp, ipos, my_block2->nmt);
      ipos += iofmax;
      for(i=0; i<my_block2->nmt; i++) {
         strncpy((char*)iname,bl12,sizeof(iname));
         strncpy((char*)iname,my_block2->cmt[i],min(sizeof(iname),strlen(my_block2->cmt[i])));
         irc = kdiput_c(my_block2->ifile, iname, ipos, c__3);
         ipos += iwrd;
      }
      if (irc != 0) goto L50;
   }
   return;
/* ABORT ON FATAL ERRORS */
L30:
   sprintf(AbortString,"%s: UNABLE TO RECOVER DIRECTORY.",nomsub);
   xabort_c(AbortString);
L40:
   sprintf(AbortString,"%s: kdiget_c ERROR NB. %d.",nomsub,(int)irc);
   xabort_c(AbortString);
L50:
   sprintf(AbortString,"%s: kdiput_c ERROR NB. %d.",nomsub,(int)irc);
   xabort_c(AbortString);
}

void xsmop_c(xsm **iplist, char *namp, int_32 imp, int_32 impx)
/*
 *-----------------------------------------------------------------------
 *
 * open an existing or create a new xsm file.
 *
 * The xsm database results from the juxtaposition of a hierarchical
 * logical structure into a direct access file. The direct access file
 * is ANSI-C or Fortran-77 compatible and is managed by kdiget/put/cl.
 * xsmop/put/get/len/vec/nxt/cl entries provide a set of methods to
 * access a xsm file.
 *
 * The logical structure of a xsm file is made of a root directory fol-
 * lowed by variable-length blocks containing the useful information.
 * Each time a directory is full, an extent is automatically created at
 * the end of the file, so that the total number of blocks in a direc-
 * tory is only limited by the maximum size of the direct access file.
 * Any block can contain a sub-directory in order to create a hierar-
 * chical structure.
 *
 * input parameters:
 *    namp : character name (null terminated) of the xsm file.
 *     imp : type of access.  =0: new file mode;
 *                            =1: modification mode;
 *                            =2: read only mode.
 *    impx : if impx=0, we suppress printing on xsmop.
 *
 * output parameters:
 *  iplist : address of the handle to the xsm file.
 *    namp : character*12 name of the xsm file if imp=1 or imp=2.
 *
 * The active directory is made of two blocks linked together. A block 1
 * is allocated for each scalar directory or vector directory component.
 * Block 2 is unique for a given xsm file; every block 1 is pointing to
 * the same block 2.
 *
 *-----------------------------------------------------------------------
 */
{
   char *nomsub="xsmop_c";
   int_32 irc,ibuf;
   char hbuf[5];
   block2 *my_block2;
   db1 *my_db1;
   db2 *my_db2;
   kdi_file *my_file;
   if (imp < 0 || imp > 2) {
      sprintf(AbortString,"%s: INVALID ACTION ( %d ) ON XSM FILE '%s'.",nomsub,(int)imp,namp);
      xabort_c(AbortString);
   } else if (strlen(namp) > 72) {
      sprintf(AbortString,"%s: FINENAME '%s' EXCEEDING 72 CHARACTERS.",nomsub,namp);
      xabort_c(AbortString);
   }
   *iplist = (xsm *) malloc(sizeof(**iplist));
   my_block2 = (block2 *) malloc(sizeof(*my_block2));

   my_db1 = (db1 *) malloc(sizeof(*my_db1));
   my_db1->nad = 0;
   my_db1->maxad = 0;
   my_db1->idir = NULL;
   (*iplist)->icang = my_db1;

   my_db2 = (db2 *) malloc(sizeof(*my_db2));
   my_db2->nad = 0;
   my_db2->maxad = 0;
   my_db2->iref = NULL;
   my_db2->iofset = NULL;
   my_db2->lg = NULL;
   (*iplist)->icang2 = my_db2;

   (*iplist)->header = 200;
   (*iplist)->listlen = -1;
   (*iplist)->impf = imp;
   (*iplist)->ibloc = my_block2;
   (*iplist)->father = NULL;
   strcpy((*iplist)->hname,namp);
   my_file = (kdi_file *) kdiop_c(namp,imp);
   if (my_file == NULL) {
      sprintf(AbortString,"%s: UNABLE TO OPEN XSM FILE '%s'.",nomsub,namp);
      xabort_c(AbortString);
   }
   my_block2->ifile = my_file;
   if (impx > 1)
      printf("%s: KDI FILE OPEN = %ld NAME = '%s' ACTION = %d.\n",nomsub,(long)my_file->fd,namp,(int)imp);
   if (imp >= 1) {
/*    RECOVER THE ROOT DIRECTORY IF THE XSM FILE ALREADY EXISTS. */
      irc=kdiget_c(my_block2->ifile, &ibuf, c__0, c__1);
      if (irc != 0) goto L140;
      strncpy(hbuf,(char*)&ibuf,4);
      hbuf[4]='\0';
      if (strcmp(hbuf,"$XSM") != 0) {
         sprintf(AbortString,"%s: WRONG HEADER ON XSM FILE '%s'.",nomsub,namp);
         xabort_c(AbortString);
      }
      irc=kdiget_c(my_block2->ifile, &(my_block2->ioft), c__1, c__1);
      if (irc != 0) goto L140;
      irc=kdiget_c(my_block2->ifile, &(my_block2->idir), c__2, c__1);
      if (irc != 0) goto L140;
      (*iplist)->idir = my_block2->idir;
      xsmdir(&c__1,my_block2);
      my_block2->modif = 0;
      if (impx > 0) {
         printf("%s: XSM FILE RECOVERY. FILE = '%s'.\n",nomsub,namp);
         printf("%6s HIGHEST ATTAINABLE ADDRESS = %d\n"," ",(int)my_block2->ioft);
         printf("%6s ACTIVE DIRECTORY = %s\n"," ",my_block2->mynam);
      }
   } else {
/*    NEW-FILE MODE. */
      (*iplist)->impf = 1;
      (*iplist)->idir = iprim;
      my_block2->ioft = iprim+klong;
      my_block2->idir = iprim;
      my_block2->iroot = -1;
      my_block2->nmt = 0;
      my_block2->link = iprim;
      sprintf(my_block2->mynam,"/");
      strncpy((char*)&ibuf,"$XSM",sizeof(ibuf));
      irc=kdiput_c(my_block2->ifile, &ibuf, c__0, c__1);
      if (irc != 0) goto L150;
      irc=kdiput_c(my_block2->ifile, &(my_block2->ioft), c__1, c__1);
      if (irc != 0) goto L150;
      irc=kdiput_c(my_block2->ifile, &(my_block2->idir), c__2, c__1);
      if (irc != 0) goto L150;
      xsmdir(&c__2,my_block2);
      my_block2->modif = 1;
   }
   return;
L140:
   sprintf(AbortString,"%s: kdiget_c ERROR NB. %d ON XSM FILE '%s'.",nomsub,(int)irc,namp);
   xabort_c(AbortString);
L150:
   sprintf(AbortString,"%s: kdiput_c ERROR NB. %d ON XSM FILE '%s'.",nomsub,(int)irc,namp);
   xabort_c(AbortString);
}

void xsmrep(const char *namt, int_32 *ind, int_32 *idir, block2 *my_block2, int_32 *iii)
/*
 *-----------------------------------------------------------------------
 *
 * find a block (record or directory) position in the active directory
 * and related extents.
 *
 * input parameters:
 *  namt   : character*12 name of the required block.
 *  ind    : =1 search namt ; =2 search and positionning in an empty
 *           slot of the active directory if namt does not exists.
 *  idir   : offset of active directory on xsm file.
 *  my_block2 : address of memory-resident xsm structure (block 2).
 *
 * output parameter:
 *  iii    : return code. =0 if the block named namt does not exists;
 *           =position in the active directory extent if namt extsts.
 *           =0 or 1 if namt=' '.
 *
 *-----------------------------------------------------------------------
 */
{
   char *nomsub="xsmrep";
   int_32 i, ipos, ipos2, irc, irc2, istart;
   char namp[13],nomC[25];

   if (my_block2->idir != *idir) {
/*    SWITCH TO THE CORRECT ACTIVE DIRECTORY (BLOCK 2). */
      if (my_block2->modif == 1) xsmdir(&c__2, my_block2);
      my_block2->idir = *idir;
      xsmdir(&c__1, my_block2);
   }
   if (strcmp(namt,"***HANDLE***") == 0) {
      sprintf(AbortString,"%s: ***HANDLE*** IS A RESERVED KEYWORD.",nomsub);
      xabort_c(AbortString);
   }
   strcpy(namp,namt);
   if (strcmp(namp," ") == 0) strcpy(namp,"***HANDLE***");
   ipos = -1;
   if (my_block2->nmt < iofmax) ipos = my_block2->idir;
   if (my_block2->nmt == 0) goto L50;
   for (i = 1; i <= my_block2->nmt; ++i) {
      if (strcmp(namp,my_block2->cmt[i-1]) == 0) {
/*       THE BLOCK ALREADY EXISTS. */
         *iii = i;
         return;
      }
   }
/* THE BLOCK NAMP DOES NOT EXISTS IN THE ACTIVE DIRECTORY EXTENT. WE
   SEARCH IN OTHER EXTENTS THAT BELONG TO THE ACTIVE DIRECTORY. */
   if (my_block2->idir != my_block2->link) {
/*    RECOVER A NEW DIRECTORY EXTENT. */
      istart = my_block2->link;
      if (my_block2->modif == 1) xsmdir(&c__2, my_block2);
      my_block2->idir = istart;
L30:
      xsmdir(&c__1, my_block2);
      if (my_block2->nmt < iofmax) ipos = my_block2->idir;
      for (i = 1; i <= my_block2->nmt; ++i) {
         if (strcmp(namp,my_block2->cmt[i-1]) == 0) {
/*          THE BLOCK NAMP WAS FOUND IN THE ACTIVE DIRECTORY EXTENT. */
            *iii = i;
            return;
         }
      }
      if (my_block2->link == istart) goto L50;
      my_block2->idir = my_block2->link;
      goto L30;
   }
L50:
   *iii = 0;
   if (*ind == 1) return;
   if (ipos >= 0 && ipos != my_block2->idir) {
/*    AN EXTENT WITH AN EMPTY SLOT WAS FOUND. */
      if (my_block2->modif == 1) xsmdir(&c__2, my_block2);
      my_block2->idir = ipos;
      xsmdir(&c__1, my_block2);
   } else if (ipos == -1) {
/*    THE ACTIVE DIRECTORY IS FULL. CREATE AN EXTENT. */
      ipos = my_block2->link;
      my_block2->link = my_block2->ioft;
      if (my_block2->modif == 1) {
         xsmdir(&c__2, my_block2);
      } else {
         ipos2 = my_block2->idir + 3;
         irc=kdiput_c(my_block2->ifile, &(my_block2->link), ipos2, c__1);
         if (irc != 0) goto L150;
      }
      my_block2->idir = my_block2->link;
      my_block2->link = ipos;
      my_block2->ioft += klong;
      my_block2->nmt = 0;
   }
   ++my_block2->nmt;
   *iii = my_block2->nmt;
   my_block2->modif = 1;
   my_block2->jlon[*iii - 1] = 0;
   my_block2->jtyp[*iii - 1] = 99;
   strcpy(my_block2->cmt[*iii - 1],namp);
   return;

L150:
   irc2=kdicl_c(my_block2->ifile, c__1);
   strcpy(nomC,(my_block2->ifile)->nom);
   if (irc2 != 0) printf("%s: kdicl_c ERROR NB. %d ON XSM FILE '%s'.\n",nomsub,(int)irc2,nomC);
   sprintf(AbortString,"%s: kdiput_c ERROR NB. %d ON XSM FILE '%s'.",nomsub,(int)irc,nomC);
   xabort_c(AbortString);
}

void xsmput_c(xsm **iplist, const char *namp, int_32 ilong, int_32 itype, int_32 *data1)
/*
 *-----------------------------------------------------------------------
 *
 * copy a block from memory into the xsm file.
 *
 * input parameter:
 *  iplist : address of the handle to the xsm file.
 *    namp : character*12 name of the current block.
 *   ilong : number of information elements stored in the current block.
 *   itype : type of information elements stored in the current block.
 *           0: directory                1: integer
 *           2: single precision         3: character*4
 *           4: double precision         5: logical
 *           6: complex
 *   data1 : information elements. dimension data1(ilong)
 *
 *-----------------------------------------------------------------------
 */
{
   char *nomsub="xsmput_c";
   char nomC[13];
   block2 *my_block2;
   int_32 iii,irc;
   if ((*iplist)->impf == 2) {
      sprintf(AbortString,"%s: THE XSM FILE '%s' IS OPEN IN READ-ONLY MODE(1).",
              nomsub,(*iplist)->hname);
      xabort_c(AbortString);
   } else if (ilong <= 0) {
      sprintf(AbortString,"%s: INVALID LENGTH (%d) FOR NODE '%s' IN THE XSM FILE '%s'.",
              nomsub,(int)ilong,namp,(*iplist)->hname);
      xabort_c(AbortString);
   } else if (itype <= 0 || itype >= 8) {
      sprintf(AbortString,"%s: INVALID TYPE NUMBER (%d) FOR NODE '%s' IN THE XSM FILE '%s'.",
              nomsub,(int)itype,namp,(*iplist)->hname);
      xabort_c(AbortString);
   } else if ((*iplist)->header != 200) {
      sprintf(AbortString,"%s: THE XSM FILE '%s' HAVE THE WRONG HEADER.",
              nomsub,(*iplist)->hname);
      xabort_c(AbortString);
   }
   my_block2=(*iplist)->ibloc;
   xsmrep(namp, &c__2, &(*iplist)->idir, my_block2, &iii);
   my_block2->modif = 1;
   if (ilong > my_block2->jlon[iii-1]) {
      my_block2->iofs[iii-1] = my_block2->ioft;
      my_block2->ioft += ilong;
   }
   my_block2->jlon[iii-1] = ilong;
   my_block2->jtyp[iii-1] = itype;
   irc=kdiput_c(my_block2->ifile, data1, my_block2->iofs[iii-1], ilong);
   if (irc != 0) {
      strcpy(nomC,(my_block2->ifile)->nom);
      sprintf(AbortString,"%s: kdiput_c ERROR NB. %d ON XSM FILE '%s'.",nomsub,(int)irc,nomC);
      xabort_c(AbortString);
   }
   return;
}
void xsmget_c(xsm **iplist, const char *namp, int_32 *data2)
/*
 *-----------------------------------------------------------------------
 *
 * copy a block from the xsm file into memory.
 *
 * input parameters:
 *  iplist : address of the handle to the xsm file.
 *   namp  : character*12 name of the current block.
 *
 * output parameter:
 *   data2 : information elements. dimension data2(ilong)
 *
 *-----------------------------------------------------------------------
 */
{
   char *nomsub="xsmget_c";
   char nomC[13];
   block2 *my_block2;
   int_32 iii,irc;
   if ((*iplist)->header != 200) {
      sprintf(AbortString,"%s: THE XSM FILE '%s' HAVE THE WRONG HEADER.",
              nomsub,(*iplist)->hname);
      xabort_c(AbortString);
   }
   my_block2=(*iplist)->ibloc;
   xsmrep(namp, &c__1, &(*iplist)->idir, my_block2, &iii);
   if (iii > 0) {
      irc=kdiget_c(my_block2->ifile, data2, my_block2->iofs[iii-1], my_block2->jlon[iii-1]);
      if (irc != 0) {
         strcpy(nomC,(my_block2->ifile)->nom);
         sprintf(AbortString,"%s: kdiget_c ERROR NB. %d ON XSM FILE '%s'.",nomsub,(int)irc,nomC);
         xabort_c(AbortString);
      }
   } else {
      sprintf(AbortString,"%s: UNABLE TO FIND BLOCK '%s' INTO DIRECTORY '%s' IN THE XSM FILE '%s'.",
              nomsub,namp,my_block2->mynam,(*iplist)->hname);
      xabort_c(AbortString);
   }
   return;
}

void xsmcl_c(xsm **iplist, int_32 istatu)
/*
 *-----------------------------------------------------------------------
 *
 * close the xsm file.
 *
 * input parameters:
 *  iplist : address of the handle to the xsm file.
 *  istatu : =1 to keep the file at close ; =2 to destroy it.
 *
 *-----------------------------------------------------------------------
 */
{
   char *nomsub="xsmcl_c";
   block2 *my_block2;
   int_32 i, irc, iii;
   db1 *ipkeep;
   db2 *ipkep2;
   if ((*iplist)->impf == 2 && istatu == 2) {
      sprintf(AbortString,"%s: CANNOT ERASE THE XSM FILE '%s' OPEN IN READ-ONLY MODE.",
              nomsub,(*iplist)->hname);
      xabort_c(AbortString);
   } else if (istatu < 1 || istatu > 2) {
      sprintf(AbortString,"%s: INVALID ACTION ( %d ) ON XSM FILE '%s'.",
              nomsub,(int)istatu,(*iplist)->hname);
      xabort_c(AbortString);
   } else if ((*iplist)->header != 200) {
      sprintf(AbortString,"%s: THE XSM FILE '%s' HAVE THE WRONG HEADER.",
              nomsub,(*iplist)->hname);
      xabort_c(AbortString);
   }
   ipkeep = (*iplist)->icang;
   if (ipkeep->nad > 0) {
      for (i = 1; i <= ipkeep->nad; ++i) free(ipkeep->idir[i-1]);
      free(ipkeep->idir);
   }
   ipkep2 = (*iplist)->icang2;
   if (ipkep2->nad > 0) {
      for (i = 1; i <= ipkep2->nad; ++i) free(ipkep2->iofset[i-1]); /* rlsara_c() */
      free(ipkep2->iref);
      free(ipkep2->iofset);
      free(ipkep2->lg);
   }
   my_block2 = (*iplist)->ibloc;

   if (my_block2->modif == 1) {
      if ((*iplist)->impf == 2) {
         sprintf(AbortString,"%s: THE XSM FILE '%s' IS OPEN IN READ-ONLY MODE(2).",
                 nomsub,(*iplist)->hname);
         xabort_c(AbortString);
      }
      xsmdir(&c__2, my_block2);
   }

   if (my_block2->idir != (*iplist)->idir) {
/*    SWITCH TO THE CORRECT ACTIVE DIRECTORY (BLOCK 2). */
      my_block2->idir = (*iplist)->idir;
      xsmdir(&c__1, my_block2);
   }
   if (my_block2->iroot != -1) {
      sprintf(AbortString,"%s: THE XSM FILE '%s' IS NOT ON ROOT DIRECTORY.",
              nomsub,(*iplist)->hname);
      xabort_c(AbortString);
   }
   if (my_block2->idir != iprim) {
/*    SWITCH TO THE CORRECT ACTIVE DIRECTORY (BLOCK 2). */
      my_block2->idir = iprim;
      xsmdir(&c__1, my_block2);
   }

   irc = kdiget_c(my_block2->ifile, &iii, c__1, c__1);
   if (irc != 0) goto L140;
   if (my_block2->ioft > iii) {
      if ((*iplist)->impf == 2) {
         sprintf(AbortString,"%s: THE XSM FILE '%s' IS OPEN IN READ-ONLY MODE(3).",
                 nomsub,(*iplist)->hname);
         xabort_c(AbortString);
      }
      irc = kdiput_c(my_block2->ifile, &(my_block2->ioft), c__1, c__1);
      if (irc != 0) goto L150;
   }
   irc = kdicl_c(my_block2->ifile, istatu);
   if (irc != 0) goto L160;

/* RELEASE THE XSM FILE HANDLE. */
   free((*iplist)->icang);
   free((*iplist)->icang2);
   my_block2->ifile = NULL;
   free(my_block2);
   (*iplist)->header = 0;
   free(*iplist);
   *iplist = NULL;
   return;

L140:
   sprintf(AbortString,"%s: kdiget_c ERROR NB. %d ON XSM FILE '%s'.",nomsub,(int)irc,(*iplist)->hname);
   xabort_c(AbortString);
L150:
   sprintf(AbortString,"%s: kdiput_c ERROR NB. %d ON XSM FILE '%s'.",nomsub,(int)irc,(*iplist)->hname);
   xabort_c(AbortString);
L160:
   sprintf(AbortString,"%s: kdicl_cS ERROR NB. %d ON XSM FILE '%s'.",nomsub,(int)irc,(*iplist)->hname);
   xabort_c(AbortString);
}

void xsmnxt_c(xsm **iplist, char *namp)
/*
 *-----------------------------------------------------------------------
 *
 * find the name of the next block stored in the active directory.
 *
 * input parameters:
 *  iplist : address of the handle to the xsm file.
 *    namp : character*12 name of a block. if namp=' ' at input, find
 *           any name for any block stored in this directory.
 *
 * output parameters:
 *    namp : character*12 name of the next block. namp=' ' for an empty
 *           directory.
 *
 *-----------------------------------------------------------------------
 */
{
   char *nomsub="xsmnxt_c";
   block2 *my_block2;
   int_32 iii;

   if ((*iplist)->header != 200) {
      sprintf(AbortString,"%s: THE XSM FILE '%s' HAVE THE WRONG HEADER.",
              nomsub,(*iplist)->hname);
      xabort_c(AbortString);
   }
   my_block2 = (*iplist)->ibloc;
   if (strcmp(namp," ") == 0) {
      if (my_block2->idir != (*iplist)->idir) {
/*       SWITCH TO THE CORRECT ACTIVE DIRECTORY (BLOCK 2). */
         if (my_block2->modif == 1) xsmdir(&c__2, my_block2);
         my_block2->idir = (*iplist)->idir;
         xsmdir(&c__1, my_block2);
      }
      iii = min(my_block2->nmt,1);
   } else {
      xsmrep(namp, &c__1, &(*iplist)->idir, my_block2, &iii);
   }
   if (iii == 0 && strcmp(namp, " ") == 0) {
/*    EMPTY DIRECTORY */
      sprintf(AbortString,"%s: THE ACTIVE DIRECTORY '%s' OF THE XSM FILE '%s' IS EMPTY.",
              nomsub,my_block2->mynam,(*iplist)->hname);
      xabort_c(AbortString);
   } else if (iii == 0) {
      sprintf(AbortString,"%s: UNABLE TO FIND BLOCK '%s' INTO DIRECTORY '%s' IN THE XSM FILE '%s'.",
              nomsub,namp,my_block2->mynam,(*iplist)->hname);
      xabort_c(AbortString);
   } else if (iii + 1 <= my_block2->nmt) {
      strcpy(namp,my_block2->cmt[iii]);
      return;
   }
/* SWITCH TO THE NEXT DIRECTORY. */
   if (my_block2->idir != my_block2->link) {
      if (my_block2->modif == 1) xsmdir(&c__2, my_block2);
      my_block2->idir = my_block2->link;
/*    RECOVER THE NEXT DIRECTORY. */
      xsmdir(&c__1, my_block2);
   }
   strcpy(namp,my_block2->cmt[0]);
   if (strcmp(namp,"***HANDLE***") == 0) strcpy(namp," ");
   return;
}

void xsmlen_c(xsm **iplist, const char *namp, int_32 *ilong, int_32 *itype)
/*
 *-----------------------------------------------------------------------
 *
 * return the length and type of a block. Return 0 if the block does not
 * exists.
 *
 * input parameters:
 *  iplist : address of the handle to the xsm file.
 *   namp  : character*12 name of the current block.
 *   ilong : number of information elements stored in the current block.
 *           ilong=-1 is returned for a scalar directory.
 *           ilong=0 if the block does not exists.
 *   itype : type of information elements stored in the current block.
 *           0: directory                1: integer
 *           2: single precision         3: character*4
 *           4: double precision         5: logical
 *           6: complex                 99: undefined
 *
 *-----------------------------------------------------------------------
 */
{
   char *nomsub="xsmlen_c";
   block2 *my_block2;
   int_32 iii;
   if ((*iplist)->header != 200) {
      sprintf(AbortString,"%s: THE XSM FILE '%s' HAVE THE WRONG HEADER.",
              nomsub,(*iplist)->hname);
      xabort_c(AbortString);
   }
   my_block2=(*iplist)->ibloc;
   xsmrep(namp, &c__1, &(*iplist)->idir, my_block2, &iii);
   if (iii > 0) {
      *ilong = my_block2->jlon[iii-1];
      *itype = my_block2->jtyp[iii-1];
   } else {
      *ilong = 0;
      *itype = 99;
   }
   return;
}
void xsminf_c(xsm **iplist, char *namxsm, char *nammy, int_32 *empty, int_32 *ilong, int_32 *access)
/*
 *-----------------------------------------------------------------------
 *
 * recover global informations related to an xsm file.
 *
 * input parameters:
 *  iplist : address of the handle to the xsm file.
 *
 * output parameters:
 *  namxsm : character*12 name of the xsm file.
 *   nammy : charecter*12 name of the active directory.
 *   empty : =.true. if the active directory is empty.
 *   ilong : =-1: for a table; >0: number of list items.
 *  access : type of access. =1: object open for modification;
 *           =2: object in read-only mode.
 *
 *-----------------------------------------------------------------------
 */
{
   char *nomsub="xsminf_c";
   block2 *my_block2;
   if ((*iplist)->header != 200) {
      sprintf(AbortString,"%s: THE XSM FILE '%s' HAVE THE WRONG HEADER.",
              nomsub,(*iplist)->hname);
      xabort_c(AbortString);
   }
   my_block2=(*iplist)->ibloc;
   if (my_block2->idir != (*iplist)->idir) {
/*    SWITCH TO THE CORRECT ACTIVE DIRECTORY (BLOCK 2). */
      if (my_block2->modif == 1) xsmdir(&c__2, my_block2);
      my_block2->idir = (*iplist)->idir;
      xsmdir(&c__1, my_block2);
   }
   strcpy(namxsm,(*iplist)->hname);
   strcpy(nammy,my_block2->mynam);

   *empty = (my_block2->nmt == 0);
   *ilong = (*iplist)->listlen;
   *access = (*iplist)->impf;
   return;
}

void xsmsix_c(xsm **iplist, const char *namp, int_32 iact)
/*
 *-----------------------------------------------------------------------
 *
 * move in the scalar hierarchical structure of a xsm file.
 *
 * input parameters:
 *  iplist : address of the father/son table.
 *    namp : character*12 name of the son table if iact=1.
 *           not used if iact=0 or iact=2.
 *    iact : type of movement in the hierarchical structure.
 *           0: move back to the root directory;
 *           1: move to a son vectorial directory;
 *           2: move back to the parent directory.
 *
 *-----------------------------------------------------------------------
 */
{
   char *nomsub="xsmsix_c";
   block2 *my_block2;
   int_32 iii, lenold, idir=0, ityold;
   xsm *iofset, *iofpre;
   char nomC[13];

   if (iact < 0 || iact > 2) {
      sprintf(AbortString,"%s: INVALID ACTION (%d) ON THE XSM FILE '%s'.",
              nomsub,(int)iact,(*iplist)->hname);
      xabort_c(AbortString);
   } else if ((*iplist)->header != 200) {
      sprintf(AbortString,"%s: THE XSM FILE '%s' HAVE THE WRONG HEADER.",
              nomsub,(*iplist)->hname);
      xabort_c(AbortString);
   }
   if (iact == 1) {
/*    MOVE TO A SON DIRECTORY. */
      my_block2=(*iplist)->ibloc;
      xsmrep(namp, &c__2, &(*iplist)->idir, my_block2, &iii);
      lenold = my_block2->jlon[iii-1];
      if (lenold == -1) lenold = 1;
      ityold = my_block2->jtyp[iii-1];
      if (lenold == 0) {
/*       CREATE A NEW SCALAR DIRECTORY EXTENT ON THE XSM FILE. */
         if ((*iplist)->impf == 2) {
            printf("new directory name=%s\n",namp);
            sprintf(AbortString,"%s: THE XSM FILE '%s' IS OPEN IN READ-ONLY MODE(4).",
                    nomsub,(*iplist)->hname);
            xabort_c(AbortString);
         }
         my_block2->jlon[iii-1] = -1;
         my_block2->jtyp[iii-1] = 0;
         my_block2->iofs[iii-1] = my_block2->ioft;
         idir = my_block2->iofs[iii-1];
         my_block2->ioft += klong;
         xsmdir(&c__2, my_block2);
         my_block2->iroot = my_block2->idir;
         strcpy(my_block2->mynam,namp);
         my_block2->idir = my_block2->iofs[iii-1];
         my_block2->nmt = 0;
         my_block2->link = my_block2->idir;
         my_block2->modif = 1;
      } else if (lenold == 1 && ityold == 0) {
         idir = my_block2->iofs[iii-1];
      } else if (ityold != 0) {
         sprintf(AbortString,"%s:  BLOCK '%s' IS NOT A DIRECTORY OF THE XSM FILE '%s'.",
                 nomsub,namp,(*iplist)->hname);
         xabort_c(AbortString);
      }
      iofset = (xsm *) malloc(sizeof(*iofset));

/*    COPY BLOCK1 */
      iofset->header = (*iplist)->header;
      strcpy(iofset->hname,(*iplist)->hname);
      iofset->listlen = -1;
      iofset->impf = (*iplist)->impf;
      iofset->idir = (*iplist)->idir;
      iofset->ibloc = (*iplist)->ibloc;
      iofset->icang = (*iplist)->icang;
      iofset->icang2 = (*iplist)->icang2;
      iofset->father = (*iplist)->father;

      xsmkep(iofset->icang, c__1, &iofset);
      iofset->idir  = idir;
      iofset->father = *iplist;
      *iplist = iofset;
   } else if (iact == 0 || iact == 2) {
/*    MOVE BACK TO THE ROOT OR PARENT DIRECTORY. */
L50:
      my_block2 = (*iplist)->ibloc;
      if (my_block2->modif == 1) xsmdir(&c__2, my_block2);
      if (my_block2->idir != (*iplist)->idir) {
/*       SWITCH TO THE CORRECT ACTIVE DIRECTORY (BLOCK 2). */
         my_block2->idir = (*iplist)->idir;
         xsmdir(&c__1, my_block2);
      }
      if (my_block2->iroot == -1) {
         if (iact == 0) {
            if ((*iplist)->header != 200) {
               sprintf(AbortString,"%s: WRONG HEADER(1).",nomsub);
               xabort_c(AbortString);
            }
            return;
         }
         sprintf(AbortString,"%s: THE XSM FILE '%s' IS ALREADY ON ROOT DIRECTORY.",
                 nomsub,(*iplist)->hname);
         xabort_c(AbortString);
      }
      strcpy(nomC,my_block2->mynam);
      iofset = *iplist;
      *iplist = (*iplist)->father;
      xsmrep(nomC, &c__1, &(*iplist)->idir, my_block2, &iii);
      if (iii == 0) {
         sprintf(AbortString,"%s: UNABLE TO STEP DOWN ON FATHER RECORD '%s' FOR XSM FILE '%s'.",
                 nomsub,namp,(*iplist)->hname);
         xabort_c(AbortString);
      }
      iofpre = iofset;
      xsmkep((*iplist)->icang, c__2, &iofpre);
      free(iofset);
      if (iact == 0 && (*iplist)->idir != iprim) {
         goto L50;
      } else if ((*iplist)->header != 200) {
         sprintf(AbortString,"%s: WRONG HEADER(2).",nomsub);
         xabort_c(AbortString);
      }
   }
   return;
}

void xsmdid_c(xsm **iplist, const char *namp, xsm **jplist)
/*
 *-----------------------------------------------------------------------
 *
 * create/access a daughter associative table in a father table.
 *
 * input parameters:
 *  iplist : address of the father table.
 *    namp : character*12 name of the daughter associative table.
 *
 * output parameter:
 *  jplist : address of the daughter associative table.
 *
 *-----------------------------------------------------------------------
 */
{
   char *nomsub="xsmdid_c";
   block2 *my_block2;
   int_32 iii, lenold, idir=0, ityold;
   xsm *iofset;

   if ((*iplist)->header != 200) {
      sprintf(AbortString,"%s: THE XSM FILE '%s' HAVE THE WRONG HEADER.",
              nomsub,(*iplist)->hname);
      xabort_c(AbortString);
   }
   my_block2=(*iplist)->ibloc;
   xsmrep(namp, &c__2, &(*iplist)->idir, my_block2, &iii);
   lenold = my_block2->jlon[iii-1];
   ityold = my_block2->jtyp[iii-1];
   if (lenold == 0) {
/*    CREATE A NEW SCALAR DIRECTORY EXTENT ON THE XSM FILE. */
      if ((*iplist)->impf == 2) {
         sprintf(AbortString,"%s: THE XSM FILE '%s' IS OPEN IN READ-ONLY MODE(5).",
                 nomsub,(*iplist)->hname);
         xabort_c(AbortString);
      }
      my_block2->jlon[iii-1] = -1;
      my_block2->jtyp[iii-1] = 0;
      my_block2->iofs[iii-1] = my_block2->ioft;
      idir = my_block2->iofs[iii-1];
      my_block2->ioft += klong;
      xsmdir(&c__2, my_block2);
      my_block2->iroot = my_block2->idir;
      strcpy(my_block2->mynam,namp);
      my_block2->idir = my_block2->iofs[iii-1];
      my_block2->nmt = 0;
      my_block2->link = my_block2->idir;
      my_block2->modif = 1;
   } else if (lenold == -1 && ityold == 0) {
      idir = my_block2->iofs[iii-1];
   } else {
      sprintf(AbortString,"%s: BLOCK '%s' IS NOT AN ASSOCIATIVE TABLE OF THE XSM FILE '%s'.",
              nomsub,namp,(*iplist)->hname);
      xabort_c(AbortString);
   }
   iofset = (xsm *) malloc(sizeof(*iofset));
   *jplist = iofset;

/*  COPY BLOCK1 */
   (*jplist)->header = (*iplist)->header;
   strcpy((*jplist)->hname,(*iplist)->hname);
   (*jplist)->listlen = -1;
   (*jplist)->impf = (*iplist)->impf;
   (*jplist)->idir  = idir;
   (*jplist)->ibloc = (*iplist)->ibloc;
   (*jplist)->icang = (*iplist)->icang;
   (*jplist)->icang2 = (*iplist)->icang2;
   (*jplist)->father = *iplist;
   xsmkep((*iplist)->icang, c__1, &iofset);
   return;
}

void xsmlid_c(xsm **iplist, const char *namp, int_32 ilong, xsm **jplist)
/*
 *-----------------------------------------------------------------------
 *
 * create/access the hierarchical structure of a list in a xsm file.
 *
 * input parameters:
 *  iplist : address of the father table.
 *    namp : character*12 name of the daughter list.
 *   ilong : dimension of the daughter list.
 *
 * output parameter:
 *  jplist : address of the daughter list.
 *
 *-----------------------------------------------------------------------
 */
{
   char *nomsub="xsmlid_c";
   char nomC[13];
   block2 *my_block2;
   int_32 iii, irc, irc2, lenold, idir=0, i, idiold, ityold, iroold, *iivec;
   xsm *iofset;

   if ((*iplist)->header != 200) {
      sprintf(AbortString,"%s: THE XSM FILE '%s' HAVE THE WRONG HEADER.",
              nomsub,(*iplist)->hname);
      xabort_c(AbortString);
   } else if (ilong <= 0) {
      sprintf(AbortString,"%s: INVALID LENGTH (%d) FOR NODE '%s' IN THE XSM FILE '%s'.",
              nomsub,(int)ilong,namp,(*iplist)->hname);
      xabort_c(AbortString);
   }
   my_block2=(*iplist)->ibloc;
   xsmrep(namp, &c__2, &(*iplist)->idir, my_block2, &iii);
   lenold = my_block2->jlon[iii-1];
   ityold = my_block2->jtyp[iii-1];
   if ((ilong > lenold && ityold == 10) || lenold == 0) {
/*    CREATE ILONG-LENOLD NEW LIST EXTENTS ON THE XSM FILE. */
      if ((*iplist)->impf == 2) {
         sprintf(AbortString,"%s: THE XSM FILE '%s' IS OPEN IN READ-ONLY MODE(6).",
                 nomsub,(*iplist)->hname);
         xabort_c(AbortString);
      }
      my_block2->jlon[iii-1] = ilong;
      my_block2->jtyp[iii-1] = 10;
      idiold = my_block2->iofs[iii-1];
      my_block2->iofs[iii-1] = my_block2->ioft;
      idir = my_block2->iofs[iii-1];
      my_block2->ioft += ilong;
      iroold = my_block2->idir;
      xsmdir(&c__2, my_block2);
      iivec = (int_32 *) malloc(ilong * sizeof(*iivec));
      if (lenold > 0) {
         irc = kdiget_c(my_block2->ifile, iivec, idiold, lenold);
         if (irc != 0) goto L110;
      }
      for (i = abs(lenold) + 1; i <= ilong; ++i) {
         iivec[i-1] = my_block2->ioft;
         my_block2->iroot = iroold;
         strcpy(my_block2->mynam,namp);
         my_block2->nmt = 0;
         my_block2->idir = my_block2->ioft;
         my_block2->ioft += klong;
         my_block2->link = my_block2->idir;
         xsmdir(&c__2, my_block2);
      }
      irc = kdiput_c(my_block2->ifile, iivec, idir, ilong);
      if (irc != 0) goto L100;
      free(iivec);
   } else if (lenold == ilong && ityold == 10) {
      idir = my_block2->iofs[iii-1];
   } else if (ityold != 10) {
      sprintf(AbortString,"%s: BLOCK '%s' IS NOT A LIST OF THE XSM FILE '%s'.",
              nomsub,namp,(*iplist)->hname);
      xabort_c(AbortString);
   } else {
      sprintf(AbortString,"%s: THE LIST '%s' OF THE XSM FILE '%s' HAVE AN INVALID LENGTH (%d).",
              nomsub,namp,(*iplist)->hname,(int)ilong);
      xabort_c(AbortString);
   }
   iivec = (int_32 *) malloc(ilong * sizeof(*iivec));
   irc = kdiget_c(my_block2->ifile, iivec, idir, ilong);
   if (irc != 0) goto L110;
   *jplist = (xsm *) malloc(ilong * sizeof(**jplist));
   for (i = 0; i < ilong; ++i) {
      iofset = *jplist + i;

/*    COPY BLOCK1 */
      iofset->header = (*iplist)->header;
      strcpy(iofset->hname,(*iplist)->hname);
      iofset->listlen = 0;
      iofset->impf = (*iplist)->impf;
      iofset->idir = iivec[i];
      iofset->ibloc = (*iplist)->ibloc;
      iofset->icang = (*iplist)->icang;
      iofset->icang2 = (*iplist)->icang2;
      iofset->father = *iplist;
   }
   (*jplist)->listlen = ilong;
   xsmkep((*iplist)->icang, c__1, jplist);
   free(iivec);
   return;

L100:
   irc2=kdicl_c(my_block2->ifile, c__1);
   strcpy(nomC,(my_block2->ifile)->nom);
   if (irc2 != 0) printf("%s: kdicl_c ERROR NB. %d ON XSM FILE '%s'.\n",nomsub,(int)irc2,nomC);
   sprintf(AbortString,"%s: kdiput_c ERROR NB. %d ON XSM FILE '%s'.",nomsub,(int)irc,nomC);
   xabort_c(AbortString);
L110:
   irc2=kdicl_c(my_block2->ifile, c__1);
   if (irc2 != 0) printf("%s: kdicl_c ERROR NB. %d ON XSM FILE '%s'.\n",nomsub,(int)irc2,nomC);
   strcpy(nomC,(my_block2->ifile)->nom);
   sprintf(AbortString,"%s: kdiget_c ERROR NB. %d ON XSM FILE '%s'.",nomsub,(int)irc,nomC);
   xabort_c(AbortString);
}

void xsmgpd_c(xsm **iplist, const char *namp, int_32 **iofdum)
/*
 *-----------------------------------------------------------------------
 *
 * get a malloc pointer for an entry in the xsm file.
 *
 * input parameters:
 *  iplist : address of the handle to the xsm file.
 *    namp : character*12 name of the current block.
 *
 * output parameter:
 *  iofdum : malloc pointer to the xsm entry named namp.
 *
 *-----------------------------------------------------------------------
 */
{
   db2 *ipkep2;
   int_32 i, i0, ilong, itylcm, n;
   xsmlen_c(iplist,namp,&ilong,&itylcm);
   ipkep2 = (*iplist)->icang2;
   n = ipkep2->nad;
   for (i = n; i >= 1; --i) {
      if (ipkep2->iref[i-1] == iofdum) {
         i0 = i;
         goto L10;
      }
   }
   goto L20;
L10:
   if (ilong == ipkep2->lg[i0-1]) {
      *iofdum = ipkep2->iofset[i0-1];
      xsmget_c(iplist,namp,*iofdum);
      return;
   }
   free(ipkep2->iofset[i0-1]); /* rlsara_c() */
   for (i = i0; i <= n-1; ++i) {
      ipkep2->iref[i-1]=ipkep2->iref[i];
      ipkep2->iofset[i-1]=ipkep2->iofset[i];
      ipkep2->lg[i-1]=ipkep2->lg[i];
   }
   --ipkep2->nad;
   n = ipkep2->nad;
L20:
   *iofdum = (int_32 *)malloc(ilong*sizeof(int_32)); /* setara_c(ilong) */
   xsmget_c(iplist,namp,*iofdum);
   if (n + 1 > ipkep2->maxad) {
      int_32 ***my_iref, **my_iofset, *my_lg;
      ipkep2->maxad += maxit;
      my_iref = (int_32 ***) malloc((ipkep2->maxad)*sizeof(*my_iref));
      my_iofset = (int_32 **) malloc((ipkep2->maxad)*sizeof(*my_iofset));
      my_lg = (int_32 *) malloc((ipkep2->maxad)*sizeof(*my_lg));
      for (i = 0; i < n; ++i) {
         my_iref[i]=ipkep2->iref[i];
         my_iofset[i]=ipkep2->iofset[i];
         my_lg[i]=ipkep2->lg[i];
      }
      if (n > 0) {
         free(ipkep2->iref);
         free(ipkep2->iofset);
         free(ipkep2->lg);
      }
      ipkep2->iref=my_iref;
      ipkep2->iofset=my_iofset;
      ipkep2->lg=my_lg;
   }
   ipkep2->iref[n] = iofdum;
   ipkep2->iofset[n] = *iofdum;
   ipkep2->lg[n] = ilong;
   ++ipkep2->nad;
   return;
}

void xsmppd_c(xsm **iplist, const char *namp, int_32 ilong, int_32 itype, int_32 *iofdum)
/*
 *-----------------------------------------------------------------------
 *
 * add a new malloc pointer entry in the xsm file.
 *
 * input parameter:
 *  iplist : address of the handle to the xsm file.
 *    namp : character*12 name of the current block.
 *   ilong : number of information elements stored in the current block.
 *   itype : type of information elements stored in the current block.
 *           0: directory                1: integer
 *           2: single precision         3: character*4
 *           4: double precision         5: logical
 *           6: complex
 *  iofdum : malloc pointer of the first information element.
 *
 *-----------------------------------------------------------------------
 */
{
   db2 *ipkep2;
   int_32 i, i0, n;
   xsmput_c(iplist,namp,ilong,itype,iofdum);
   ipkep2 = (*iplist)->icang2;
   n = ipkep2->nad;
   for (i = n; i >= 1; --i) {
      if (ipkep2->iofset[i-1] == iofdum) {
         i0 = i;
         goto L10;
      }
   }
   goto L20;
L10:
   for (i = i0; i <= n-1; ++i) {
      ipkep2->iref[i-1]=ipkep2->iref[i];
      ipkep2->iofset[i-1]=ipkep2->iofset[i];
      ipkep2->lg[i-1]=ipkep2->lg[i];
   }
   --ipkep2->nad;
   if (ipkep2->nad == 0) {
      free(ipkep2->iref);
      free(ipkep2->iofset);
      free(ipkep2->lg);
      ipkep2->maxad = 0;
      ipkep2->iref = NULL;
      ipkep2->iofset = NULL;
      ipkep2->lg = NULL;
   }
L20:
   free(iofdum); /* rlsara_c(iofdum) */
   iofdum = NULL;
   return;
}
