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

   FILE:  MC1.C

      Higher-level machine format conversion routines for converting a
      CODAS block file.  These are called from the main program MKBLKDIR.C,
      and in turn call the low-level routines in MC0.C.

      Modified 6/25/90 (JR):
      convert_profiles()--deleted initial write of data directory as
                          unnecessary and troublesome when writing
                          over the network (running on one machine
                          that writes to another hard disk):
                          the write and rewrite to the same buffer
                          can lose data

      Modified 8/1/90 (JR):
      convert_profiles()--added recalculation of profile offsets in
                          profile directory and rewrite of profile
                          directory since the profile offsets may
                          also change if profiles have been deleted
                          or through DBPUT with smaller n, ...
      convert_block_file()--added reset of db->struct_def to NULL if
                          same as db->block_strdef when freeing
                          db->block_strdef after each block file has
                          been processed

      Modified 10/11/93 (JR):
           convert_*()--modified to allow conversion to 3rd machine,
           instead of the host, as specified in the mkblkdir.cnt file
		   option DESTINATION.  Programming strategy is to convert
		   the data to destination machine format first then write them
		   out to disk.  For the case of internal db structures that
		   stay in memory, the data are then converted to HOST_ENVIRONMENT
		   format (if necessary) and are assumed to stay that way.
		   For the profile_dir and data_dir that get rewritten afterward,
		   a conversion from HOST_ENVIRONMENT copy in memory to the
           DESTINATION machine is again made before writing to disk.

     95/08 (JR): moved dbint_sd[] and identify_ms_code to include/dbglo.h
           and dbsource/dbcommon.c so db routines can read foreign format
           databases;
           added convert_block_ftr()

 ******************************************************************************/
#include "dbinc.h"
#include "mc0.h"  /* convert_*() */
#include "mc.h"

int from, to;
FILE *fpin;
long file_nbytes;

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

    FUNCTION: convert_block_dir

    This converts the newly created block directory file from the
    HOST_ENVIRONMENT format to the destination machine format.

*/
#if PROTOTYPE_ALLOWED
int convert_block_dir(char *db_name, int destmach)
#else
int convert_block_dir(db_name, destmach)
char *db_name;
int destmach;
#endif
{
   char *bde;
   BLOCK_DIR_HDR_TYPE bdh;
   FILE *fpdir;
   FILE_NAME_TYPE dir_name;
   int nbytes, dir_nentries;

   strcpy(dir_name, db_name);
   strcat(dir_name, "dir.blk");
   if ( (fpdir = open_binary_file(dir_name, READ_WRITE)) == NULL )
   {
      printf("\n CODAS ERROR:   UNABLE_TO_OPEN\t  ACCESSING:   BLOCK_DIR_FILE");
      printf("\n FROM FUNCTION: convert_block_dir\n");
      return(-1);
   }
   if ( read_data(fpdir, (char *) &bdh, 0L, BLOCK_DIR_HDR_SIZE) )
   {
      printf("\n CODAS ERROR:   READ_ERROR\t  ACCESSING:   BLOCK_DIR_HDR");
      printf("\n FROM FUNCTION: convert_block_dir\n");
      return(-1);
   }
   dir_nentries = bdh.dir_nentries;
   nbytes = bdh.dir_nentries * bdh.dir_entry_nbytes;
   if (convert_struct((char *) &bdh, (char *) &bdh,  HOST_ENVIRONMENT, destmach,
      "block_dir_hdr", &(dbint_sd[0].block_dir_hdr)) == BADUINT)
   {
      printf("\n CODAS ERROR:   CONVERT_ERROR\t  ACCESSING:   BLOCK_DIR_HDR");
      printf("\n FROM FUNCTION: convert_block_dir\n");
      return(-1);
   }
   strncpy(bdh.ms_code, MS_TABLE[destmach].ms_code, 4);
   if ( write_data(fpdir, (char *) &bdh, 0L, BLOCK_DIR_HDR_SIZE) )
   {
      printf("\n CODAS ERROR:   WRITE_ERROR\t  ACCESSING:   BLOCK_DIR_HDR");
      printf("\n FROM FUNCTION: convert_block_dir\n");
      return(-1);
   }
   if (nbytes > 0)
   {
      if ( (bde = malloc(nbytes)) == NULL )
      {
         printf("\n CODAS ERROR:   INSUFFICIENT_MEMORY\t  ACCESSING:   BLOCK_DIR");
         printf("\n FROM FUNCTION: convert_block_dir\n");
         return(-1);
      }
      if (read_data(fpdir, bde, BLOCK_DIR_HDR_SIZE, nbytes))
      {
         printf("\n CODAS ERROR:   READ_ERROR\t  ACCESSING:   BLOCK_DIR");
         printf("\n FROM FUNCTION: convert_block_dir\n");
         return(-1);
      }
      if (convert_array_struct(bde, bde, HOST_ENVIRONMENT, destmach, dir_nentries,
         "block_dir_entry", &(dbint_sd[0].block_dir_entry)) == BADUINT)
      {
         printf("\n CODAS ERROR:   CONVERT_ERROR\t  ACCESSING:   BLOCK_DIR");
         printf("\n FROM FUNCTION: convert_block_dir\n");
         return(-1);
      }
      if (write_data(fpdir, bde, BLOCK_DIR_HDR_SIZE, nbytes))
      {
         printf("\n CODAS ERROR:   WRITE_ERROR\t  ACCESSING:   BLOCK_DIR");
         printf("\n FROM FUNCTION: convert_block_dir\n");
         return(-1);
      }
      free(bde);
   }
   fclose(fpdir);
   return(0);
}

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

    FUNCTION: convert_block_file

       Copies a CODAS block file named <infile> to a file named <outfile>,
       performing machine conversion if needed.

    RETURNS:

       0 if okay
       CODAS error code otherwise

*/
#if PROTOTYPE_ALLOWED
int convert_block_file(char *infile, char *outfile, int destmach)
#else
int convert_block_file(infile, outfile, destmach)
char *infile, *outfile;
int destmach;
#endif
{
   int host;
   STRUCT_DEF_HDR_TYPE **link_address;
   BLOCK_HDR_TYPE bh;

#if (COMPILER == VAX_VMS_C)
   char tempfile[L_tmpnam];

   tmpname(tempfile);
   if (copy_file(infile, tempfile)) != 0)
   {
      db->error_code = UNABLE_TO_OPEN;
      db->error_data = BLOCK_FILE;
      goto error_found;
   }
   if ((fpin = open_binary_file(tempfile, READ_ONLY)) == NULL)
   {
      unlink(tempfile);
#else
   if ((fpin = open_binary_file(infile, READ_ONLY)) == NULL)
   {
#endif
      db->error_code = UNABLE_TO_OPEN;
      db->error_data = BLOCK_FILE;
      goto error_found;
   }

   if ( (db->fpblkdata = fopen(outfile, "wb+")) == NULL )
   {
      db->error_code = FILE_PROTECTION_ERROR;
      db->error_data = BLOCK_FILE;
      goto error_found;
   }

   file_nbytes = 0L;

   if ((db->error_code = read_data(fpin, (char *) &bh, 0L, BLOCK_HDR_SIZE)) != 0)
   {
      db->error_data = BLOCK_HDR;
      goto error_found;
   }
   /* from and to are global values used by the other convert_* routines
      below; they are initialized as follows: */
   if ((from = identify_ms_code(bh.ms_code)) == UNKNOWN_HOST)
   {
      db->error_code = UNKNOWN_HOST_ERROR;
      db->error_data = BLOCK_HDR;
      goto error_found;
   }
   to = destmach;
   if (convert_struct((char *) &(db->block_hdr), (char *) &bh, 
      from, HOST_ENVIRONMENT, "block_hdr", &(dbint_sd[0].block_hdr)) == BADUINT)
   {
      db->error_code = CONVERT_ERROR;
      db->error_data = BLOCK_HDR;
      goto error_found;
   }
   if ((host = identify_ms((char *) MACHINE_SIGNATURE)) == UNKNOWN_HOST)
   {
      db->error_code = UNKNOWN_HOST_ERROR;
      db->error_data = BLOCK_HDR;
      goto error_found;
   }
   strncpy(db->block_hdr.producer_host, MS_TABLE[host].ms_name, 4);
   strncpy(db->block_hdr.ms_code, MS_TABLE[host].ms_code, 4);
   if (from == to)
   {
      if (copy_file(infile, outfile) != 0)
      {
         db->error_code = UNABLE_TO_OPEN;
         db->error_data = BLOCK_FILE;
         goto error_found;
      }
   }
   else
   {
      /* 95/09 JR:  we're going to have to rewrite the block header again
         later, so let's just write an unconverted version to file for now
         to reserve space for the block header, and then rewrite
         the converted version later, when we have recalculated the
         no. of bytes in the block file: */
      if ( (db->error_code = write_data(db->fpblkdata, (char *) &db->block_hdr, 0L, BLOCK_HDR_SIZE)) != 0 )
      {
         db->error_data = BLOCK_HDR;
         goto error_found;
      }
      file_nbytes += BLOCK_HDR_SIZE;
      if (convert_data_list()) goto error_found;
      if (convert_block_strdef()) goto error_found;
      if (db->block_hdr.struct_def_nentries > 0)
         concat_strdef(&db->struct_def, db->block_strdef);
      if (convert_profile_dir()) goto error_found;
      if (convert_block_var_data()) goto error_found;
      if (convert_profiles()) goto error_found;
      if (convert_block_ftr()) goto error_found;
      db->block_hdr.block_nbytes = file_nbytes;
      if (convert_block_hdr()) goto error_found;
      if (db->struct_def == db->block_strdef) db->struct_def = NULL;
   }
/*   free_data: */
      free(db->block_strdef);
      free(db->profile_dir);
      if (db->prev_strdef)
      {
         link_address = (STRUCT_DEF_HDR_TYPE **) &(db->prev_strdef->LINK_PTR);
         *link_address = NULL;
      }
/*   close_files: */
      fclose(db->fpblkdata);
      fclose(fpin);
#if (COMPILER == VAX_VMS_C)
      unlink(tempfile);
#endif
      return(0);
   error_found:
      report_db_error("convert_block_file");
      return(-1);
}

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

    FUNCTION:  convert_block_hdr

       Converts a CODAS block file header pointed to by the db structure
       from the HOST_ENVIRONMENT machine format to the target machine
       format, and writes it to the output file.

    RETURNS:

       0 if okay
       CONVERT_ERROR, UNKNOWN_HOST_ERROR, SEEK_ERROR or WRITE_ERROR otherwise

*/
#if PROTOTYPE_ALLOWED
int convert_block_hdr(void)
#else
int convert_block_hdr()
#endif
{
   BLOCK_HDR_TYPE bh;

   if (convert_struct((char *) &bh, (char *) &(db->block_hdr), 
      HOST_ENVIRONMENT, to, "block_hdr", &(dbint_sd[0].block_hdr)) == BADUINT) 
   {
      db->error_code = CONVERT_ERROR;
      db->error_data = BLOCK_HDR;
      goto error_found;
   }
   strncpy(bh.producer_host, MS_TABLE[to].ms_name, 4);
   strncpy(bh.ms_code, MS_TABLE[to].ms_code, 4);
   if ( (db->error_code = write_data(db->fpblkdata, (char *) &bh, 0L, BLOCK_HDR_SIZE)) != 0 ) 
   {
      db->error_data = BLOCK_HDR;
      goto error_found;
   }
   return(0);

   error_found:
      report_db_error("convert_block_hdr");
      return(-1);
}

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

    FUNCTION:  convert_data_list

       Converts the data list structure in a CODAS block file to the
       HOST_ENVIRONMENT machine format and writes it to the output file.

    RETURNS:

       0 if okay
       INSUFFICIENT_MEMORY, SEEK_ERROR, READ_ERROR, WRITE_ERROR,
       or CONVERT_ERROR otherwise

*/
#if PROTOTYPE_ALLOWED
int convert_data_list(void)
#else
int convert_data_list()
#endif
{
   unsigned int nbytes;
   char *buf;

   if (db->block_hdr.data_list_nentries > 0)
   {
      nbytes = db->block_hdr.data_list_nentries * DATA_LIST_ENTRY_SIZE;
      if (nbytes == 0)
      {
         db->error_code = DATA_LIST_IS_EMPTY;
         db->error_data = DATA_LIST;
         goto error_found;
      }
      if ((buf = malloc(nbytes)) == NULL)
      {
         db->error_code = INSUFFICIENT_MEMORY;
         db->error_data = DATA_LIST;
         goto error_found;
      }
      if ((db->error_code = read_data(fpin, buf, BLOCK_HDR_SIZE, nbytes)) != 0)
      {
         db->error_data = DATA_LIST;
         goto error_found;
      }
      if (convert_array_struct((char *) db->data_list, buf, from, HOST_ENVIRONMENT,
         db->block_hdr.data_list_nentries, "data_list_entry",
         &(dbint_sd[0].data_list_entry)) == BADUINT)
      {
         db->error_code = CONVERT_ERROR;
         db->error_data = DATA_LIST;
         goto error_found;
      }
      free(buf);
      /* Commented out as unnecessary & potentially troublesome--will
         be written out after the block variable data have been processed
      if ((ierr = write_data_list()) != 0)
         return(ierr);
      */
      file_nbytes += nbytes;
   }
   return(0);

   error_found:
      report_db_error("convert_data_list");
      return(-1);
}

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

    FUNCTION:  convert_block_strdef

       Converts the structure definitions in a CODAS block file to the
       HOST_ENVIRONMENT machine format and write them to the output file.

    RETURNS:

       0 if okay
       INSUFFICIENT_MEMORY, SEEK_ERROR, READ_ERROR, WRITE_ERROR,
       or CONVERT_ERROR otherwise

*/
#if PROTOTYPE_ALLOWED
int convert_block_strdef(void)
#else
int convert_block_strdef()
#endif
{
   STRUCT_DEF_HDR_TYPE *dest_ptr, *src_ptr;
   unsigned int nbytes, nelem, ofs = 0, i, converted_nb;
   char *buf;

   if (db->block_hdr.struct_def_nentries > 0)
   {
      nbytes = db->block_hdr.struct_def_nentries * STRUCT_DEF_ENTRY_SIZE;
      if ( (buf = malloc(nbytes)) == NULL
         || (db->block_strdef = (STRUCT_DEF_HDR_TYPE *) malloc(nbytes)) == NULL)
      {
         db->error_code = INSUFFICIENT_MEMORY;
         db->error_data = STRUCTURE_DEF;
         goto error_found;
      }
      if ((db->error_code = read_data(fpin, buf, BLOCK_HDR_SIZE +
         db->block_hdr.data_list_nentries * DATA_LIST_ENTRY_SIZE, nbytes)) != 0)
      {
         db->error_data = STRUCTURE_DEF;
         goto error_found;
      }
      do
      {
         dest_ptr = (STRUCT_DEF_HDR_TYPE *) (((char *) db->block_strdef) + ofs);
         src_ptr = (STRUCT_DEF_HDR_TYPE *) ((char *) buf + ofs);
         if ( (converted_nb = convert_struct((char *) dest_ptr, (char *) src_ptr,
            from, HOST_ENVIRONMENT, "struct_def_hdr", &(dbint_sd[0].struct_def_hdr))) == BADUINT) 
         {
            db->error_code = CONVERT_ERROR;
            db->error_data = STRUCTURE_DEF;
            goto error_found;
         }
         if (convert_struct((char *) src_ptr, (char *) dest_ptr, HOST_ENVIRONMENT, to,
            "struct_def_hdr",  &(dbint_sd[0].struct_def_hdr)) == BADUINT)
         {
            db->error_code = CONVERT_ERROR;
            db->error_data = STRUCTURE_DEF;
            goto error_found;
         }
         ofs += converted_nb;
         nelem = dest_ptr->nelem;
         for (i = 0; i < nelem; i++)
         {
            dest_ptr = (STRUCT_DEF_HDR_TYPE *) (((char *) db->block_strdef) + ofs);
            src_ptr = (STRUCT_DEF_HDR_TYPE *) ((char *) buf + ofs);
            if ((converted_nb = convert_struct((char *) dest_ptr, (char *) src_ptr, from,
               HOST_ENVIRONMENT, "struct_def_elem", &(dbint_sd[0].struct_def_elem))) == BADUINT)
            {
               db->error_code = CONVERT_ERROR;
               db->error_data = STRUCTURE_DEF;
               goto error_found;
            }
            if (convert_struct((char *) src_ptr, (char *) dest_ptr, HOST_ENVIRONMENT, to,
               "struct_def_elem", &(dbint_sd[0].struct_def_elem)) == BADUINT)
            {
               db->error_code = CONVERT_ERROR;
               db->error_data = STRUCTURE_DEF;
               goto error_found;
            }
            ofs += converted_nb;
         }
      } while (ofs < nbytes);
      if ((db->error_code = write_data(db->fpblkdata, buf, 
         db->block_hdr.data_list_ofs + db->block_hdr.data_list_nentries * DATA_LIST_ENTRY_SIZE,
         db->block_hdr.struct_def_nentries * STRUCT_DEF_ENTRY_SIZE)) != 0)
      {
         db->error_data = STRUCTURE_DEF;
         goto error_found;
      }
      free(buf);
      file_nbytes += nbytes;
   }
   return(0);

   error_found:
      report_db_error("convert_block_strdef");
      return(-1);
}

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

    FUNCTION:  convert_profile_dir

       Converts the profile directory in a CODAS block file to the
       HOST_ENVIRONMENT machine format and writes it to the output file.

    RETURNS:

       0 if okay
       INSUFFICIENT_MEMORY, SEEK_ERROR, READ_ERROR, WRITE_ERROR,
       CONVERT_ERROR, or INVALID_DIRECTORY_TYPE otherwise

*/
#if PROTOTYPE_ALLOWED
int convert_profile_dir(void)
#else
int convert_profile_dir()
#endif
{
   unsigned int nbytes;
   char struct_def_name[20];
   char *buf;

   if (db->block_hdr.dir_nentries > 0)
   {
      sprintf(struct_def_name, "profile_dir_%1ld_entry", db->block_hdr.dir_type);
      nbytes = db->block_hdr.dir_nentries * db->block_hdr.dir_entry_nbytes;
      if (nbytes == 0)
      {
         db->error_code = PROFILE_DIR_IS_EMPTY;
         goto error_found;
      }
      if ((buf = malloc(nbytes)) == NULL || (db->profile_dir = malloc(nbytes)) == NULL)
      {
         db->error_code = INSUFFICIENT_MEMORY;
         goto error_found;
      }
      if ((db->error_code = read_data(fpin, buf, db->block_hdr.dir_ofs, nbytes)) != 0)
         goto error_found;
      if (convert_array_struct(db->profile_dir, buf, from, to,
         db->block_hdr.dir_nentries, struct_def_name,
         &(dbint_sd[0].profile_dir_0_entry)) == BADUINT)
      {
         db->error_code = CONVERT_ERROR;
         goto error_found;
      }
      if ((db->error_code = write_profile_dir()) != 0)
         goto error_found;
      if (to != HOST_ENVIRONMENT)
         if (convert_array_struct(db->profile_dir, buf, from, HOST_ENVIRONMENT,
            db->block_hdr.dir_nentries, struct_def_name,
            &(dbint_sd[0].profile_dir_0_entry)) == BADUINT)
         {
            db->error_code = CONVERT_ERROR;
            goto error_found;
         }
      free(buf);
      file_nbytes += nbytes;
   }
   return(0);

   error_found:
      db->error_data = PROFILE_DIR;
      report_db_error("convert_profile_dir");
      return(-1);
}

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

    FUNCTION:  convert_block_var_data

       Converts all the block-variable data in a CODAS block file to the
       HOST_ENVIRONMENT machine format and writes them to the output file.
       Note that some rearrangement among the block variables may occur in
       case the block variables were not originally loaded in the order of
       the data list ID numbers.  The data list is rewritten to update the
       offsets in case this occurs.

    RETURNS:

       0 if okay
       INSUFFICIENT_MEMORY, SEEK_ERROR, READ_ERROR, WRITE_ERROR,
       or CONVERT_ERROR otherwise

*/
#if PROTOTYPE_ALLOWED
int convert_block_var_data(void)
#else
int convert_block_var_data()
#endif
{
   unsigned int i, nbytes, nv;
   char *buf, *vdat;

   for (i = 0; i < db->block_hdr.data_list_nentries; i++)
      if (db->data_list[i].access_type == BLOCK_VAR_ACCESS_CODE)
      {
         nbytes = db->data_list[i].access_1;
         if (nbytes == 0)
            continue;
         if ((buf = malloc(nbytes)) == NULL || (vdat = malloc(nbytes)) == NULL)
         {
            db->error_code = INSUFFICIENT_MEMORY;
            db->error_data = i;
            goto error_found;
         }
         if ((db->error_code = read_data(fpin, buf, db->data_list[i].access_0, nbytes)) != 0)
         {
            db->error_data = i;
            goto error_found;
         }
         if (db->data_list[i].value_type == STRUCT_VALUE_CODE)
            nv = -nbytes;
         else
            nv = nbytes / VALUE_SIZE[db->data_list[i].value_type];
         if (convert_select(vdat, buf, from, to, nv, db->data_list[i].value_type,
            db->data_list[i].name, db->struct_def) == BADUINT)
         {
            db->error_code = CONVERT_ERROR;
            db->error_data = i;
            goto error_found;
         }
         free(buf);
         db->data_list[i].access_0 = file_nbytes; /* append */
         if ((db->error_code = write_data(db->fpblkdata, vdat, db->data_list[i].access_0,
            nbytes)) != 0)
         {
            db->error_data = i;
            goto error_found;
         }
         file_nbytes += nbytes;
         free(vdat);
      }
   /* rewrite data list in case block var data offsets have been interchanged */
   if (to == HOST_ENVIRONMENT)
   {
      if ((db->error_code = write_data_list()) != 0)
      {
         db->error_data = DATA_LIST;
         goto error_found;
      }
   }
   else
   {
      nbytes = db->block_hdr.data_list_nentries * DATA_LIST_ENTRY_SIZE;
      if ((buf = malloc(nbytes)) == NULL)
      {
         db->error_code = INSUFFICIENT_MEMORY;
         db->error_data = DATA_LIST;
         goto error_found;
      }
      if (convert_array_struct(buf, (char *) db->data_list, HOST_ENVIRONMENT, to,
         db->block_hdr.data_list_nentries, "data_list_entry",
         &(dbint_sd[0].data_list_entry)) == BADUINT)
      {
         db->error_code = CONVERT_ERROR;
         db->error_data = DATA_LIST;
         goto error_found;
      }
      if ((db->error_code = write_data(db->fpblkdata, buf, 
         db->block_hdr.data_list_ofs, nbytes)) != 0)
      {
         db->error_data = DATA_LIST;
         goto error_found;
      }
      free(buf);
   }
   return(0);

   error_found:
      report_db_error("convert_block_var_data");
      return(-1);
}

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

    FUNCTION:  convert_profiles

       Converts the data directories and profile-variable data in a CODAS
       block file to the HOST_ENVIRONMENT machine format and writes them
       to the output file.  Note that some rearrangement among the profile
       variables may occur if the profile variables were not originally
       loaded in the order of their data list ID numbers.  The data
       directories are rewritten to update the offsets in case this occurs.

    RETURNS:

       0 if okay
       INSUFFICIENT_MEMORY, SEEK_ERROR, READ_ERROR, WRITE_ERROR,
       INVALID_TYPE_REQUEST, or CONVERT_ERROR otherwise

*/
#if PROTOTYPE_ALLOWED
int convert_profiles(void)
#else
int convert_profiles()
#endif
{
   unsigned int i, j, nbytes, nv;
   int index;
   LONG old_ofs, *new_ofs;
   char struct_def_name[20];
   char *buf, *vdat;

   nbytes = db->block_hdr.data_dir_nentries * DATA_DIR_ENTRY_SIZE;
   for (i = 0; i < db->block_hdr.dir_nentries; i++)
   {
      if ((buf = malloc(nbytes)) == NULL)
      {
         db->error_code = INSUFFICIENT_MEMORY;
         db->error_data = DATA_DIR;
         goto error_found;
      }
      old_ofs = *((LONG *) (db->profile_dir + i * db->block_hdr.dir_entry_nbytes));
      if ((db->error_code = read_data(fpin, buf, old_ofs, nbytes)) != 0)
      {
         db->error_data = DATA_DIR;
         goto error_found;
      }
      if (convert_array_struct((char *) db->data_dir, buf, from, HOST_ENVIRONMENT,
         db->block_hdr.data_dir_nentries, "data_dir_entry",
         &(dbint_sd[0].data_dir_entry)) == BADUINT)
      {
         db->error_code = CONVERT_ERROR;
         db->error_data = DATA_DIR;
         goto error_found;
      }
      free(buf);
      /* This initial write of the data directory is unnecessary and causes
         trouble when writing files across networked machines 6/25/90
      if ((db->error_code = write_data(db->fdblkdata, (char *) db->data_dir, ofs, nbytes))
         != 0)
         return(ierr);
      */
      /* The next two lines added 8/1/90:  The profile offsets may change
         if profiles get deleted or profile data shrink via DBPUT or ... */
      new_ofs = (LONG *)(db->profile_dir + i * db->block_hdr.dir_entry_nbytes);
      *new_ofs = file_nbytes;
      file_nbytes += nbytes;

      for (j = 0; j < db->block_hdr.data_dir_nentries; j++)
      {
         if ((index = get_data_list_ndx(j)) < 0)
         {
            db->error_code = INVALID_TYPE_REQUEST;
            db->error_data = DATA_LIST;
            goto error_found;
         }
         if (db->data_dir[j].nbytes == 0)
            continue;
         if ((buf = malloc(db->data_dir[j].nbytes)) == NULL)
         {
            db->error_code = INSUFFICIENT_MEMORY;
            db->error_data = index;
            goto error_found;
         }
         if ((vdat = malloc(db->data_dir[j].nbytes)) == NULL)
         {
            db->error_code = INSUFFICIENT_MEMORY;
            db->error_data = index;
            goto error_found;
         }
         if ((db->error_code = read_data(fpin, buf, old_ofs + db->data_dir[j].ofs,
            db->data_dir[j].nbytes)) != 0)
         {
            db->error_data = index;
            goto error_found;
         }
         if (db->data_list[index].value_type == STRUCT_VALUE_CODE)
            nv = -(db->data_dir[j].nbytes);
         else
            nv = db->data_dir[j].nbytes /
               VALUE_SIZE[db->data_list[index].value_type];
         if (convert_select(vdat, buf, from, to, nv,
            db->data_list[index].value_type, db->data_list[index].name,
            db->struct_def) == BADUINT)
         {
            db->error_code = CONVERT_ERROR;
            db->error_data = index;
            goto error_found;
         }
         free(buf);
         db->data_dir[j].ofs = file_nbytes - *new_ofs;
         if ((db->error_code = write_data(db->fpblkdata, vdat,
            *new_ofs + db->data_dir[j].ofs, db->data_dir[j].nbytes)) != 0)
         {
            db->error_data = index;
            goto error_found;
         }
         file_nbytes += db->data_dir[j].nbytes;
         free(vdat);
      }

      /*-----------------rewrite data directory --------------------*/
      if (to == HOST_ENVIRONMENT)
      {
         if ((db->error_code = write_data(db->fpblkdata, (char *) db->data_dir, *new_ofs, nbytes))
            != 0) 
         {
            db->error_data = DATA_DIR;
            goto error_found;
         }
      }
      else
      {
         if ( (buf = malloc(nbytes)) == NULL )
         {
            db->error_code = INSUFFICIENT_MEMORY;
            db->error_data = DATA_DIR;
            goto error_found;
         }
         if (convert_array_struct(buf, (char *) db->data_dir, HOST_ENVIRONMENT, to,
            db->block_hdr.data_dir_nentries, "data_dir_entry",
            &(dbint_sd[0].data_dir_entry)) == BADUINT)
         {
            db->error_code = CONVERT_ERROR;
            db->error_data = DATA_DIR;
            goto error_found;
         }
         if ((db->error_code = write_data(db->fpblkdata, buf, *new_ofs, nbytes))
            != 0) 
         {
            db->error_data = DATA_DIR;
            goto error_found;
         }
         free(buf);
      }
   }
   /*-----------------rewrite profile directory --------------------*/
   if (to == HOST_ENVIRONMENT)
   {
      if ( (db->error_code = write_profile_dir()) != 0 ) 
      goto error_found;
   }
   else
   {
      nbytes = db->block_hdr.dir_nentries * db->block_hdr.dir_entry_nbytes;
      if ( (buf = malloc(nbytes)) == NULL )
      {
         db->error_code = INSUFFICIENT_MEMORY;
         db->error_data = PROFILE_DIR;
         goto error_found;
      }
      sprintf(struct_def_name, "profile_dir_%1ld_entry", db->block_hdr.dir_type);
      if (convert_array_struct(buf, db->profile_dir, HOST_ENVIRONMENT, to,
         db->block_hdr.dir_nentries, struct_def_name,
         &(dbint_sd[0].profile_dir_0_entry)) == BADUINT)
      {
         db->error_code = CONVERT_ERROR;
         db->error_data = PROFILE_DIR;
         goto error_found;
      }
      if ( (db->error_code = write_data(db->fpblkdata, buf, db->block_hdr.dir_ofs, nbytes)) != 0)
      {
         db->error_data = PROFILE_DIR;
         goto error_found;
      }

      free(buf);
   }
   return(0);
   error_found:
      report_db_error("convert_profile_data");
      return(-1);
}

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

    FUNCTION:  get_data_list_ndx

       Returns the data list ID number of a profile variable, given its
       data directory ID number.

    RETURNS:

       the data list ID number if okay
       -1 if the data directory ID number is invalid or does not
       correspond to profile-variable data

*/
#if PROTOTYPE_ALLOWED
int get_data_list_ndx(unsigned int index)
#else
int get_data_list_ndx(index)
unsigned int index;
#endif
{
   int i = 0;

   while (i < db->block_hdr.data_list_nentries)
   {
      if ((db->data_list[i].access_type == PROFILE_VAR_ACCESS_CODE) &&
         (db->data_list[i].access_0 == (ULONG) index))
         return(i);
      i++;
   }
   return(-1);
}

#if PROTOTYPE_ALLOWED
int convert_block_ftr(void)
#else
int convert_block_ftr()
#endif
{
   unsigned int nbytes;

   if (db->block_hdr.block_ftr_ofs &&
      (nbytes = (unsigned int)
               (db->block_hdr.block_nbytes - db->block_hdr.block_ftr_ofs)) > 0)
   {
      if ( (db->block_ftr = malloc(nbytes)) == NULL )
      {
         db->error_code = INSUFFICIENT_MEMORY;
         goto error_found;
      }

      if ((db->error_code = read_data(fpin, db->block_ftr,
         db->block_hdr.block_ftr_ofs, nbytes)) != 0)
      {
         goto error_found;
      }
      if ((db->error_code = write_data(db->fpblkdata, db->block_ftr,
         file_nbytes, nbytes)) != 0)
      {
         goto error_found;
      }
      db->block_hdr.block_ftr_ofs = file_nbytes;
      file_nbytes += nbytes;
      free(db->block_ftr);
   }
   return(0);

   error_found:
      db->error_data = BLOCK_FTR;
      report_db_error("convert_block_ftr");
      return(-1);
}

