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

   FILE: blk_asc.c

   Purpose: routines for converting a block file to ASCII. Concern
            given to machine type from which input block file was
            created, but the output is ASCII.

   Called by: asc_dump.c


   95/08 (JR) - removed some redundant code (dbint_sd[] and
                identify_ms_code)

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

/*--------------------
   BYTE-COPYING FLAGS
  --------------------*/
#define AS_IS    0
#define INVERTED 1
#define SPECIAL  2

/* global variables */
FILE *fpin, *fpasc;
BLOCK_HDR_TYPE dest_bh;
DATA_LIST_ENTRY_TYPE dest_data_list[MAX_DATA_LIST_SIZE];
STRUCT_DEF_HDR_TYPE *dest_block_strdef;
STRUCT_DEF_HDR_TYPE *dest_struct_def = NULL;
DATA_DIR_ENTRY_TYPE dest_data_dir[MAX_DATA_LIST_SIZE];
char *dest_profile_dir;
long file_nbytes;
int from, to;

#if PROTOTYPE_ALLOWED
int write_blk_ftr(void);
void write_asc_block_hdr(void);
void write_asc_data_list(void);
void strip_blk_name(char *outfile, char *infile);
int convert_asc_data_list(void);
int  convert_asc_block_strdef(void);
int  convert_asc_profile_dir(void);
int  convert_asc_block_var_data(void);
int  convert_asc_profiles(void);
#else
int write_blk_ftr();
void write_asc_block_hdr();
void write_asc_data_list();
void strip_blk_name();
int convert_asc_data_list();
int  convert_asc_block_strdef();
int  convert_asc_profile_dir();
int  convert_asc_block_var_data();
int  convert_asc_profiles();
#endif

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

    FUNCTION: convert_blk_ascii

       Converts a CODAS block file named <infile>, which could have been a
       different machine, to an ASCII file of the destination
       <destmach> machine.

    RETURNS:

       0 if okay
       CODAS error code otherwise

*/
#if PROTOTYPE_ALLOWED
int convert_blk_asc(char *infile, int destmach)
#else
int convert_blk_asc(infile, destmach)
char *infile;
int destmach;
#endif

{
   char outfile[13];
   int ierr = 0, ftr_missing=0;
   /*STRUCT_DEF_HDR_TYPE **link_address;*/
   BLOCK_HDR_TYPE src_bh;

/*
-----> OPEN CODAS BLOCK FILE
*/
#if (COMPILER == VAX_VMS_C)
   char tempfile[L_tmpnam];

   tmpname(tempfile);
   if ((ierr = copy_file(infile, tempfile)) != 0)
      return(ierr);
   if ((fpin = open_binary_file(tempfile, READ_ONLY)) == NULL)
   {
      unlink(tempfile);
#else
   if ((fpin = open_binary_file(infile, READ_ONLY)) == NULL)
   {
#endif
      return(FILE_PROTECTION_ERROR);
   }

/*
-----> OPEN ASCII OUTPUT FILE
*/
   strip_blk_name( outfile, infile );              /* make output filename */
   if ( (fpasc = fopen(outfile, "w")) == NULL )
      return(FILE_PROTECTION_ERROR);
   file_nbytes = 0;


/*
-----> READ IN BLOCK HEADER
*/
   if ((ierr = read_data(fpin, (char *) &src_bh, 0L, BLOCK_HDR_SIZE)) != 0)
      return(ierr);

/*
-----> IDENTIFY SOURCE MACHINE CODE
*/
   if ((from = identify_ms_code(src_bh.ms_code)) == UNKNOWN_HOST)
      return(UNKNOWN_HOST_ERROR);
   to = destmach;

/*
-----> CONVERT BLOCK HEADER from SOURCE to HOST BYTE ORDER
*/
   if (convert_struct((char *) &dest_bh, (char *) &src_bh, 
      from, HOST_ENVIRONMENT, "block_hdr", &(dbint_sd[0].block_hdr)) == BADUINT)
      return(CONVERT_ERROR);

/*
-----> WRITE OUT BLOCK FOOTER TO ASCII OUTPUT
*/
       ftr_missing = write_blk_ftr( );
       if( ftr_missing != 0 && ftr_missing != 1 ) goto free_data;

/*
-----> WRITE OUT SELECTED BLOCK HEADER ELEMENTS TO ASCII OUTPUT
*/
      if( ftr_missing ) write_asc_block_hdr();
      file_nbytes = BLOCK_HDR_SIZE;    /*increment global var for file offset */

/*
-----> CONVERT and WRITE OUT SELECTED DATA LIST ELEMENTS TO ASCII OUTPUT
*/

      if ((ierr = convert_asc_data_list()) != 0) goto free_data;
  
/*
-----> FILL MEMEORY WITH BLOCK STRUCTURE DEFINITIONS
*/
      if ((ierr = convert_asc_block_strdef()) != 0) goto free_data;
      if (dest_bh.struct_def_nentries > 0)
         concat_strdef(&dest_struct_def, dest_block_strdef);

/*
-----> CONVERT PROFILE DIRECTORY TO HOST MACHINE AND SAVE IN MEMORY
*/
      if ((ierr = convert_asc_profile_dir()) != 0) goto free_data;

/*
-----> CONVERT and WRITE OUT BLOCK VARIABLES TO ASCII OUTPUT
*/
      if ((ierr = convert_asc_block_var_data()) != 0) goto free_data;

/*
-----> CONVERT and WRITE OUT PROFILE VARIABLES TO ASCII OUTPUT
*/
      if ((ierr = convert_asc_profiles()) != 0) goto free_data;
      if (dest_struct_def == dest_block_strdef) dest_struct_def = NULL;
  

   free_data:
      free(dest_block_strdef);
      free(dest_profile_dir);
      /*if (db->prev_strdef)
      {
         link_address = (STRUCT_DEF_HDR_TYPE **) &(db->prev_strdef->LINK_PTR);
         *link_address = NULL;
      }*/

/*   close_files: */
      fclose(fpasc);
      fclose(fpin);
#if (COMPILER == VAX_VMS_C)
      unlink(tempfile);
#endif
      return(ierr);
}


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

   FUNCTION:  write_asc_block_hdr

      It writes out as ASCII select portions of block header to
      output FILE *fpasc (global variable).

   RETURNS:  VOID

*/
#if PROTOTYPE_ALLOWED
void write_asc_block_hdr(void)
#else
void write_asc_block_hdr()
#endif

{
   fprintf(fpasc,"START_BLOCK_HEADER:");
   fprintf(fpasc,"\ndataset id: %.32s",  (char *) &(dest_bh.dataset_id));
   fprintf(fpasc,"\nproducer id: %.32s", (char *) &(dest_bh.producer_id));
   fprintf(fpasc,"\ntime:  ");
   prpckt(fpasc, &(dest_bh.time1));
   fprintf(fpasc," --- to --- ");
   prpckt(fpasc, &(dest_bh.time2));
   fprintf(fpasc,"\nlongitude: ");
   prpckp(fpasc, &(dest_bh.lon1));
   fprintf(fpasc," --- to --- ");
   prpckp(fpasc, &(dest_bh.lon2));
   fprintf(fpasc,"\nlatitude:  ");
   prpckp(fpasc, &(dest_bh.lat1));
   fprintf(fpasc," --- to --- ");
   prpckp(fpasc, &(dest_bh.lat2));
   fprintf(fpasc,"\ndepth: %d", dest_bh.depth1);
   fprintf(fpasc," --- to --- %d", dest_bh.depth2);
   fprintf(fpasc,"\nEND_BLOCK_HEADER:");
}

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

   FUNCTION: write_asc_data_list

      Write out in ASCII selected elements of each entry in the data list.

   RETURNS:  VOID

*/
#if PROTOTYPE_ALLOWED 
void write_asc_data_list(void)
#else 
void write_asc_data_list()
#endif
{
   int i, ic=0;

   struct t_tag {
        char bv_type[8];
    };
   static struct t_tag actype[3] = { " ", "  BLOCK", "PROFILE" };
   struct o_tag {
        char org[13];
    };
    static struct o_tag orgtype[2] = { "BINNED_ARRAY","STRUCTURE" };
    int iorg;

/* count number of data entries for output */
   for (i = 0; i < dest_bh.data_list_nentries; i++)
      if (dest_data_list[i].access_type)
          ic++;

   fprintf(fpasc,"\nSTART_DATA_LIST:     NUMBER OF ENTRIES= %d\n", ic);
   fprintf(fpasc," # name               units    variable_type   organization\n");
   fprintf(fpasc,"------------------------------------------------------------\n");

/*
-----> FOR EACH ENTRY, WRITE OUT THE NAME, UNITS, and note for
       BLOCK OR PROFILE VARIABLE 
*/
   for (i = 0; i < dest_bh.data_list_nentries; i++)
      if (dest_data_list[i].access_type)
      {
         iorg = 0; /* index for binned array vs structure type */
         if( dest_data_list[i].value_type == 11 ) iorg = 1;
         fprintf(fpasc,"%2d", i);
         fprintf(fpasc," %-20s%-7.7s    %s      %s\n",
                        dest_data_list[i].name,
                        dest_data_list[i].units,
                        actype[dest_data_list[i].access_type].bv_type,
                        orgtype[iorg].org);
      }
   fprintf(fpasc,"END_DATA_LIST: \n");
}


/*-----------------------------------------------------------------------------
 
    FUNCTION:  strip_blk_name
 
           Strips out root name of block file <bf> for use as root name of
           ascii file <af>
 
    RETURNS: VOID
 
 
*/
#if PROTOTYPE_ALLOWED
void strip_blk_name(char *af, char *bf )
#else
void strip_blk_name( af, bf )
char *af, *bf;
#endif
{
   int path=0;
 
   /*test if path provided*/
   if( (strchr( bf, '\057' ) != '\0') || *bf == '\056' ) path = 1;

   if( path )
      {
      /* move pointer to end of string */
      while( *bf++ != '\0' ) ;
 
      /* find slash before file name */
      while( *bf-- != '\057' ) ;
 
      /* place pointer at start of filename */
      *bf++;
      *bf++;
      }
 
   /* grab file name root */
   while( *bf != '\056' ) *af++ = *bf++;
 
   /* add file extension for ascii */
   *af++ = '\056';
   *af++ = 'a';
   *af++ = 's';
   *af++ = 'c';
   *af = '\0';
}

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

    FUNCTION:  convert_asc_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.

       P.Caldwell April, 1994: this is a modified version of
       convert_data_list from file mc1.c

    RETURNS:

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

*/
#if PROTOTYPE_ALLOWED
int convert_asc_data_list(void)
#else
int convert_asc_data_list()
#endif
{
   unsigned int nbytes;
   int ierr;
   char *buf;
  
   if (dest_bh.data_list_nentries > 0)
   {
      nbytes = dest_bh.data_list_nentries * DATA_LIST_ENTRY_SIZE;
      if (nbytes == 0)
         return(DATA_LIST_IS_EMPTY);
      if ((buf = malloc(nbytes)) == NULL)
         return(INSUFFICIENT_MEMORY);
      if ((ierr = read_data(fpin, buf, BLOCK_HDR_SIZE, nbytes)) != 0)
         return(ierr);
      if (convert_array_struct( (char *) dest_data_list, buf, 
                                 from, HOST_ENVIRONMENT,
         dest_bh.data_list_nentries, "data_list_entry",
         &(dbint_sd[0].data_list_entry)) == BADUINT)
         return(CONVERT_ERROR);
      free(buf);
      file_nbytes += nbytes;
      write_asc_data_list();           /* WRITE OUT DATA LIST IN ASCII */
   }
   return(0);
}

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

    FUNCTION:  convert_asc_block_strdef

       Converts the structure definitions in a CODAS block file to the
       HOST_ENVIRONMENT machine format.

       P.Caldwell April, 1994: this is a modified version of
       convert_block_strdef from file mc1.c

    RETURNS:

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

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

   if (dest_bh.struct_def_nentries > 0)
   {
      nbytes = dest_bh.struct_def_nentries * STRUCT_DEF_ENTRY_SIZE;
      if ( (buf = malloc(nbytes)) == NULL
         || (dest_block_strdef = (STRUCT_DEF_HDR_TYPE *) malloc(nbytes)) == NULL)
         return(INSUFFICIENT_MEMORY);
      if ((ierr = read_data(fpin, buf, BLOCK_HDR_SIZE +
         dest_bh.data_list_nentries * DATA_LIST_ENTRY_SIZE, nbytes)) != 0)
         return(ierr);
      do
      {
         dest_ptr = (STRUCT_DEF_HDR_TYPE *) (((char *) dest_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) 
            return(CONVERT_ERROR);
	 if (convert_struct((char *) src_ptr, (char *) dest_ptr, HOST_ENVIRONMENT, to,
	    "struct_def_hdr",  &(dbint_sd[0].struct_def_hdr)) == BADUINT) return(CONVERT_ERROR);
         ofs += converted_nb;
         nelem = dest_ptr->nelem;
         for (i = 0; i < nelem; i++)
         {
            dest_ptr = (STRUCT_DEF_HDR_TYPE *) (((char *) dest_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)
               return(CONVERT_ERROR);
            if (convert_struct((char *) src_ptr, (char *) dest_ptr, HOST_ENVIRONMENT, to,
	       "struct_def_elem", &(dbint_sd[0].struct_def_elem)) == BADUINT) return(CONVERT_ERROR);
            ofs += converted_nb;
         }
      } while (ofs < nbytes);
      free(buf);
      file_nbytes += nbytes;
   }
   return(0);
}

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

    FUNCTION:  convert_asc_profile_dir

       Converts the profile directory in a CODAS block file to the
       HOST_ENVIRONMENT machine format.

       P.Caldwell April, 1994: this is a modified version of
       convert_profile_dir from file mc1.c

    RETURNS:

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

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

   if (dest_bh.dir_nentries > 0)
   {
      sprintf(struct_def_name, "profile_dir_%1ld_entry", dest_bh.dir_type);
      nbytes = dest_bh.dir_nentries * dest_bh.dir_entry_nbytes;
      if (nbytes == 0)
         return(PROFILE_DIR_IS_EMPTY);
      if ((buf = malloc(nbytes)) == NULL || 
          (dest_profile_dir = malloc(nbytes)) == NULL)
         return(INSUFFICIENT_MEMORY);
      if ((ierr = read_data(fpin, buf, dest_bh.dir_ofs, nbytes)) != 0)
         return(ierr);
      if (convert_array_struct(dest_profile_dir, buf, from, to,
         dest_bh.dir_nentries, struct_def_name,
         &(dbint_sd[0].profile_dir_0_entry)) == BADUINT)
         return(CONVERT_ERROR);
      free(buf);
      file_nbytes += nbytes;
   }
   return(0);
}

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

    FUNCTION:  convert_asc_block_var_data

       Converts all the block-variable data in a CODAS block file to the
       HOST_ENVIRONMENT machine format and writes them to an ASCII output file.

       P.Caldwell April, 1994: this is a modified version of
       convert_block_var_data from file mc1.c

    RETURNS:

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

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

   fprintf(fpasc,"START_BLOCK_VARIABLES:\n");
   for (i = 0; i < dest_bh.data_list_nentries; i++)
      if ( dest_data_list[i].access_type == BLOCK_VAR_ACCESS_CODE)
      {
         nbytes = dest_data_list[i].access_1;
         if (nbytes == 0)
            continue;
         if ((buf = malloc(nbytes)) == NULL || (vdat = malloc(nbytes)) == NULL)
            return(INSUFFICIENT_MEMORY);
         if ((ierr = read_data(fpin, buf, dest_data_list[i].access_0, nbytes)) != 0)
            return(ierr);
         if (dest_data_list[i].value_type == STRUCT_VALUE_CODE)
            nv = -nbytes;
         else
            nv = nbytes / VALUE_SIZE[dest_data_list[i].value_type];
         if (convert_select(vdat, buf, from, to, nv, dest_data_list[i].value_type,
            dest_data_list[i].name, dest_struct_def) == BADUINT)
            return(CONVERT_ERROR);
         free(buf);
         file_nbytes += nbytes;
         /*
         ---> Write out in ASCII
         */
         if( dest_data_list[i].value_type == 11 )
            fprintf(fpasc,"START_STRUCT:");
         else
            fprintf(fpasc,"START_ARRAY:");

         print_select( fpasc, vdat, 
                       (STRUCT_DEF_ELEM_TYPE *) &(dest_data_list[i]),
                       nv, NULL, dest_struct_def );
         if( dest_data_list[i].value_type == 11 )
            fprintf(fpasc,"END_STRUCT:\n");
         else
            fprintf(fpasc,"\nEND_ARRAY:\n");
            
         free(vdat);
      }
   fprintf(fpasc,"END_BLOCK_VARIABLES:\n");
   return(0);
}

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

    FUNCTION:  convert_asc_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 as ASCII. 

       P.Caldwell April, 1994: this is a modified version of
       convert_profiles from file mc1.c

    RETURNS:

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

*/
#if PROTOTYPE_ALLOWED
int convert_asc_profiles(void)
#else
int convert_asc_profiles()
#endif
{
   PROFILE_DIR_3_ENTRY_TYPE *profile_dir_entry_ptr;
   unsigned int i, j, nbytes, nv;
   int ierr, index;
   LONG old_ofs, *new_ofs;
   YMDHMS_TIME_TYPE time_prof;
   YMDHMS_TIME_TYPE block_base_time;
   char *buf, *vdat;

#if PROTOTYPE_ALLOWED
   unsigned int print_rescale_select(FILE *fp, char *data, DATA_LIST_ENTRY_TYPE *nuv, unsigned int n);
   int get_asc_data_list_ndx( unsigned int j );
#else
   unsigned int print_rescale_select();
   int get_asc_data_list_ndx();
#endif

   fprintf(fpasc,"START_PROFILE_VARIABLES:     NUMBER PROFILES= %d\n",
           dest_bh.dir_nentries);
   nbytes = dest_bh.data_dir_nentries * DATA_DIR_ENTRY_SIZE;

    UPCKTIM(&(block_base_time), &(dest_bh.time1));
/*
--> FOR EACH PROFILE DIRECTORY ENTRY
*/
   for (i = 0; i < dest_bh.dir_nentries; i++)
   {
      /*
      ---> PRINT OUT PROFILE KEY AND PROFILE DTG/POSITION
      */
      fprintf(fpasc,"START_PROFILE_%d:\n",i+1);
      profile_dir_entry_ptr = (PROFILE_DIR_3_ENTRY_TYPE *)
                              (dest_profile_dir + i * dest_bh.dir_entry_nbytes);


      fprintf(fpasc,"Time= ");
      DIFTIM((YMDHMS_TIME_TYPE *)&(block_base_time),
            &time_prof,
            (LONG *)&(profile_dir_entry_ptr->time));
      print_ymdhms_time(fpasc, &time_prof);
      if (dest_bh.dir_type == 1 || dest_bh.dir_type == 3)
      {
         fprintf(fpasc,"\nLongitude= " );
         prpckp(fpasc, &(profile_dir_entry_ptr->lon));
         fprintf(fpasc," Latitude= " );
         prpckp(fpasc, &(profile_dir_entry_ptr->lat));
      }
      /*
      ---> ALLOCATE MEMORY TO HOLD DATA DIRECTORY FOR THIS PROFILE,
           SET POINTER TO THE START OF DATA DIRECTORY, CONVERT THE
           DATA DIRECTORY TO HOST MACHINE, HOLD IN MEMORY, AND FREE BUFFER
      */
      if ((buf = malloc(nbytes)) == NULL)
         return(INSUFFICIENT_MEMORY);
      old_ofs = *((LONG *) (dest_profile_dir + i * dest_bh.dir_entry_nbytes));
      if ((ierr = read_data(fpin, buf, old_ofs, nbytes)) != 0)
         return(ierr);
      if (convert_array_struct((char *) dest_data_dir, buf, from, 
          HOST_ENVIRONMENT, dest_bh.data_dir_nentries, "data_dir_entry",
         &(dbint_sd[0].data_dir_entry)) == BADUINT)
         return(CONVERT_ERROR);
      free(buf);
      /* 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 *)(dest_profile_dir + i * dest_bh.dir_entry_nbytes);
      *new_ofs = file_nbytes;
      file_nbytes += nbytes;

      /*
      ----> FOR EACH DATA DIRECTORY ENTRY
      */
      for (j = 0; j < dest_bh.data_dir_nentries; j++)
      {
         if ((index = get_asc_data_list_ndx(j)) < 0)
            return(INVALID_TYPE_REQUEST);
         if (dest_data_dir[j].nbytes == 0)
            continue;
         if ((buf = malloc(dest_data_dir[j].nbytes)) == NULL)
            return(INSUFFICIENT_MEMORY);
         if ((vdat = malloc(dest_data_dir[j].nbytes)) == NULL)
            return(INSUFFICIENT_MEMORY);
         if ((ierr = read_data(fpin, buf, old_ofs + dest_data_dir[j].ofs,
            dest_data_dir[j].nbytes)) != 0)
            return(ierr);
         if (dest_data_list[index].value_type == STRUCT_VALUE_CODE)
            nv = -(dest_data_dir[j].nbytes);
         else
            nv = dest_data_dir[j].nbytes /
               VALUE_SIZE[dest_data_list[index].value_type];
         if (convert_select(vdat, buf, from, to, nv,
            dest_data_list[index].value_type, dest_data_list[index].name,
            dest_block_strdef) == BADUINT)
            return(CONVERT_ERROR);
         free(buf);
         file_nbytes += dest_data_dir[j].nbytes;
         if( dest_data_list[index].value_type == 11 )
            fprintf(fpasc,"\nSTART_STRUCT:");
         else 
            fprintf(fpasc,"\nSTART_ARRAY:");
         /*
         ---> SPECIAL ATTENTION FOR OFFSET AND SCALE ADJUSTMENTS
         */
         if( dest_data_list[index].offset != 0. ||
             dest_data_list[index].scale  != 1. )
             print_rescale_select( fpasc, vdat,
                       &(dest_data_list[index]),
                       nv);
         else
             print_select( fpasc, vdat, 
                       (STRUCT_DEF_ELEM_TYPE *) &(dest_data_list[index]),
                       nv, NULL, dest_block_strdef );
         if( dest_data_list[index].value_type == 11 ) 
            fprintf(fpasc,"END_STRUCT:");
         else 
            fprintf(fpasc,"\nEND_ARRAY:");
         free(vdat);
      }
      fprintf(fpasc,"\nEND_PROFILE_%d:\n",i+1);
   }
   fprintf(fpasc,"END_PROFILE_VARIABLES:");
   return(0);
}

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

    FUNCTION:  get_asc_data_list_ndx

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

       Modified version of get_data_list_ndx for ascii dump program
       (Pat Caldwell April 1994)

    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_asc_data_list_ndx(unsigned int index)
#else
int get_asc_data_list_ndx(index)
unsigned int index;
#endif
{
   int i = 0;

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

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

   FUNCTION: pr_rescale_select

      This function prints data to a file using either given or default
      formats AFTER RESCALING THE DATA BASED ON OFFSET AND SCALE AS
      DEFINED IN THE DATA LIST.  The data can be of any type from
      VALUE_CODE--single element, array, or structure.

      THIS IS A MODIFIED VERSION OF PRINT_SELECT (PCC 4/11/94)

   PARAMETERS:

      fp = pointer to FILE to print to

      data = pointer to data to be printed

      nuv = pointer to structure with ff. members:

         1) name = variable name for data

         2) units = variable units ("none" or "" or NULL if not applicable)

         3) value_type = VALUE_CODE (0 to 11)

         The structure may therefore correspond to a DATA_LIST_ENTRY_TYPE
         or a STRUCT_DEF_ELEM_TYPE.

      n = no. of elements in data

*/
#if PROTOTYPE_ALLOWED
unsigned int print_rescale_select(FILE *fp, char *data, DATA_LIST_ENTRY_TYPE *nuv, unsigned int n)
#else
unsigned int print_rescale_select(fp, data, nuv, n)
FILE *fp;
char *data;
DATA_LIST_ENTRY_TYPE *nuv;
unsigned int n;
#endif
{
   int ncol;
   unsigned int byte_count = 0;
   FLOAT *rdat;
   static char format[]= "%12.6f";
   fprintf(fp, " %20s : ", nuv->name);
   fprintf(fp, "in %s ", nuv->units);
   fprintf(fp, "(%u VALUES)\n\n", n);
   /*
   ---> Rescale and apply offset
   */
   if ((rdat =  (FLOAT *) malloc ( n * sizeof( FLOAT ) )) == NULL)
         return(INSUFFICIENT_MEMORY);

   switch (nuv->value_type)
   {
      case BYTE_VALUE_CODE:
         UNSCALE_BYTE_TO_FLOAT( rdat,  (BYTE *) data,
                                &(nuv->scale), &(nuv->offset), &n);
         break;
      case UBYTE_VALUE_CODE:
         UNSCALE_UBYTE_TO_FLOAT( rdat,  (UBYTE *) data,
                                &(nuv->scale), &(nuv->offset), &n);
         break;
      case SHORT_VALUE_CODE:
         UNSCALE_SHORT_TO_FLOAT( rdat,  (SHORT *) data,
                                &(nuv->scale), &(nuv->offset), &n);
         break;
      case USHORT_VALUE_CODE:
         UNSCALE_USHORT_TO_FLOAT( rdat,  (USHORT *) data,
                                &(nuv->scale), &(nuv->offset), &n);
         break;
      case LONG_VALUE_CODE:
         UNSCALE_LONG_TO_FLOAT( rdat,  (LONG *) data,
                                &(nuv->scale), &(nuv->offset), &n);
         break;
      case ULONG_VALUE_CODE:
         UNSCALE_ULONG_TO_FLOAT( rdat,  (ULONG *) data,
                                &(nuv->scale), &(nuv->offset), &n);
         break;
      case FLOAT_VALUE_CODE:
         UNSCALE_FLOAT_TO_FLOAT( rdat,  (FLOAT *) data,
                                &(nuv->scale), &(nuv->offset), &n);
         break;
      case DOUBLE_VALUE_CODE:
         UNSCALE_DOUBLE_TO_FLOAT( rdat,  (DOUBLE *) data,
                                &(nuv->scale), &(nuv->offset), &n);
         break;
      }
   ncol = 6;
   byte_count = print_array_float(fp, rdat, n, ncol, format);
   free(rdat);
   return(byte_count);
}
/*******************************************************************

      FUNCTION  write_blk_ftr
       Converts the block footer in a CODAS block file to the
       HOST_ENVIRONMENT machine format and writes it to the ascii
       output file.

      RETURN   0 if ok
               1 if footer missing
               special code if not ok

*/
#if PROTOTYPE_ALLOWED
int write_blk_ftr(void)
#else
int write_blk_ftr()
#endif
{
   unsigned int nbytes;
   int ierr;
   char *dest_buf;
  
      if( dest_bh.block_ftr_ofs == 0 ) return(1); 
      nbytes = dest_bh.block_nbytes - dest_bh.block_ftr_ofs;
      if (nbytes == 0)
         return(0);
      if ((dest_buf = malloc(nbytes)) == NULL)
         return(INSUFFICIENT_MEMORY);
      if ((ierr = read_data(fpin, dest_buf, dest_bh.block_ftr_ofs, nbytes)) != 0)
         return(ierr);
      /* write out to ascii file */
      fprintf(fpasc,"\nSTART_DOCUMENTATION: \n");
      fwrite( dest_buf, nbytes, 1, fpasc );
      fprintf(fpasc,"\nEND_DOCUMENTATION: \n");
      
      free(dest_buf);
      return(0);
}
