/******************************************************************************
*
*  NSSDC/CDF                                            CDFwalk.  Part 2 of 2.
*
*  Version 1.4f, 17-May-96, Hughes STX.
*
*  Modification history:
*
*   V1.0   1-May-92, H Leckner  Original version.
*                    J Love
*   V1.1  21-Aug-92, H Leckner  CDF V2.3 (shareable/zVar/NeXT).
*                    J Love
*   V1.2   2-Dec-93, H Leckner  CDF V2.4.
*   V1.2a  4-Feb-94, J Love     DEC Alpha/OpenVMS port.
*   V1.3  13-Dec-94, J Love     CDF V2.5.
*   V1.3a 23-Feb-95, J Love	Use `IsGraphChr'.
*   V1.4   4-Apr-95, J Love	POSIX.
*   V1.4a 18-Apr-95, J Love	More POSIX.
*   V1.4b 13-Jun-95, J Love	Linux.
*   V1.4c 20-Jun-95, J Love	Fixed bug involving NUL-termination of buffer
*				receiving character data read from the CDF.
*   V1.4d 17-Jul-95, J Love	CDFexport-related changes.
*   V1.4e 18-Sep-95, J Love	Macintosh event handling.
*   V1.4f 17-May-96, J Love	Linux `gcc' warnings.
*
******************************************************************************/

#include "cdfwalk.h"

CDFstatus     CDFWALK_select_RZ(screen, CDF, tcode)
struct  GLOBAL_struct   *screen;
struct  CDF_struct      *CDF;
int                     *tcode;
{
int                     ok;
int                     tempcode;
long                    temp_val = 1;
int                    k,i;
char                    buf[80],temp[10];
int                     len;
int                     RZ_rows, RZ_columns;
struct vid_struct       *RZ_display;
static char             noRvar_mes[] = "There are no rVariables in this CDF";
static char             noRdata_mes[] = "The rVariables contain no data";
if(C.num_ZCDF > RZ_ROWS)
   RZ_rows = RZ_ROWS;
else
   RZ_rows = (int) C.num_ZCDF;
RZ_columns = 0;
RZ_display = (struct vid_struct *)
		  malloc((size_t) C.num_ZCDF * sizeof(struct vid_struct));
if(RZ_display == NULL)return(BAD_MALLOC);
for(k=0; k<C.num_ZCDF; k++)
    {
    for(i=0; i<80; i++)buf[i] = ' ';
    if(k == 0)
	    strcpy(buf, "rVariables");
    else if(C.num_dims[k] == 0)
	    strcpy(buf, "Z  0:[]");
    else
	    {
	    buf[0] = 'Z';
	    sprintf(buf+2,"%2d:[",(int)C.num_dims[k]);
	    if(C.num_dims[k] > 0)
	       {
	       for (i=0; i < C.num_dims[k]; i++)
		    {
		    sprintf(temp, "%ld", C.dim_sizes[k][i]);
		    if(i < C.num_dims[k]-1)
		       strcat(temp, ",");
		    else
		       strcat(temp,"]");
		    strcat(buf, temp);
		    }
	       }
	    }
    len = strlen(buf);
    if(len > RZ_columns)RZ_columns = len;
    RZ_display[k].row = k+1;
    RZ_display[k].col = 1;
    strcpy(RZ_display[k].label,buf);
   }
   if(RZ_columns > RZ_COLUMNS)RZ_columns = RZ_COLUMNS;
   create_virtual_display(RZ_rows+BORDER_ROWS, RZ_columns+BORDER_COLUMNS, 
				&S.RZ_vid, BORDER, NORMAL);
   ok = FALSE;
   while(!ok)
      { 
      CDFWALK_select_menu_item(S.RZ_vid, S.MES_vid,
	   &temp_val, RZ_display, (int) C.num_ZCDF, RZ_rows, RZ_columns,
	   RZ_ROW_PASTE, RZ_COL_PASTE, MENU, &tempcode);
      if(tempcode == QUITkey_WALK)
	      {
	      *tcode = QUITkey_WALK;
	      ok = TRUE;
	      }
      else if(temp_val == 1 && C.numRvars ==  0)
	      CDFWALK_put_message(S.MES_vid, noRvar_mes, RINGBELL,
					NORMAL, PAUSE);
      else if(temp_val == 1 && C.max_record_num[0] == -1)
	      CDFWALK_put_message(S.MES_vid, noRdata_mes, RINGBELL,
					NORMAL, PAUSE);
      else
	      {
	      *tcode = tempcode;
	      SO.curr_CDF = (int) (temp_val - 1);
	      ok = TRUE;
	      }
      }
   free(RZ_display);
   delete_virtual_display(S.RZ_vid);
   return(CDF_OK);
}
void CDFWALK_load_discrete(values, num_values, num_bytes, DIS_display,
			num_rows, num_cols)
char                    values[];
long                    num_values;
long                    num_bytes;
struct vid_struct       *DIS_display;
int                     *num_rows;
int                     *num_cols;
{

int                    i;
for (i=0; i<num_values; i++)
     {
	DIS_display[i].row = 1;
	DIS_display[i].col = 1;
	strncpy(DIS_display[i].label,&values[(int)(i*(num_bytes+1))],
		(size_t) num_bytes);
	DIS_display[i].label[(int)num_bytes] = '\0';
     }

*num_rows = (int) (num_values > DIS_ROWS ? DIS_ROWS : num_values);

*num_cols = (int) (num_bytes < DIS_COLUMNS ? num_bytes : DIS_COLUMNS);
}
void CDFWALK_get_EPOCH(CDF_id, Z, var_num, max_record_num,
			bin_values, char_values)
CDFid                   CDF_id;
int                     Z;
long                    var_num;
long                    max_record_num;
double                  bin_values[];
char                    *char_values;
{
long                    indices[CDF_MAX_DIMS];
long                    counts[CDF_MAX_DIMS];
long                    intervals[CDF_MAX_DIMS];
long                    record_num;
long                    recInterval;
int                    i;
CDFstatus               rcode;

for (i=0; i < CDF_MAX_DIMS; i++)
     {
     indices[i] = 0;
     counts[i] = 1;
     intervals[i] = 1;
     }
record_num = 0;
recInterval = 1;
rcode = CDFlib (SELECT_, CDF_, CDF_id, 
		     Zq(Z, zVAR_, rVAR_),  var_num,
		     Zq(Z, zVAR_RECNUMBER_,rVARs_RECNUMBER_),record_num,
		     Zq(Z, zVAR_RECCOUNT_, rVARs_RECCOUNT_), max_record_num+1,
		     Zq(Z, zVAR_RECINTERVAL_, rVARs_RECINTERVAL_),  recInterval,
		     Zq(Z, zVAR_DIMINDICES_, rVARs_DIMINDICES_), indices,
		     Zq(Z, zVAR_DIMCOUNTS_, rVARs_DIMCOUNTS_),    counts,
		     Zq(Z, zVAR_DIMINTERVALS_, rVARs_DIMINTERVALS_), intervals,
	    GET_,    Zq(Z, zVAR_HYPERDATA_, rVAR_HYPERDATA_),     bin_values,
		    NULL_);
if(rcode == CDF_OK)
   {
   for (record_num=0; record_num <= max_record_num; record_num++)
     {
     encodeEPOCH (bin_values[(int)record_num],
		  &char_values[(int)(record_num*EPOCH_WIDTH)]);
     }
   }
}
void CDFWALK_get_discrete(CDF_id, Z, dim_num, var_id, data_type, num_values,
		  bin_values, char_values)
CDFid                   CDF_id;
int                     Z;
long                    dim_num;
long                    var_id;
long                    data_type;
long                    num_values;
double                  bin_values[];
char                    *char_values;
{
long                    indices[10];
char                    temp_val[MINMAX_SIZE+1];
int                     i;
long                    record_num;
CDFstatus               rcode;
union   mixed           temp;
double                  r4_r8();

record_num = 0;
for (i=0; i < 10; i++)
     indices[i] = 0;
for (i=0; i < num_values; i++)
     {
     if(dim_num > 0)
	indices[(int)(dim_num-1)]=i;
     else
	record_num = i;
     rcode = CDFlib (SELECT_, CDF_, CDF_id,
			  Zq(Z,zVAR_,rVAR_), var_id,
			  Zq(Z,zVAR_RECNUMBER_,rVARs_RECNUMBER_),record_num,
			  Zq(Z,zVAR_DIMINDICES_,rVARs_DIMINDICES_),indices,
		 GET_,    Zq(Z,zVAR_DATA_,rVAR_DATA_), &temp,
		 NULL_);
     
     if(rcode >= CDF_OK)
	{
	switch(data_type)
	     {
	     case CDF_REAL4:
	     case CDF_FLOAT:
	     bin_values[i] = r4_r8(&temp.r4);
	     if(bin_values[i] < -1.e12 ||
		bin_values[i] >  1.e12)
		sprintf(temp_val,"%e",bin_values[i]);
	     else
		sprintf(temp_val,"%f",bin_values[i]);
	     break;
	     case CDF_REAL8:
	     case CDF_DOUBLE:
	     case CDF_EPOCH:
		     if(temp.r8 < -1.e12 ||
			temp.r8 >  1.e12)
			sprintf(temp_val,"%e",temp.r8);
	     else
			sprintf(temp_val,"%f",temp.r8);
		     bin_values[i] = temp.r8;
		     break;
	     case CDF_INT4:
		     sprintf(temp_val,"%ld",temp.i4);
		     bin_values[i] = (double) temp.i4;
		     break;
	     case CDF_UINT4:
		     sprintf(temp_val,"%lu",temp.ui4);
		     bin_values[i] = (double) temp.ui4;
		     break;
	     case CDF_INT2:
		     sprintf(temp_val,"%d",temp.i2);
		     bin_values[i] = (double) temp.i2;
		     break;
	     case CDF_UINT2:
		     sprintf(temp_val,"%u",temp.ui2);
		     bin_values[i] = (double) temp.ui2;
		     break;
	     case CDF_BYTE:
	     case CDF_INT1:
		     sprintf(temp_val,"%d",temp.byte);
		     bin_values[i] = (double) temp.byte;
		     break;
	     case CDF_UINT1:
		     sprintf(temp_val,"%u",temp.ubyte);
		     bin_values[i] = (double) temp.ubyte;
	     }
	temp_val[MINMAX_SIZE-1] = '\0';
	zero_replace(temp_val);
	strcpy(&char_values[i*MINMAX_SIZE], temp_val);
	}
     }
}
void CDFWALK_get_discrete_char(CDF_id, Z, dim_num, var_num, num_values,
		num_bytes, char_values)
CDFid                   CDF_id;
int                     Z;
long                    dim_num;
long                    var_num;
long                    num_values;
long                    num_bytes;
char                    *char_values;
{
char                    *temp;
long                    indices[10];
int                     i;
long                    record_num;
CDFstatus               rcode;
temp = (char *) malloc((size_t)(num_bytes+1));
record_num = 0;
for (i=0; i < 10; i++)
     indices[i] = 0;
for (i=0; i < num_values; i++)
     {
     indices[(int)(dim_num-1)] = i;
     rcode = CDFlib (SELECT_, CDF_, CDF_id,
			  Zq(Z,zVAR_,rVAR_), var_num,
			  Zq(Z,zVAR_RECNUMBER_,rVARs_RECNUMBER_),record_num,
			  Zq(Z,zVAR_DIMINDICES_,rVARs_DIMINDICES_),indices,
		 GET_,    Zq(Z,zVAR_DATA_,rVAR_DATA_), temp,
		 NULL_);
     temp[(int)num_bytes] = '\0';
     if(rcode == CDF_OK) strcpy(&char_values[(int)(i*(num_bytes+1))], temp);
     }
free (temp);
}
void CDFWALK_clear_row(vid, display, start_elem, end_elem, end_col)
WINDOWid                vid;
struct  vid_struct      display[];
int                     start_elem;
int                     end_elem;
int                     end_col;
{
int                     i;
int                     len;

int                     row, col;

for (i=start_elem; i<=end_elem; i++)
     {
     len = strlen(display[i-1].label);
     row = display[i-1].row;
     col = display[i-1].col + len;
     erase_display(vid, row, col, row, end_col);
     }
}
void CDFWALK_help(screen)
struct          GLOBAL_struct   *screen;
{
long                    dummy = 0;
struct vid_struct       *HELP_display;
long                    help_num_elements = 0;
int                     i;
long                    len;
int                     tcode;
AOSs1 (help_mes, "Press _____ key when done")
static char             help_error_mes[] = "Help not available ";
static char             help_error_mal[] = "Help not available, malloc error ";
char                    temp[80];
int                     help_rows, help_columns, paste_col;
int                     max_len;
EncodeKeyDefinitions(1, help_mes, HELPDONEkey_WALK);
if(HELP_ptr != NULL)
   {
/*
READ text until complete and load into a vid structure
*/
   max_len = 0;
   fseek(HELP_ptr, 0l, SEEK_SET);
   while (fgets(temp,80,HELP_ptr) != NULL)
	  {
	  help_num_elements++;
	  len = lastc(temp);
	  if(len > max_len) max_len = (int) len;
	  }
   if(help_num_elements > HELP_ROWS)
      help_rows = HELP_ROWS;
   else
      help_rows = (int) help_num_elements;

   if(max_len > HELP_COLUMNS)
      help_columns = HELP_COLUMNS;
   else
      help_columns = max_len;

   paste_col = (80-(help_columns+BORDER_COLUMNS))/2;

   create_virtual_display(help_rows+BORDER_ROWS,help_columns+BORDER_COLUMNS,
		 &S.HELP_vid, BORDER, NORMAL);

   HELP_display = (struct vid_struct *)
		  malloc((size_t) help_num_elements * sizeof(struct vid_struct));
   if(HELP_display == NULL)
      {
      CDFWALK_put_message(S.MES_vid, help_error_mal, RINGBELL, NORMAL,
		NOPAUSE);
      return;
      }
   fseek(HELP_ptr, 0l, SEEK_SET);
   i=0;
   for(i=0; i <help_num_elements; i++)
	{
	fgets(temp,80,HELP_ptr);
	HELP_display[i].row = 1;
	HELP_display[i].col = 1;
	len = lastc(temp) - 1;
	strncpy(HELP_display[i].label,temp,(size_t)len);
	HELP_display[i].label[(int)len] = '\0';
	}
/*
LOAD in the keypad definitions for this option
*/
	CDFWALK_help_keydef(screen);
	CDFWALK_put_message(S.MES_vid, help_mes[0], NOBELL, NORMAL, NOPAUSE);
/*
Display the HELP screen
*/
	CDFWALK_select_menu_item(S.HELP_vid, S.MES_vid,
	&dummy, HELP_display, (int) help_num_elements, help_rows, help_columns,
	HELP_ROW_PASTE, paste_col, HELP_MENU, &tcode);
	delete_virtual_display(S.HELP_vid);
	free(HELP_display);
   }
else
   CDFWALK_put_message(S.MES_vid, help_error_mes, RINGBELL, NORMAL, NOPAUSE);
}
int lastc(buf)
char    *buf;
{
int done = FALSE;
int i,j;
int end;
i = strlen(buf) + 1;
end = i;
j = 0;
while(j < end && !done)
      {
      if(!IsGraphChr(buf[i-1]))
	 done = TRUE;
      else
	 j++; i--;
      }
return(i);
}

void CDFWALK_field_menu(screen, CDF_id, option)
struct          GLOBAL_struct   *screen;
CDFid           CDF_id;
long            *option;
{
int             tcode, cont;
long            temp;
temp = *option+1;
cont = CONTINUEkey_WALK;
while(cont != DONE)
      {
/*
Choose the particular field you wish to be in
*/
      CDFWALK_Menu_keydef(screen);
      CDFWALK_select_menu_item(S.FIELD_vid, S.MES_vid, &temp,
      FIELD_display, FIELD_NUM_ELEMENTS, FIELD_ROWS, FIELD_COLUMNS,
      FIELD_ROW_PASTE, FIELD_COL_PASTE, MENU, &tcode);
      *option = temp-1;
      if(*option == HELP_FIELD)
	 CDFWALK_help(screen);
      else if(*option == SPECIAL_OPT_FIELD)
	      CDFWALK_special_options(screen, CDF_id);
      else
	 cont = DONE;
       }
}

void CDFWALK_open_screen(screen)
struct  GLOBAL_struct   *screen;
{
create_pasteboard();
begin_pasteboard_update();
create_virtual_display(CDF_ROWS+BORDER_ROWS, CDF_COLUMNS+BORDER_COLUMNS, 
	&S.CDF_vid, BORDER, NORMAL);
paste_virtual_display(S.CDF_vid, CDF_ROW_PASTE, CDF_COL_PASTE);
load_vid(S.CDF_vid, CDF_display, 0, CDF_NUM_ELEMENTS-1, NO_label);
create_virtual_display(VAR_ROWS+BORDER_ROWS, VAR_COLUMNS+BORDER_COLUMNS, 
			&S.VAR_vid, BORDER, NORMAL);
paste_virtual_display(S.VAR_vid, VAR_ROW_PASTE, VAR_COL_PASTE);
create_virtual_display(KEY_ROWS+BORDER_ROWS, KEY_COLUMNS+BORDER_COLUMNS, 
			&S.KEY_vid, BORDER, NORMAL);
paste_virtual_display(S.KEY_vid, KEY_ROW_PASTE, MES_COL_PASTE);
create_virtual_display(MES_ROWS+BORDER_ROWS, MES_COLUMNS+BORDER_COLUMNS, 
				&S.MES_vid, BORDER, NORMAL);
paste_virtual_display(S.MES_vid, MES_ROW_PASTE, MES_COL_PASTE);
create_virtual_display(VARSCROLL_ROWS+BORDER_ROWS, 
		       VARSCROLL_COLUMNS+BORDER_COLUMNS, &S.VARSCROLL_vid,
			BORDER, NORMAL);
create_virtual_display(FIELD_ROWS+BORDER_ROWS, FIELD_COLUMNS+BORDER_COLUMNS, 
			&S.FIELD_vid, BORDER, NORMAL);
create_virtual_display(DIS_ROWS+BORDER_ROWS, DIS_COLUMNS+BORDER_COLUMNS, 
				&S.DIS_vid, BORDER, NORMAL);
create_virtual_display(DIM_ROWS+BORDER_ROWS, DIM_COLUMNS+BORDER_COLUMNS, 
			&S.DIM_vid, BORDER, NORMAL);
create_virtual_display(DIR_ROWS+BORDER_ROWS, DIR_COLUMNS+BORDER_COLUMNS, 
			&S.DIR_vid, BORDER, NORMAL);
create_virtual_display(SPECIAL_ROWS+BORDER_ROWS,SPECIAL_COLUMNS+BORDER_COLUMNS, 
			&S.SPECIAL_vid, BORDER, NORMAL);
create_virtual_display(VARFORMAT_ROWS+BORDER_ROWS, 
		       VARFORMAT_COLUMNS+BORDER_COLUMNS,
			&S.VARFORMAT_vid, BORDER, NORMAL);
create_virtual_display(ZERO_ROWS+BORDER_ROWS, 
		       ZERO_COLUMNS+BORDER_COLUMNS,
			&S.ZERO_vid, BORDER, NORMAL);
end_pasteboard_update();
/*enable_trap(S.MES_vid);*/
load_vid(S.KEY_vid, KEY_display, 0, KEY_NUM_ELEMENTS, KEY_label);
load_vid(S.MES_vid, MES_display, 0, MES_NUM_ELEMENTS, MES_label);
}
void CDFWALK_special_options(screen, CDF_id)
struct  GLOBAL_struct   *screen;
CDFid                   CDF_id;
{
int     tcode;
int     field_num;
int     save;
static char star[]  = "*";
static char noformat_mes[] =
"This CDF does not a contain the attribute FORMAT, switching back to default";
AOSs1 (VARFORM_mes,
"USE CDF FORMAT attribute to display data, ___ to leave Special Option Window")
AOSs1A (ZERO_mes,
"CONVERT -0.0 to +0.0 or IGNORE -0.0, ___ to quit")
EncodeKeyDefinitions(1, VARFORM_mes, QUITkey_WALK);
EncodeKeyDefinitions(1, ZERO_mes, QUITkey_WALK);

begin_pasteboard_update();
paste_virtual_display(S.SPECIAL_vid, SPECIAL_ROW_PASTE, SPECIAL_COL_PASTE);
label_border(S.SPECIAL_vid, SPECIAL_label, REVERSE);

paste_virtual_display(S.VARFORMAT_vid, VARFORMAT_ROW_PASTE,
			VARFORMAT_COL_PASTE);
load_vid(S.VARFORMAT_vid, VARFORMAT_display, 0,
	VARFORMAT_NUM_ELEMENTS, VARFORMAT_label);

paste_virtual_display(S.ZERO_vid, ZERO_ROW_PASTE,
			ZERO_COL_PASTE);
load_vid(S.ZERO_vid, ZERO_display, 0,
	ZERO_NUM_ELEMENTS, ZERO_label);

end_pasteboard_update();

put_chars(S.VARFORMAT_vid, star, 1, SO.variable_format, 2, NOERASE, NORMAL);
put_chars(S.ZERO_vid, star, 1, SO.zero, 2, NOERASE, NORMAL);
CDFWALK_special_keydef(screen);
tcode = NORMAL;
field_num = VARFORMAT_FIELD;
while(tcode != QUITkey_WALK)
  {
  switch(field_num)
	 {
	 case VARFORMAT_FIELD:
	      CDFWALK_put_message(S.MES_vid, VARFORM_mes[0], NOBELL, NORMAL,
					NOPAUSE);
	      tcode = CDFWALK_special_option_menu(S.VARFORMAT_vid,
			&SO.variable_format, VARFORMAT_NUM_ELEMENTS);
	      if(!SO.format && SO.variable_format == FORMAT)
		 {
		 SO.variable_format = NOFORMAT;
		 CDFWALK_put_message(S.MES_vid, noformat_mes, RINGBELL, NORMAL,
					PAUSE);
		 CDFWALK_disp_opt(S.VARFORMAT_vid, SO.variable_format,
				VARFORMAT_NUM_ELEMENTS);
		 }
	      break;
	 case ZERO_FIELD:
	      CDFWALK_put_message(S.MES_vid, ZERO_mes[0], NOBELL, NORMAL,
					NOPAUSE);
	      save = SO.zero;
	      tcode = CDFWALK_special_option_menu(S.ZERO_vid,
			&SO.zero, ZERO_NUM_ELEMENTS);
	      if(SO.zero != save)NEG_to_POS(CDF_id);
	 }
	 field_num++;
	 if(field_num > ZERO_FIELD)
	    field_num = VARFORMAT_FIELD;
	 else if(field_num < VARFORMAT_FIELD)
		 field_num = ZERO_FIELD;
   }

begin_pasteboard_update();
unpaste_virtual_display(S.VARFORMAT_vid);
unpaste_virtual_display(S.ZERO_vid);
unpaste_virtual_display(S.SPECIAL_vid);

CDFWALK_clear_row(S.MES_vid, MES_display, 1, 1, MES_COLUMNS);

end_pasteboard_update();


}
int CDFWALK_special_option_menu(vid, value, num_rows)
WINDOWid        vid;
int             *value;
int             num_rows;
{
int             done;
int             row,col;
int             tcode;

done = FALSE;
row = *value;
col = 2;
while(!done)
  {
  set_cursor_abs(vid, row, col);
  read_input(
#if defined(CURSESui)
	     vid,
#endif
		 &tcode, PASSTHRUri, TRUE);
  switch(tcode)
	 {
	 case QUITkey_WALK:
	 case ACTIONkey_WALK:
	      tcode = QUITkey_WALK;
	      done = TRUE;
	      break;
	 case SELECTkey_WALK:
	      done = TRUE;
	      break;
	 case PREVITEMkey_WALK:
	      row--;
	      if(row < 1)row = num_rows;
	      break;
	 case NEXTITEMkey_WALK:
	      row++;
	      if(row > num_rows)row = 1;
	      break;
	 case REFRESHkey_FSI:
	      repaint_screen();
	      break;
	  }
  CDFWALK_disp_opt(vid, row, num_rows);
  }

*value = row;
return(tcode);
}
void CDFWALK_disp_opt(vid, row, num_rows)
WINDOWid        vid;
int             row;
int             num_rows;
{
int             i;
static char star[]  = "*";
static char blank[] = " ";

for(i=1; i<=num_rows;i++)
      {
      if(i == row)
	 put_chars(vid, star, 1, i, 2, NOERASE, NORMAL);
      else
	 put_chars(vid, blank, 1, i, 2, NOERASE, NORMAL);
      }
}

void CDFWALK_select_menu_item(vid, MES_vid, rvalue, display,
num_elements, num_rows, num_columns, row_start, col_start, mode, termcode)
WINDOWid        vid;
WINDOWid        MES_vid;
long             *rvalue;
struct          vid_struct      display[];
int             num_elements;
int             num_rows;
int             num_columns;
int             row_start;
int             col_start;
int             mode;
int             *termcode;
{
int             in_value;
int             row, col;
int             tcode;
int             done;
int             num_screen;
int             start_page;
int             end;
int             value;
int             row1 = 1;
int             col1 = 1;
static char     top[]    = "Top of menu";
static char     bottom[] = "Bottom of menu";

in_value = (int) *rvalue;
/*
Find out the number of rows to be on the screen at one time
*/
if(num_elements > num_rows)
   num_screen = num_rows;
else
   num_screen = num_elements;
/*
Erase and load data into the menu for selection
*/
value = 1;
row = 1;
col = 1;
begin_pasteboard_update();
erase_display(vid, 1, 1, num_rows, num_columns);
load_menu(vid, display, num_screen, NO_label);
change_rendition(vid,1,1,num_rows,num_columns,NORMAL);
paste_virtual_display(vid, row_start, col_start);
end_pasteboard_update();
start_page = 1;
if(mode == MENU)change_rendition(vid, row, col, 1, num_columns, REVERSE);
done = FALSE;
while(!done)
     {
     set_cursor_abs(vid, row, col);
     read_input(
#if defined(CURSESui)
		vid,
#endif
		    &tcode, PASSTHRUri, TRUE);
     switch (tcode)
	  {
	  case NEXTITEMkey_WALK:
	       if(row == num_rows || value == num_elements)
		  if(value < num_elements)
		     {
/*
SCROLL UP
*/
		     value++; start_page++;
		     begin_pasteboard_update();
		     erase_display(vid, row1, col1, num_rows, num_columns);
		     load_menu(vid, display+(start_page-1),
		     num_screen, NO_label);
		     end_pasteboard_update();
		     }
		  else
		     {
		     value = 1;
		     row = 1;
		     start_page = 1;
		     begin_pasteboard_update();
		     erase_display(vid, 1, 1, num_rows, num_columns);
		     load_menu(vid, display, num_screen, NO_label);
		     end_pasteboard_update();
		     }
	       else
		  {
		  row++; value++;
		  if(row == num_rows && value == num_elements)
		     CDFWALK_put_message(MES_vid, bottom, NOBELL, 
					NORMAL, NOPAUSE);
		  }
	       break;
	  case PREVITEMkey_WALK:
	       if(row > 1)
		  {
		     row--;
		     value--;
		  }
	       else if(value > 1)
		  {
/*
SCROLL DOWN
*/
		     value--; start_page--;
		     begin_pasteboard_update();
		     erase_display(vid, row1, col1, num_rows, num_columns);
		     load_menu(vid, display+(start_page-1),
		     num_screen, NO_label);
		     end_pasteboard_update();
		  }
	       else
		  {
		     start_page = num_elements - num_screen + 1;
		     value = num_elements;
		     row = num_screen;
		     begin_pasteboard_update();
		     erase_display(vid, row1, col1, num_rows, num_columns);
		     load_menu(vid, display+(start_page-1),
		     num_screen, NO_label);
		     end_pasteboard_update();
		  }
	       break;
/*
PAGE DOWN
*/
	  case PAGEDOWNkey_WALK:
	       start_page = start_page + num_screen;
	       end = start_page + num_screen - 1;
	       value = value + num_screen;
	       if(end > num_elements)
		  {
/*
Display the next page down
*/
		  end = num_elements;
		  start_page = end - num_screen + 1;
		  value = num_elements;
		  row = num_rows;
		  CDFWALK_put_message(MES_vid, bottom, NOBELL, NORMAL, NOPAUSE);
		  }
	       begin_pasteboard_update();
	       erase_display(vid, row1, col1, num_rows, num_columns);
	       load_menu(vid, display+(start_page-1), num_screen, NO_label);
	       end_pasteboard_update();
	       break;
/*
PAGE UP
*/
	  case PAGEUPkey_WALK:
	       start_page = start_page - num_screen;
	       value = value - num_screen;
	       if(start_page < 1)
		  {
		  start_page = 1;
		  value = 1;
		  row = 1;
		  CDFWALK_put_message(MES_vid, top, NOBELL, NORMAL, NOPAUSE);
		  }
	       begin_pasteboard_update();
/*
Display the next page up
*/
	       erase_display(vid, row1, col1, num_rows, num_columns);
	       load_menu(vid, display+(start_page-1), num_screen, NO_label);
	       end_pasteboard_update();
	       break;
	  case SELECTkey_WALK:
	       done = TRUE;
	       *rvalue = value;
	       *termcode = SELECTkey_WALK;
	       break;
	  case QUITkey_WALK:
	       done = TRUE;
	       *rvalue = in_value;
	       *termcode = QUITkey_WALK;
	       break;
	  case ACTIONkey_WALK:
	       done = TRUE;
	       *rvalue = value;
	       *termcode = ACTIONkey_WALK;
	       break;
	  case REFRESHkey_FSI:
	       repaint_screen();
	       break;
	  default:
		break;
	  }
	  if(mode == MENU)
	     {
	     change_rendition(vid, 1, 1, num_rows, num_columns, NORMAL);
	     change_rendition(vid, row, 1, 1, num_columns, REVERSE);
	     }
      }
unpaste_virtual_display(vid);
}
int CDFWALK_CDF_name(screen, CDF, field_num, input_type)
struct  GLOBAL_struct   *screen;
struct  CDF_struct      *CDF;
long                    *field_num;
long                    *input_type;
{
char                    file_spec[256],temp[256] /*, dummy[256]*/ ;
static char             save[CDF_PATHNAME_LEN];
char                    save_name[CDF_PATHNAME_LEN];
char                    save_temp[CDF_PATHNAME_LEN];
char                    **directory_list;
char                    **result_spec_list;
int                     num_files = 0;
int                     termcode = CONTINUEkey_WALK;
int                     drows;
int                     i, row;
long                    CDF_num = 1;
int                     tcode;
int                     done;
int                     dir;
char                    row_data[CDF_COLUMNS+1];

#if defined(unix) || defined(posixSHELL)
static char curr_dir[] = "./";
#else
#if defined(dos)
static char curr_dir[] = ".\\";
#else
#if defined(vms)
static char curr_dir[] = "[]";
#else
#if defined(mac)
static char curr_dir[] = "";
#endif
#endif
#endif
#endif

static char dir_mes[] =
"Enter Directory and/or CDF name (default=CDFs in current directory)";
static char dir_error[] = "No CDFs found, reenter directory and/or CDF name";
AOSs1 (select_mes,
"Select a CDF or press _____ to enter a new Directory/CDF name")
struct vid_struct       *DIR_display;
int                     new_CDF;
int                     regfile;
int                     last_error = FALSE;
static int              exit_keys[] = { SELECTkey_WALK, ACTIONkey_WALK, NUL };
EncodeKeyDefinitions(1, select_mes, QUITkey_WALK);
strcpy(save_name, C.CDF_name);
new_CDF= FALSE;
done = FALSE;
regfile = FALSE;
while(!done)
{
if(*input_type == MANUAL)
   {
   if(firstForCDFname)
      {
      CDFWALK_CDFname_keydef(screen);
      if(!last_error)
	 {
	 if(!SO.spec_entered)strcpy(C.CDF_name, default_name);
	 CDFWALK_put_selection(S.CDF_vid, CDF_display, 0,
	      C.CDF_name, CDF_NAME_LENGTH, REVERSE);
	 }
      CDFWALK_put_message(S.MES_vid, dir_mes, NOBELL, NORMAL, NOPAUSE);
      input_field(S.CDF_vid, C.CDF_name, CDF_NAME_ROW, CDF_NAME_COL,
	CDF_NAME_LENGTH, exit_keys, &termcode, INSERTTOGGLEkey_WALK, 
	MOVEtoBEGINkey_WALK, MOVEtoENDkey_WALK, NOTTHERE, DELETEtoENDkey_WALK,
		  REFRESHkey_FSI);
      }
   else
      CDFWALK_put_selection(S.CDF_vid, CDF_display, 0,
	      save, CDF_NAME_LENGTH, REVERSE);
   }
else
    termcode = SELECTkey_WALK;
*input_type = MANUAL;
firstForCDFname = FALSE;
last_error = FALSE;
CDFWALK_clear_row(S.MES_vid, MES_display, 1, 1, MES_COLUMNS);
if(termcode == ACTIONkey_WALK)
   {
   CDFWALK_field_menu(screen, C.CDF_id, field_num);
   if((int) (*field_num) != CDF_FIELD)
      {
      done = TRUE;
      tcode = QUITkey_WALK;
      }
   else
      firstForCDFname = TRUE;
   }
else
   {
   row = CDF_NAME_ROW;

   read_display(S.CDF_vid, row, row_data);

   strncpy(temp, row_data+(CDF_NAME_COL-1), CDF_NAME_LENGTH);
   temp[CDF_NAME_LENGTH] = '\0';
   remove_trail(temp);
/*
Save for next time
*/
   strcpy(save_temp, temp);

   strcpy (file_spec, temp);
   if (strlen(file_spec) == 0) strcpy (file_spec, curr_dir);

   dir = FALSE;
   regfile = FALSE;

   if (IsCDF(file_spec)) regfile = TRUE;
   if (IsDir(file_spec)) dir = TRUE;

   num_files = /*DirList*/
	       CDFdirList (file_spec, &directory_list, &result_spec_list);

   if(num_files > 0)
      {
      strcpy(save, save_temp);
      done = TRUE;
      if(num_files == 1 && regfile)
	 {
	 CDF_num = 1;
	 tcode = SELECTkey_WALK;
	 firstForCDFname = TRUE;
	 }
       else
	 {
/*
allocate the space for a vid structure which contains the CDF NAMES
*/
	 DIR_display = (struct vid_struct *)
	       malloc(num_files * sizeof(struct vid_struct));
	 if(DIR_display == NULL) return ((int) BAD_MALLOC);
/*
Load in the cdf names into the structure
*/
	 for (i=0; i<num_files; i++)
	   {
	   DIR_display[i].row = 1;
	   DIR_display[i].col = 1;
	   strcpy(DIR_display[i].label, result_spec_list[i]);
	   }
	 if(num_files > DIR_ROWS)
	     drows = DIR_ROWS;
	 else
	     drows = num_files;
	 create_virtual_display(drows+BORDER_ROWS, DIR_COLUMNS+BORDER_COLUMNS,
				   &S.DIR_vid, BORDER, NORMAL);
	 CDFWALK_put_message(S.MES_vid, select_mes[0], NOBELL, NORMAL, NOPAUSE);
	 CDFWALK_Menu_keydef(screen);
	 CDFWALK_select_menu_item(S.DIR_vid,
	   S.MES_vid, &CDF_num, DIR_display, num_files, drows,
	   DIR_COLUMNS, DIR_ROW_PASTE, DIR_COL_PASTE, MENU, &tcode);
	 delete_virtual_display(S.DIR_vid);
	 free (DIR_display);
	 } /* end num_files > 1 */
	 if(tcode == SELECTkey_WALK)
	      {
	      if(dir || strlen(directory_list[(int)(CDF_num-1)]) > (size_t) 0)
		 {
		 strcpy(C.CDF_name, directory_list[(int)(CDF_num-1)]);
		 AppendToDir(C.CDF_name, result_spec_list[(int)(CDF_num-1)]);
		 }
	      else
		 strcpy(C.CDF_name, result_spec_list[(int)(CDF_num-1)]);

	      C.CDF_name[CDF_NAME_LENGTH]= '\0';
	      CDFWALK_put_selection(S.CDF_vid, CDF_display, 0,
	      C.CDF_name, CDF_NAME_LENGTH, REVERSE);
	      new_CDF = TRUE;
	      *field_num = WALK_FIELD;
	      }
	   else
	      {
	      change_rendition(S.CDF_vid, CDF_NAME_ROW, CDF_NAME_COL, 1,
		  strlen(C.CDF_name), REVERSE);
	      if(tcode == ACTIONkey_WALK)
		 {
		 CDFWALK_field_menu(screen, C.CDF_id, field_num);
		 if((int) (*field_num) == CDF_FIELD)done = FALSE;
		 }
	      else
		 done = FALSE;
	      firstForCDFname = TRUE;
	  } /* num > 1 */

	  FreeMemory (directory_list, FatalError);
	  FreeMemory (result_spec_list, FatalError);
       } /*num_file > 0*/
       else
	   {
	   CDFWALK_put_message(S.MES_vid, dir_error, RINGBELL, NORMAL, PAUSE);
	   firstForCDFname = TRUE;
	   last_error = TRUE;
	   }
   }/*keyboard != C-F*/
}/*done?*/
/*
If a new CDF was not selected put the old one back on the input line
*/
if(!new_CDF)
   {
   strcpy(C.CDF_name, save_name);
   CDFWALK_put_selection(S.CDF_vid, CDF_display, 0,
	      C.CDF_name, CDF_NAME_LENGTH, REVERSE);
   }
SO.spec_entered = FALSE;
return(tcode);

}
void CDFWALK_CDF_info(screen, CDF, CDF_display)
struct  GLOBAL_struct   *screen;
struct  CDF_struct      *CDF;
struct  vid_struct      CDF_display[];
{
char            string[21];
char            temp[7];
int             i;
sprintf(string, "%ld ", C.num_vars[SO.curr_CDF]);
CDFWALK_clear_row(S.CDF_vid, CDF_display, NUMVAR_ELEMENT_NUM,
			NUMVAR_ELEMENT_NUM, 27);
CDFWALK_put_selection(S.CDF_vid, CDF_display, NUMVAR_ELEMENT_NUM-1, string,
	6, REVERSE);
sprintf(string, "%ld ", C.max_record_num[SO.curr_CDF]+1);
CDFWALK_clear_row(S.CDF_vid, CDF_display, NUMREC_ELEMENT_NUM,
			NUMREC_ELEMENT_NUM, CDF_COLUMNS);
CDFWALK_put_selection(S.CDF_vid, CDF_display, NUMREC_ELEMENT_NUM-1, string,
	6, REVERSE);
sprintf(string, "%ld ", C.num_dims[SO.curr_CDF]);
CDFWALK_clear_row(S.CDF_vid, CDF_display, NUMDIM_ELEMENT_NUM,
			NUMDIM_ELEMENT_NUM, CDF_COLUMNS);
CDFWALK_put_selection(S.CDF_vid, CDF_display, NUMDIM_ELEMENT_NUM-1, string,
	2, REVERSE);
string[0] = '\0';
CDFWALK_clear_row(S.CDF_vid, CDF_display, DIMSIZ_ELEMENT_NUM,
			DIMSIZ_ELEMENT_NUM, CDF_COLUMNS);
if(C.num_dims[SO.curr_CDF] > 0)
   {
   for (i=0; i < C.num_dims[SO.curr_CDF]; i++)
	{
	sprintf(temp, "%ld ", C.dim_sizes[SO.curr_CDF][i]);
	strcat(string, temp);
	}
   }
else
    string[0] = '\0';
CDFWALK_put_selection(S.CDF_vid, CDF_display, DIMSIZ_ELEMENT_NUM-1, string,
	10, REVERSE);
}
void load_vid(vid, display, start_element, num_elements, label)
WINDOWid                vid;
struct  vid_struct      display[];
int                     start_element;
int                     num_elements;
char                    label[];
{
int                     i;
int                     len;

int             erase_mode = NOERASE;
int             video_type = NORMAL;
len = strlen(label);
if(len > 0)label_border(vid, label, REVERSE);
for(i=0; i< num_elements; i++)
    {
    len = strlen(display[i+start_element].label);
    put_chars(vid, display[i+start_element].label, len,
    display[i+start_element].row, display[i+start_element].col,
	erase_mode, video_type);
    }
}
void load_vid_element(vid, display, element_num)
WINDOWid                vid;
struct  vid_struct      display[];
int                     element_num;
{

int                     len;

int                    erase_mode = NOERASE;
int                    video_type = NORMAL;

len = strlen(display[element_num-1].label);
put_chars(vid, display[element_num-1].label, len,
display[element_num-1].row, display[element_num-1].col, erase_mode, video_type);
}
void CDFWALK_load_keydef(vid, line1, line2)
WINDOWid                vid;
char                    line1[];
char                    line2[];
{
int                     row, col;
int                     erase_mode;
int                     video_type;
int                     len;

begin_pasteboard_update();
erase_display(vid, 1, 1, KEY_ROWS, KEY_COLUMNS);
row = 1; col = 1; erase_mode = ERASE; video_type = NORMAL;
len = strlen(line1);
if(len > KEY_COLUMNS)len = KEY_COLUMNS;
put_chars(vid, line1, len, row, col, erase_mode, video_type);
len = strlen(line2);
row = 2; col = 1; erase_mode = ERASE; video_type = NORMAL;
if(len > KEY_COLUMNS)len = KEY_COLUMNS;
put_chars(vid, line2, len, row, col, erase_mode, video_type);
end_pasteboard_update();
}
void CDFWALK_put_selection(vid, display, element_num, selection,
				field_len, video_type)
WINDOWid                vid;
struct  vid_struct      display[];
int                     element_num;
char                    selection[];
int                     field_len;
int                     video_type;
{
/*long                  i;*/
int                     len;

int                     erase_mode = NOERASE;
int                     row, col, end_col;

len = strlen(display[element_num].label);
row = display[element_num].row;
col = display[element_num].col + len;
len = strlen(selection);
end_col = col + field_len - 1;
erase_display(vid, row, col, row, end_col);
put_chars(vid, selection, len, row, col, erase_mode, video_type);
}
void CDFWALK_put_value(vid, display, element_num, bin_value)
WINDOWid                vid;
struct  vid_struct      display[];
int                     element_num;
double                  bin_value;
{
char                    value[20];
int                    i;
int                     len;

int                     erase_mode = NOERASE;
int                     video_type = NORMAL;
int                     row, col, end_col;

len = strlen(display[element_num].label);
row = display[element_num].row;
col = display[element_num].col;
end_col = col + 20;
erase_display(vid, row, col, row, end_col);
sprintf(value,"%f",bin_value);
zero_replace(value);
len = strlen(value);
for(i = len; i<14; i++)
    value[i] = ' ';
value[14] = '\0';
len = 14;
put_chars(vid, value, len, row, col, erase_mode, video_type);
}
void CDFWALK_put_message(vid, message, rbell, video_type, pause)
WINDOWid                vid;
char                    message[];
int                     rbell;
int                     video_type;
int                     pause;
{
/*long                  i;*/
int                     len;

int                     erase_mode = ERASE;
int                     row, col;
#if defined(vms)
float                   wait = 3.;
#endif

len = strlen(message);
row = 1;
col = 1;
if(rbell == RINGBELL)
    ring_bell();
if(len > MES_COLUMNS)len = MES_COLUMNS;
put_chars(vid, message, len, row, col, erase_mode, video_type);
if(pause == PAUSE)
#if 0
#if defined(vms)
		     lib$wait(&wait);
#endif
#if defined(unix) || defined(dos)
		     sleep(3);
#endif
#else
		   zzzzz (3.0);
#endif
}
void load_menu(vid, display, num_elements, label)
WINDOWid                vid;
struct  vid_struct      display[];
int                     num_elements;
char                    label[];
{
int                     i;
int                     len;

int                     erase_mode = NOERASE;
int                     video_type = NORMAL;
int                     row;
int                     col = 1;
len = strlen(label);
if(len > 0)label_border(vid, label, REVERSE);
for(i=0; i< num_elements; i++)
    {
    row = i + 1;
    len = strlen(display[i].label);
    put_chars(vid, display[i].label, len, row, col,
    erase_mode, video_type);
    }
}
void zero_replace(string)
char            string[];
{
long            zero_index;
int             byte /*, ebyte*/ ;
long            found = FALSE;
long            len;

CDFWALK_left_justify(string);
byte = 0;
len = strlen(string);
while(byte < len && !found)
      {
      if(string[byte] == PERIOD)found = TRUE;
      byte++;
      }
if(found)
   {
   zero_index = byte;
   while(byte < len)
      {
      if(string[byte] == '0')
	  {
	  if(zero_index == 0)zero_index = byte;
	  }
      else
	 zero_index = 0;
      byte++;
      }
   if(zero_index > 0)
     {
     for (byte=(int)zero_index; byte<len; byte++)
	  string[byte] = ' ';
     }
   }
}
void CDFWALK_left_justify (field)
	char            field[];
{
	int             i;
	int             index;
	long            done;
	char            *temp;
	long            len;
	len = strlen(field);
	temp = (char *) malloc((size_t)len);

/* Blank out temporary hold area */

	for (i = 0; i < len; i++)
		temp[i] = ' ';


		done = FALSE;
		for (index = 0; done != TRUE && index <= len; index++)

			{
/* Look for a non-blank character */

			if(field[index] != ' ')
				{
/* Left Justify by copying from the non-blank character to the end of field */

				strncpy(temp,field+index,(size_t)(len-index));
				for (i = 0; i < len; i++)
					field[i] = ' ';

/* Now copy from the temporary field back to the permanent field */

				strncpy(field, temp, (size_t) len);
				done = TRUE;
				}
			}
free(temp);
}
int precision(num)
double          num;
{
double          abs_value;
int             p;
abs_value = fabs(num);
if(abs_value < 1.)
	p = 5;
else if(abs_value < 10.)
	p = 4;
else if(abs_value < 10000.)
	p = 3;
else if(abs_value < 100000.)
	p = 2;
else
	p = 1;
return(p);
}
void CDFWALK_free_discrete(variables, num_vars)
struct variable_struct  *variables;
long                    num_vars;
{
long                    var_num;

for(var_num = 0; var_num < num_vars; var_num++)
    {
    if(V.bin_value != NULL)
       {
       free(V.bin_value);
       V.bin_value = NULL;
       }
    if(V.char_value != NULL)
       {
       free(V.char_value);
       V.char_value = NULL;
       }
    }
}
CDFstatus CDFWALK_close(CDF, vars)
struct  CDF_struct      *CDF;
struct variable_struct  **vars;
{
int                     i,k;
int                     var_num;
CDFstatus               rcode;

for(k=0; k<C.num_ZCDF; k++)
    {
    for(var_num = 0; var_num < C.num_vars[k]; var_num++)
	{
	if(vars[k][var_num].format_value != NULL)
	   {
	   free(vars[k][var_num].format_value);
	   vars[k][var_num].format_value = NULL;
	   }
	}
    if(C.num_vars[k] > 0)free(vars[k]);
    }
free(vars);

if(C.num_dims != NULL)
   {
   free(C.num_dims);
   C.num_dims = NULL;
   }
for(i=0; i<C.numZvars+1; i++)
    free(C.dim_sizes[i]);
if(C.dim_sizes != NULL)
   {
   free(C.dim_sizes);
   C.dim_sizes = NULL;
   }
if(C.num_vars != NULL)
   {
   free(C.num_vars);
   C.num_vars = NULL;
   }
if(C.max_record_num != NULL)
   {
   free(C.max_record_num);
   C.max_record_num = NULL;
   }

rcode = CDFlib(SELECT_, CDF_, C.CDF_id,
		CLOSE_, CDF_,
		NULL_);
return(rcode);
}
void CDFWALK_close_screen()
{
delete_pasteboard(ERASE);
}
double r4_r8(r4_ptr)
float   *r4_ptr;
{
/*
Convert float to double
Based on assumption that float contains 7 significant digits
*/
float r4;
double          r4r8;
double          fracr8;
float           realexp,temp,rfrac,x;
double          base, power;
long            exp,frac;
long            evalue;

r4 = *r4_ptr;
/*
If the REAL*4 value is 0 then just set the REAL*8 value to 0 and return
*/
if(r4 == 0.) return(0.);

temp = r4;
evalue  = 0;
/*
Calculate the exponent of the incoming REAL*4 value
If absolute value ge 10 exponent is positive
If absolute value lt 1  exponent is negative
*/
if(fabs(temp) >= 10.)
	{
	while(fabs(temp) >= 10.)
	      {
	      evalue = evalue + 1;
	      temp = temp / 10.;
	      }
	}
else if(fabs(temp) < 1.)
	{
	while(fabs(temp) < 1.)
	      {
	      evalue = evalue - 1;
	      temp = temp * 10.;
	      }
	}
/*
Extract out the fractional portion of the real value
*/
exp = (long    ) r4;
realexp =  (float) exp;
rfrac = r4-realexp;
/*
Convert significant digits of fraction portion to integer by multiplying.
*/
base = 10.;
power = (double) (6-evalue);
x = rfrac*pow(base,power);
if(x > 0.)
   frac = (long    ) (x + .5);
else
   frac = (long    ) (x - .5);
fracr8 = (double) frac;
r4r8 = (double) exp;
/*
Convert the integer back into a fraction by diving.
then ADD back in the integer portion.
*/
r4r8 = r4r8 + fracr8/(pow(base, power));
return(r4r8);
}
long     CDFWALK_get_index(CDF_id, Z, dim_num, var_num, value, data_type,
				dim_values, num_values)
CDFid                   CDF_id;
long                    Z;
long                    dim_num;
long                    var_num;
long                    data_type;
double                  value;
double                  dim_values[];
long                    num_values;
{
int                     i;
double                  diff,closest_diff;
long                    closest_indice;
double                  min,max,fudge_up,fudge_down;
long                    indices[10];
long                    record_num;
CDFstatus               rcode;
double                  test_value;
union   mixed           temp;
double                  r4_r8();


if(data_type != CDF_REAL8 && data_type != CDF_EPOCH)
   {
   fudge_down = .999999; fudge_up = 1.000001;
   if(value > 0.)
      {
      min = fudge_down*value;
      max = fudge_up*value;
      }
   else
      {
      min = fudge_up*value;
      max = fudge_down*value;
      }
   }
else
   {
   min = value;
   max = value;
   }
if(num_values > MAX_VALUES)
   {
   record_num = 0;
   for (i=0; i < CDF_MAX_DIMS; i++)
     indices[i] = 0;
   }
closest_diff = 1.7e38;
closest_indice = 0;
for(i=0; i<num_values; i++)
    {
    if(num_values > MAX_VALUES)
       {
       if(dim_num > 0)
	  indices[(int)(dim_num-1)]=i;
       else
	  record_num = i;
       rcode = CDFlib (SELECT_, CDF_, CDF_id,
			  Zq(Z,zVAR_,rVAR_), var_num,
			  Zq(Z,zVAR_RECNUMBER_,rVARs_RECNUMBER_),record_num,
			  Zq(Z,zVAR_DIMINDICES_,rVARs_DIMINDICES_),indices,
		   GET_,  Zq(Z,zVAR_DATA_,rVAR_DATA_), &temp,
		   NULL_);
       if(rcode >= CDF_OK)
	  {
	  switch(data_type)
	      {
	      case CDF_REAL4:
	      case CDF_FLOAT:
		   test_value = r4_r8(&temp.r4);
		   break;
	      case CDF_REAL8:
	      case CDF_DOUBLE:
	      case CDF_EPOCH:
		   test_value = temp.r8;
		   break;
	      case CDF_INT4:
		   test_value = (double) temp.i4;
		   break;
	      case CDF_UINT4:
		   test_value = (double) temp.ui4;
		   break;
	      case CDF_INT2:
		   test_value = (double) temp.i2;
		   break;
	      case CDF_UINT2:
		   test_value = (double) temp.ui2;
		   break;
	      case CDF_BYTE:
	      case CDF_INT1:
		   test_value = (double) temp.byte;
		   break;
	      case CDF_UINT1:
		   test_value = (double) temp.ubyte;
	      }
	  }
	  if(rcode < CDF_OK)test_value = 1.7e38;
       }
    else
	test_value = dim_values[i];
    if(test_value >= min && test_value <= max)return(i);
    diff = fabs(test_value - value);
    if(diff < closest_diff)
       {
       closest_diff = diff;
       closest_indice = i;
       }
    }
return(closest_indice);
}
long     CDFWALK_get_index_char(CDF_id, Z, dim_num, var_num, value,
				num_bytes, dim_values, num_values)
CDFid                   CDF_id;
long                    Z;
long                    dim_num;
long                    var_num;
char                    *value;
long                    num_bytes;
char                    dim_values[];
long                    num_values;
{
int                     i;
long                    closest_indice;
long                    most;
long                    num;
long                    indices[CDF_MAX_DIMS];
long                    record_num;
CDFstatus               rcode;
char                    *string;

closest_indice = 0;
most = 0;

string = (char *) malloc ((size_t) (num_bytes+1));
if(string == NULL)return(closest_indice);
if(num_values > MAX_VALUES)
   {
   record_num = 0;
   for (i=0; i < CDF_MAX_DIMS; i++)
     indices[i] = 0;
   }


for(i=0; i<num_values; i++)
    {
    if(num_values > MAX_VALUES)
       {
       if(dim_num > 0)
	  indices[(int)(dim_num-1)]=i;
       else
	  record_num = i;
       rcode = CDFlib (SELECT_, CDF_, CDF_id,
			  Zq(Z,zVAR_,rVAR_), var_num,
			  Zq(Z,zVAR_RECNUMBER_,rVARs_RECNUMBER_),record_num,
			  Zq(Z,zVAR_DIMINDICES_,rVARs_DIMINDICES_),indices,
		   GET_,  Zq(Z,zVAR_DATA_,rVAR_DATA_), string,
		   NULL_);
       if(rcode < CDF_OK)
	  string[0] = '\0';
       else
	  string[(int)num_bytes] = '\0';
       }
    else
       {
       strncpy (string, &dim_values[(int)(i*(num_bytes+1))], (size_t)num_bytes);
       string[(int)num_bytes] = '\0';
       } 
    num = how_many_match(value, string);
    if(num > most)
       {
       closest_indice = i;
       most = num;
       }
    }
free(string);
return(closest_indice);
}
void make_it_upper(upstring,string)
char    *upstring;
char    *string;
{
int     i,len;
len=strlen(string);
for(i=0; i<len; i++)
    {
    upstring[i] = ToUpperChr(string[i]);
    }
upstring[len] = '\0';
}
long     how_many_match(str1, str2)
char            *str1;
char            *str2;
{
char            *up1, *up2;
long            num;
int             i;
up1 = (char *) malloc(strlen(str1) + 1);
up2 = (char *) malloc(strlen(str2) + 1);
make_it_upper(up1, str1);
make_it_upper(up2, str2);
for(i=0, num=0; up1[i] != '\0' && up1[i] == up2[i]; i++)
    num++;
free(up1);
free(up2);
return(num);
}
double          check_epoch(str)
char            str[];
{
static char     default_time[] = " 00:00:00.000";
long            len;
double          scale;
scale = 0.;
len = strlen(str);
if(len == 0)
   return(0.);
else if(len < 11)
	return(-1.0);
else if(len < 24)
	strcat(str, default_time + (int) (len+2-13));
scale = parseEPOCH(str);
return(scale);
}

void NEG_to_POS(CDF_id)
CDFid   CDF_id;
{
CDFstatus rcode;
long convert0;
convert0 = SO.zero == CONVERT ? NEGtoPOSfp0on : NEGtoPOSfp0off; 
rcode = CDFlib (SELECT_, CDF_, CDF_id,
			 CDF_NEGtoPOSfp0_MODE_, convert0, 
		 NULL_);
if(rcode != CDF_OK)rcode = CDF_OK; /* Don't want this to be a killer */
return;
}
