#include <math.h> 
#include <stdio.h>
#include <stdlib.h>
#include "dprints.h"		/* for dprints */
#include "gribfuncs.h"		/* prototypes */

/* REVISION/MODIFICATION HISTORY:
       03/07/94 written by Mugur Georgescu CSC, Monterey CA
       02/01/96 modified by Steve Lowe SAIC, Monterey CA
       06/18/96 modified by Alice T. Nakajima (ATN), SAIC, Monterey CA 
       01/22/98 ATN, MRY SAIC
       04/22/98 ATN change requirement for using extensions.
       06/13/00 ATN add support for TimeRangeIndicator=10
       06/28/00 ATN updated algorithm for TimeRangeIndicator
*
************************************************************************
* A.  FUNCTION  gribgetpds
*       Decode the Product Definition Section (PDS) from the provided 
*       pointer location and store the info in the internal PDS structure.
*
*    INTERFACE:
*       int gribgetpds (curr_ptr, pds, errmsg)
*
*    ARGUMENTS (I=input, O=output, I&O=input and output):
*      (I)  char *curr_ptr;    pointer to first octet of PDS
*      (O)  PDS_INPUT *pds;    empty PDS structure to be filled
*      (O)  char *errmsg;      returned filled if error occurred
* 
*     RETURN CODE:
*     0>  Always,  PDS info stored in Pds structure;
************************************************************************
*/
int gribgetpds ( char *curr_ptr, PDS_INPUT *pds, char *errmsg)
{
char *in = curr_ptr;      /* pointer to the message */
unsigned long skip=0;              /* bits to be skipped */
unsigned long something;  /* value extracted from message */
unsigned long p1,p2;  	  /* working vars */
int sign;                 /* sign + or - */

 DPRINT0 ("Entering gribgetpds()\n");
/*
*
* A.1       FUNCTION gbyte !3-byte PDS length
*/
 gbyte(in,&something,&skip,24); 
 DPRINT0 ("pds->uslength\n");
 pds->uslength = (unsigned short) something;       

/*
*
* A.2       FUNCTION gbyte !parameter table version
*/
 gbyte(in,&something,&skip,8); 
 DPRINT0 ("pds->usParm_tbl\n");
 pds->usParm_tbl = (unsigned short) something;     

/*
*
* A.3       FUNCTION gbyte !center identification
*/
 gbyte(in,&something,&skip,8); 
 DPRINT0 ("pds->usCenter_id\n");
 pds->usCenter_id = (unsigned short) something;    

/*
*
* A.4       FUNCTION gbyte !generating process id
*/
 gbyte(in,&something,&skip,8); 
 DPRINT0 ("pds->usProc_id\n");
 pds->usProc_id = (unsigned short) something;      

/*
*
* A.5       FUNCTION gbyte !grid identification
*/
 gbyte(in,&something,&skip,8); 
 DPRINT0 ("pds->usGrid_id\n");
 pds->usGrid_id = (unsigned short) something;      

/*
*
* A.6       FUNCTION gbyte !flag of GDS, BMS presence
*/
 gbyte(in,&something,&skip,8); 
 DPRINT0 ("pds->usGds_bms_id\n");
 pds->usGds_bms_id = (unsigned short) something;   

/*
*
* A.7       FUNCTION gbyte !parameter indicator and units 
*/
 gbyte(in,&something,&skip,8); 
 DPRINT0 ("pds->usParm_id\n");
 pds->usParm_id = (unsigned short) something;      

/*
*
* A.8       FUNCTION gbyte !level type indicator
*/
 gbyte(in,&something,&skip,8); 
 DPRINT0 ("pds->usLevel_id\n");
 pds->usLevel_id = (unsigned short) something;  

 /* switch on Level_id to determine if level or layer */
/*
*
* A.9       SWITCH (level_id)
*/
 switch(pds->usLevel_id)
    {
    case 101: /* layer between two isobaric surfaces */
    case 104: /* layer between two specified altitudes */
    case 106: /* layer between two specified height levels above ground */
    case 108: /* layer between two sigma levels */
    case 110: /* layer between two hybrid levels */
    case 112: /* layer between two depths below land surface */
    case 114: /* layer between two isentropic levels */
    case 121: /* layer between two isobaric surfaces (high precision) */
    case 128: /* layer between two sigma levels (high precision) */
    case 141: /* layer between two isobaric surfaces (mixed precision) */
/*
*              layer:
*                 FUNCTION gbyte !top of layer
*                 FUNCTION gbyte !bottom of layer
*/
       gbyte(in,&something,&skip,8);
       DPRINT0 ("pds->usHeight1\n");
       pds->usHeight1 = (unsigned short) something;  /* top layer */
       gbyte(in,&something,&skip,8);
       DPRINT0 ("pds->usHeight2\n");
       pds->usHeight2 = (unsigned short) something;  /* bottom layer */
       break;

    default:  /* all others (levels) */
/*
*              default:  !assume a level
*                 FUNCTION gbyte !level value
*                 SET Height2 to ZERO
*/
       gbyte(in,&something,&skip,16);
      DPRINT0 ("pds->usHeight1\n");
       pds->usHeight1 = (unsigned short) something;
       pds->usHeight2 = 0;                
       break;
    }
/*
* A.9       ENDSWITCH
*/

/*
*
* A.10      FUNCTION gbyte !year of Reference Data/Time
*/
 gbyte(in,&something,&skip,8); 
 DPRINT0 ("pds->usYear\n");
 pds->usYear = (unsigned short) something;   

/*
*
* A.11      FUNCTION gbyte !month of Reference Data/Time
*/
 gbyte(in,&something,&skip,8); 
 DPRINT0 ("pds->usMonth\n");
 pds->usMonth = (unsigned short) something;   

/*
*
* A.12      FUNCTION gbyte !day of Reference Data/Time
*/
 gbyte(in,&something,&skip,8); 
 DPRINT0 ("pds->usDay\n");
 pds->usDay = (unsigned short) something;      

/*
*
* A.13      FUNCTION gbyte !hour of Reference Data/Time
*/
 gbyte(in,&something,&skip,8); 
 DPRINT0 ("pds->usHour\n");
 pds->usHour = (unsigned short) something;      

/*
*
* A.14      FUNCTION gbyte !minute of Reference Data/Time
*/
 gbyte(in,&something,&skip,8); 
 DPRINT0 ("pds->usMinute\n");
 pds->usMinute = (unsigned short) something;     

/*
*
* A.15      FUNCTION gbyte !forecast time unit
*/
 gbyte(in,&something,&skip,8); 
 DPRINT0 ("pds->usFcst_unit_id\n");
 pds->usFcst_unit_id = (unsigned short) something;

/*
*
* A.16      FUNCTION gbyte !forecast period 1
*/
 gbyte(in,&something,&skip,8); 
 DPRINT0 ("temp p1\n");
 p1 = (unsigned short) something;         

/*
*
* A.17      FUNCTION gbyte !forecast period 2
*/
 gbyte(in,&something,&skip,8); 
 DPRINT0 ("temp p2\n");
 p2 = (unsigned short) something;          

/*
*
* A.18      FUNCTION gbyte !time range indicator (suppport 0 & 10)
*/
 gbyte(in,&something,&skip,8); 
 DPRINT0 ("pds->usTime_range\n");
 pds->usTime_range = (unsigned short) something;   

 switch (pds->usTime_range)   /* 6/28/00 atn */
 { 
   case 10: /*  P1 occupies octets 19 & 20, product valid at Reftime+P1 */
	    pds->usP1 = ((unsigned long)(0x000000FF & p1) << 8)
			 + (unsigned long)(0x000000FF & p2);
	    pds->usP2 = 0;  /* not used */
	    DPRINT1("usTime_Range= 10> usP1=%d (p2 notused)\n", pds->usP1);
	    break;

   default: /* treat all other time range indicators as TRI=0 */
       /*case 0:    forecast prod valid for REFTIME+P1, or 
	   	Uninitialized analysis prod for RefTime (P1=0), or
		Image prod   for ref time (P1=0) */
	    pds->usP1 = p1; 
	    pds->usP2 = p2;  
	    DPRINT3("usTime_Range= %d> usP1=%d, usP2=%d\n",
	    pds->usTime_range, pds->usP1,pds->usP2);
	    break;
  }
 

/*
*
* A.19      FUNCTION gbyte !#included in average
*/
 gbyte(in,&something,&skip,16); 
 DPRINT0 ("pds->usTime_range_avg\n");
 pds->usTime_range_avg = (unsigned short) something;

/*
*
* A.20      FUNCTION gbyte !#missing from average
*/
 gbyte(in,&something,&skip,8); 
 DPRINT0 ("pds->usTime_range_mis\n");
 pds->usTime_range_mis = (unsigned short) something;

/*
*
* A.21      FUNCTION gbyte !century of Reference Data/Time
*/
 gbyte(in,&something,&skip,8); 
 DPRINT0 ("pds->usCentury\n");
 pds->usCentury = (unsigned short) something;  

/*
*
* A.22      FUNCTION gbyte !originating Sub-Center  (Oct 26)
*/
 gbyte(in,&something,&skip,8); 
 DPRINT0 ("pds->usCenter_sub (Oct 26)\n");
 pds->usCenter_sub = 	(unsigned short) something;

/*
*
* A.23      FUNCTION gbyte !decimal scale factor
*/
 gbyte(in,&something,&skip,16); 
      DPRINT0 ("Sign & pds->sDec_sc_fctr\n");
 sign = (int)(something >> 15) & 1;                /* sign bit*/
 pds->sDec_sc_fctr = (short) (something) & 32767;  /* Decimal sclfctr D */
 if(sign)                                          /* negative Dec. sclfctr*/
    pds->sDec_sc_fctr = - pds->sDec_sc_fctr;       /* multiply by -1 */

/* 
*
* A.24      IF (more than 40 bytes in PDS) THEN
*              INCREMENT #bits to &skip ! skip reserved octets 29-40
*              FUNCTION gbyte           ! Octet-41 Extension Usage flag
*           ELSE
*              SET Octet-41 flag to zero
*           ENDIF
*/
 if (pds->uslength > 40){
    skip += 96;                                  
    gbyte(in,&something,&skip,8);
    pds->usExt_flag = 	(unsigned short) something;
    DPRINT0 ("Extension Flag (Oct 41)\n");
 }
 else pds->usExt_flag = 0;

/*
* 
* A.25      IF (MEL GRIB extensions) 
*           ! Octet-41 equals extension flag and PDS length equals 46
*           THEN
*/
 if  (pds->usExt_flag == (unsigned short)EXTENSION_FLAG && pds->uslength == 46) 
  {
/*
*
* A.25.1       FUNCTION gbyte !seconds of Reference Data/Time
*/
      gbyte(in,&something,&skip,8);
      DPRINT0 ("pds->usSecond\n");
      pds->usSecond = (unsigned short) something;  
/*
*
* A.25.2       FUNCTION gbyte !Tracking ID
*/
      gbyte(in,&something,&skip,16);
      DPRINT0 ("pds->usTrack_num\n");
      pds->usTrack_num = (unsigned short) something;
/*
*
* A.25.3       IF (it's a Sub-Table) THEN
*                  FUNCTION gbyte ! Parameter Sub-table entry
*              ENDIF
*/
      if (pds->usParm_id > 249)
	{
          gbyte(in,&something,&skip,8);
          DPRINT0 ("pds->usParm_sub\n");
          pds->usParm_sub = (unsigned short) something;  
	}
      else skip += 8;
/*
*
* A.25.4       FUNCTION gbyte ! Local table version number
*/
      gbyte(in,&something,&skip,8);
      DPRINT0 ("pds->usSub_tbl\n");
      pds->usSub_tbl = (unsigned short) something;    

/*
* A.25      ENDIF   ! MEL GRIB extensions
*/
  }

/*
* A.26      DEBUG Print
*/
  DPRINT0 ("Exiting gribgetpds(), status=0\n");

/*
* 
* A.27      RETURN 0  !success
*/
return(0);
/*
* END OF FUNCTION
*
*
*/
} 


/*
  REVISION/MODIFICATION HISTORY:
       03/07/94 written by Mugur Georgescu CSC, Monterey CA
       02/01/96 modified by Steve Lowe SAIC, Monterey CA
       06/19/96 modified by Alice Nakajima SAIC, Monterey CA
       10/15/97/ATN init usData_type in Projection struct too
       02/18/98/atn replace projection ids with constants
*
******************************************************************* 
* A.  FUNCTION  gribgetgds 
*       Decode the Grid Description Section (GDS) from the provided 
*       pointer location and store its the in the internal GDS structure;
*
*    INTERFACE:
*       int gribgetgds (curr_ptr, gds, errmsg)
*
*    ARGUMENTS (I=input, O=output, I&O=input and output):
*      (I)  char *curr_ptr;        points to 1st octet of GDS
*      (O)  grid_desc_sec *gds;    internal GDS structure to be filled
*      (O)  char *errmsg;          returned filled if error occurred
*
*    RETURN CODE:
*       0>  success, struct grid_desc_sec filled;
*       1>  unsupported projection number, errmsg filled;
*       2>  section length too short, errmsg filled;
******************************************************************* 
*/

int gribgetgds ( char *curr_ptr, grid_desc_sec *gds, char *errmsg)
{
  const char *func= "gribgetgds";
  char *in = curr_ptr;      /* pointer to the message */
  unsigned long skip;             /* bits to be skipped */
  unsigned long something;  /* value extracted from message */
  int sign;                 /* sign + or - */
  int status;
  int bytecnt = 0;
  // FILE *fp;
  
  DPRINT1 ("Entering %s\n", func);
  /*
   *
   * A.0      INIT status to good, skip to 0
   */
  status=0;  skip=0;
/*
*
* A.1      FUNCTION gbyte  !GDS length 
*          IF (length < 32 bytes) THEN
*             SET error status of 2   !length too short
*             CONTINUE to load as much info as possible into
*             structure 'grid_desc_sec' but will return with error
*          ENDIF
*/
 gbyte(in,&something,&skip,24); DPRINT0 ("gds->head.uslength\n");
 gds->head.uslength = (unsigned short) something;  
 if (gds->head.uslength < 32) {
    sprintf(errmsg,
    "GDS length too short (%ld).  Will attempt to load struct grid_desc_sec\n",
    gds->head.uslength);
    status = 2;		/* corrupt length */
   }
  bytecnt += 3;

/* 
*
* A.2      FUNCTION gbyte  !parm_nv
*/
 gbyte(in,&something,&skip,8); DPRINT0 ("gds->head.usNum_v\n");
 gds->head.usNum_v =(short) something;             
 bytecnt ++;

/* 
*
* A.3      FUNCTION gbyte  !parm_pv_pl
*/
 gbyte(in,&something,&skip,8); DPRINT0 ("gds->head.usPl_Pv\n");
 gds->head.usPl_Pv = (short) something;            
 bytecnt ++;

/* 
*
* A.4      FUNCTION gbyte  !data representation type
*/
 gbyte(in,&something,&skip,8); DPRINT0 ("gds->head.usData_type\n");
 gds->head.usData_type = (short) something;        
 bytecnt ++;

/* Remainder of GDS is projection dependent */
/*
*
* A.5      SWITCH (data type)
*/

 switch(gds->head.usData_type)
  {
   case LATLON_PRJ:    	/* Lat/Lon Grid */
   case GAUSS_PRJ:    	/* Gaussian Latitude/Longitude grid */
   case ROT_LATLON_PRJ:   	/* Rotated Lat/Lon */
   case ROT_GAUSS_PRJ:   	/* Rotated Gaussian */
   case STR_LATLON_PRJ:   	/* Stretched Lat/Lon */
   case STR_GAUSS_PRJ :   	/* Stretched Gaussian */
   case STR_ROT_LATLON_PRJ :  /* Stretched and Rotated Lat/Lon */
   case STR_ROT_GAUSS_PRJ :   /* Stretched and Rotated Gaussian */
/*
*           case latlon: 
*           case gaussian_latlon:
*           case rotated gaussian:
*           case stretched latlon:
*           case stretched gaussian:
*           case stretched & rotated latlon:
*           case stretched & rotated gaussian:
*                 Mark the Projection type 
*                 FUNCTION gbyte !get Number of Columns
*/
       gds->llg.usData_type = gds->head.usData_type;

       gbyte(in, &something, &skip, 16); 
       DPRINT0 ("gds->llg.usNi\n");
       gds->llg.usNi = (int) something;                   /* get Ni */
       bytecnt += 2;

/*
*                 FUNCTION gbyte !get Number of Rows
*/
       gbyte(in, &something, &skip, 16);
       DPRINT0 ("gds->llg.usNj\n");
       gds->llg.usNj = (int) something;                   /* get Nj */
       bytecnt += 2;

/*
*                 FUNCTION gbyte !get Latitude of First point
*/
       gbyte(in,&something,&skip,24);
       DPRINT0 ("Sign & gds->llg.lLat1 \n");
       sign = (int)(something >> 23) & 1;                 /* get sign */
       gds->llg.lLat1 = (long) (something) & 8388607;     /* get La1 */
       if(sign)                                           /* negative value */
          gds->llg.lLat1 = - gds->llg.lLat1;              /* multiply by -1 */
       bytecnt += 3;

/*
*                 FUNCTION gbyte !get Longitude of First point
*/
       gbyte(in,&something,&skip,24);
       DPRINT0 ("Sign & gds->llg.lLon1 \n");
       sign = (int)(something >> 23) & 1;                 /* get sign */
       gds->llg.lLon1 = (long) (something) & 8388607;     /* get Lo1 */
       if(sign)                                           /* negative value */
           gds->llg.lLon1 = - gds->llg.lLon1;             /* multiply by -1 */
       bytecnt += 3;

/*
*                 FUNCTION gbyte !get resolution & comp flags
*/
       gbyte(in,&something,&skip,8);
       DPRINT0 ("gds->llg.usRes_flag\n");
       gds->llg.usRes_flag = (short) something;           /* get resolution & comp flags */
       bytecnt++;

/*
*                 FUNCTION gbyte !get Latitude of Last point
*/
       gbyte(in,&something,&skip,24);
       DPRINT0 ("Sign & gds->llg.lLat2 \n");
       sign = (int)(something >> 23) & 1;                 /* get sign */
       gds->llg.lLat2 = (long) (something) & 8388607;     /* get La2 */
       if(sign)                                           /* negative value */
          gds->llg.lLat2 = - gds->llg.lLat2;              /* multiply by -1 */
       bytecnt += 3;

/*
*                 FUNCTION gbyte !get Longitude of Last point
*/
       gbyte(in,&something,&skip,24);
       DPRINT0 ("Sign & gds->llg.lLon2 \n");
       sign = (int)(something >> 23) & 1;                 /* get sign */
       gds->llg.lLon2 = (long) (something) & 8388607;     /* get Lo2 */
       if(sign)                                           /* negative value */
          gds->llg.lLon2 = - gds->llg.lLon2;              /* multiply by -1 */
       bytecnt += 3;

/*
*                 FUNCTION gbyte !get Longitudinal Increment
*/
       gbyte(in,&something,&skip,16);
       DPRINT0 ("gds->llg.iDi\n");
       gds->llg.iDi = (int) something;			  /* get Di */
       bytecnt += 2;

/*
*                 FUNCTION gbyte !get Latitudinal Increment
*/
       gbyte(in,&something,&skip,16);
       DPRINT0 ("gds->llg.iDj\n");
       gds->llg.iDj = (int) something;			  /* get Dj */
       bytecnt += 2;

/*
*                 FUNCTION gbyte !get scanning mode
*/
       gbyte(in,&something,&skip,8);
       DPRINT0 ("gds->llg.usScan_mode\n");
       gds->llg.usScan_mode = (short) something;    /* get scaning mode flag */
       bytecnt++;

/*
*                 FUNCTION gbyte !get reserved octets 29-32
*/
       gbyte(in,&something,&skip,32);
       DPRINT0 ("gds->llg.usZero\n");
       gds->llg.usZero = (long) something; /* get reserved octets 29 - 32 */
       bytecnt += 4;
       if (gds->head.uslength == 32) goto bail_out;

/*
*                 FUNCTION gbyte !get south pole lat
*/
       gbyte(in,&something,&skip,24);
       DPRINT0 ("Sign & gds->llg.lLat_southpole \n");
       sign = (int)(something >> 23) & 1;                      /* get sign */
       gds->llg.lLat_southpole = (long)(something) & 8388607; /* southpole lat*/
       if(sign)                                            /* negative value */
          gds->llg.lLat_southpole = - gds->llg.lLat_southpole; /* multiply -1 */
       bytecnt += 3;
       if (gds->head.uslength <= 35) goto bail_out;

/*
*                 FUNCTION gbyte !get south pole lon
*/
       gbyte(in,&something,&skip,24);
       DPRINT0 ("Sign & gds->llg.lLon_southpole \n");
       sign = (int)(something >> 23) & 1;                      /* get sign */
       gds->llg.lLon_southpole =(long)(something) & 8388607; /* southpole lon*/
       if(sign)                 /* negative value , multiply by -1 */
          gds->llg.lLon_southpole = - gds->llg.lLon_southpole; 
       bytecnt += 3;
       if (gds->head.uslength <= 38) goto bail_out;

/*
*                 FUNCTION gbyte !angle of rotation
*/
       gbyte(in,&something,&skip,32);
       DPRINT0 ("gds->llg.lRotate\n");
       gds->llg.lRotate = (long) something;          /* get angle of rotation */
       bytecnt += 3;
       if (gds->head.uslength <= 42) goto bail_out;

/*
*                 FUNCTION gbyte !get lat pole stretching
*/
       gbyte(in,&something,&skip,24);
       DPRINT0 ("Sign & gds->llg.lPole_lat \n");
       sign = (int)(something >> 23) & 1;                 /* get sign */
       gds->llg.lPole_lat = (long)something & 8388607; /* lat pole stretching */
       if(sign)                                           /* negative value */
          gds->llg.lPole_lat = - gds->llg.lPole_lat;      /* multiply by -1 */
       bytecnt += 3;
       if (gds->head.uslength <= 45) goto bail_out;

/*
*                 FUNCTION gbyte !get lon pole stretching
*/
       gbyte(in,&something,&skip,24);
       DPRINT0 ("Sign & gds->llg.lPole_lon \n");
       sign = (int)(something >> 23) & 1;                 /* get sign */
       gds->llg.lPole_lon= (long)(something) & 8388607; /* lon pole stretching*/
       if(sign)                                           /* negative value */
          gds->llg.lPole_lon = - gds->llg.lPole_lon;      /* multiply by -1 */
       bytecnt += 3;
       if (gds->head.uslength <= 48) goto bail_out;

       gbyte(in,&something,&skip,32);
       DPRINT0 ("gds->llg.lStretch\n");
       gds->llg.lStretch = (long) something;
       bytecnt += 3;
       break;

    case MERC_PRJ:    /* Mercator Projection Grid               */
/*
*           case Mercator Projection Grid:
*                 Mark the Projection type 
*                 FUNCTION gbyte !get Number of Columns
*/
       gds->merc.usData_type = gds->head.usData_type;

       gbyte(in,&something,&skip,16); 
       DPRINT0 ("gds->merc.cols\n");
       gds->merc.cols = (int) something;                  /* get Ni */
       bytecnt += 2;

/*
*                 FUNCTION gbyte !get Number of Rows
*/
       gbyte(in,&something,&skip,16); 
       DPRINT0 ("gds->merc.rows\n");
       gds->merc.rows = (int) something;                  /* get Nj */
       bytecnt += 2;

/*
*                 FUNCTION gbyte !get Latitude of First Point
*/
       gbyte(in,&something,&skip,24); 
       DPRINT0 ("Sign & gds->merc.first_lat\n");
       sign = (int)(something >> 23) & 1;                   /* get sign */
       gds->merc.first_lat = (long) (something) & 8388607;  /* get La1 */
       if(sign)                                             /* negative value */
          gds->merc.first_lat = - gds->merc.first_lat;      /* multiply by -1 */
       bytecnt += 3;

/*
*                 FUNCTION gbyte !get Longitude of First Point
*/
       gbyte(in,&something,&skip,24); 
       DPRINT0 ("Sign & gds->merc.first_lon\n");
       sign = (int)(something >> 23) & 1;                   /* get sign */
       gds->merc.first_lon = (long) (something) & 8388607;  /* get Lo1 */
       if(sign)                                             /* negative value */
          gds->merc.first_lon = - gds->merc.first_lon;      /* multiply by -1 */
       bytecnt += 3;

/*
*                 FUNCTION gbyte !get resolution & comp flag
*/
       gbyte(in,&something,&skip,8); 
       DPRINT0 ("gds->merc.usRes_flag\n");
       gds->merc.usRes_flag = (short) something;  /* resolution & comp flags */
       bytecnt++;

/*
*                 FUNCTION gbyte !get Latitude of Last point
*/
       gbyte(in,&something,&skip,24); 
       DPRINT0 ("Sign & gds->merc.La2\n");
       sign = (int)(something >> 23) & 1;                   /* get sign */
       gds->merc.La2 = (long) (something) & 8388607;        /* get La2 */
       if(sign)                                             /* negative value */
          gds->merc.La2 = - gds->merc.La2;                  /* multiply by -1 */
       bytecnt += 3;

/*
*                 FUNCTION gbyte !get Longitude of Last point
*/
       gbyte(in,&something,&skip,24); 
       DPRINT0 ("Sign & gds->merc.Lo2\n");
       sign = (int)(something >> 23) & 1;                   /* get sign */
       gds->merc.Lo2 = (long) (something) & 8388607;        /* get Lo2 */
       if(sign)                                             /* negative value */
          gds->merc.Lo2 = - gds->merc.Lo2;                  /* multiply by -1 */
       bytecnt += 3;

/*
*                 FUNCTION gbyte !get Latitude where projection intersects Earth
*/
       gbyte(in,&something,&skip,24); 
       DPRINT0 ("Sign & gds->merc.latin\n");
       sign = (int)(something >> 23) & 1;                   /* get sign */
       gds->merc.latin = (long) (something) & 8388607;      /* get latin */
       if(sign)                                             /* negative value */
          gds->merc.latin = - gds->merc.latin;              /* multiply by -1 */
       bytecnt += 3;

       skip += 8;      /* skip over the reserved octet */
       bytecnt++;

/*
*                 FUNCTION gbyte !get scanning mode flag
*/
       gbyte(in,&something,&skip,8);
       DPRINT0 ("gds->merc.usScan_mode\n");
       gds->merc.usScan_mode = (short) something;            /* get scaning mode flag */
       bytecnt++;

/*
*                 FUNCTION gbyte !get Longitudinal Increment
*/
       gbyte(in,&something,&skip,24); 
       DPRINT0 ("gds->merc.lon_inc\n");
       gds->merc.lon_inc = (float) something;               /* get Di */
       bytecnt += 3;

/*
*                 FUNCTION gbyte !get Latitudinal Increment
*/
       gbyte(in,&something,&skip,24); 
       DPRINT0 ("gds->merc.lat_inc\n");
       gds->merc.lat_inc = (float) something;               /* get Dj */
       bytecnt += 3;
       if (gds->head.uslength <= 34) goto bail_out;

       gbyte(in,&something,&skip,64);
       DPRINT0 ("gds->merc.usZero\n");
       gds->merc.usZero = (long) something;
       bytecnt += 8;
       break;

    case POLAR_PRJ:    /* Polar Stereographic Projection Grid    */
/*
*           case Polar Stereographic Projection Grid:
*                 Mark the Projection type 
*                 FUNCTION gbyte !get Number of Columns
*/
       gds->pol.usData_type = gds->head.usData_type;

       gbyte(in,&something,&skip,16); 
       DPRINT0 ("gds->pol.usNx\n");
       gds->pol.usNx = (short) something;                   /* get Nx */
       bytecnt += 2;

/*
*                 FUNCTION gbyte !get Number of Rows
*/
       gbyte(in,&something,&skip,16); 
       DPRINT0 ("gds->pol.usNy\n");
       gds->pol.usNy = (short) something;                   /* get Ny */
       bytecnt += 2;

/*
*                 FUNCTION gbyte !get Latitude of First point
*/
       gbyte(in,&something,&skip,24); 
       DPRINT0 ("Sign & gds->pol.lLat1\n");
       sign = (int)(something >> 23) & 1;                   /* get sign */
       gds->pol.lLat1 = (long)  (something) & 8388607;      /* get La1 */
       if(sign)                                             /* negative value */
          gds->pol.lLat1 = - gds->pol.lLat1;                /* multiply by -1 */
       bytecnt += 3;

/*
*                 FUNCTION gbyte !get Longitude of First point
*/
       gbyte(in,&something,&skip,24); 
       DPRINT0 ("Sign & gds->pol.lLon1\n");
       sign = (int)(something >> 23) & 1;                   /* get sign */
       gds->pol.lLon1 = (long) (something) & 8388607;       /* get Lo1 */
       if(sign)                                             /* negative value */
          gds->pol.lLon1 = - gds->pol.lLon1;                /* multiply by -1 */
       bytecnt += 3;

/*
*                 FUNCTION gbyte !get resolution & comp flag
*/
       gbyte(in,&something,&skip,8); 
       DPRINT0 ("gds->pol.usRes_flag\n");
       gds->pol.usRes_flag = (short) something;             /* get resolution & comp flags */
       bytecnt++;

/*
*                 FUNCTION gbyte !get Orientation Longitude
*/
       gbyte(in,&something,&skip,24); 
       DPRINT0 ("Sign & gds->pol.lLon_orient\n");
       sign = (int)(something >> 23) & 1;                    /* get sign */
       gds->pol.lLon_orient = (long) (something) & 8388607;  /* Orientation */
       if(sign)      /* negative value , multiply by -1 */
          gds->pol.lLon_orient = - gds->pol.lLon_orient;
       bytecnt += 3;

/*
*                 FUNCTION gbyte !get Increment along a Row
*/
       gbyte(in,&something,&skip,24);
       DPRINT0 ("gds->pol.ulDx\n");
       gds->pol.ulDx = something;                   /* get Dx */
       bytecnt += 3;

/*
*                 FUNCTION gbyte !get Increment along a Column
*/
       gbyte(in,&something,&skip,24);
       DPRINT0 ("gds->pol.ulDy\n");
       gds->pol.ulDy = something;                   /* get Dy */
       bytecnt += 3;

/*
*                 FUNCTION gbyte !get projection center flag
*/
       gbyte(in,&something,&skip,8);
       DPRINT0 ("gds->pol.usProj_flag\n");
       gds->pol.usProj_flag = (short) something;  /* Projection center flag */
       bytecnt++;

/*
*                 FUNCTION gbyte !get scanning mode
*/
       gbyte(in,&something,&skip,8);
       DPRINT0 ("gds->pol.usScan_mode\n");
       gds->pol.usScan_mode = (short) something;     /* get scaning mode flag */
       bytecnt++;

/*
*                 FUNCTION gbyte !reserved zero
*/
       gbyte(in,&something,&skip,32);
       DPRINT0 ("gds->pol.usZero\n");
       gds->pol.usZero = (int) something;            /* get Reserved zero */
       bytecnt += 4;
       break;

   case LAMB_PRJ:  		/* Lambert Conformal */
   case ALBERS_PRJ:  		/* Albers equal-area */
   case OBLIQ_LAMB_PRJ: 	/* Oblique Lambert Conformal */
/*
*           case Lambert conformal, secant or tangent, conical or bipolar:
*           case Albers equal-area, secant or tangent, conical or bipolar:
*           case Oblique Lambert conformal:
*                 Mark the Projection type 
*                 FUNCTION gbyte !get Number of Columns
*/
       gds->lam.usData_type = gds->head.usData_type;

       gbyte(in,&something,&skip,16); 
       DPRINT0 ("gds->lam.iNx\n");
       gds->lam.iNx = (int) something;                      /* get Nx */
       bytecnt += 2;

/*
*                 FUNCTION gbyte !get Number of Rows
*/
       gbyte(in,&something,&skip,16); 
       DPRINT0 ("gds->lam.iNy\n");
       gds->lam.iNy = (int) something;                      /* get Ny */
       bytecnt += 2;

/*
*                 FUNCTION gbyte !get Latitude of First Point
*/
       gbyte(in,&something,&skip,24); 
       DPRINT0 ("Sign & gds->lam.lLat1\n");
       sign = (int)(something >> 23) & 1;                   /* get sign */
       gds->lam.lLat1 = (long)  (something) & 8388607;      /* get La1 */
       if(sign)                                             /* negative value */
          gds->lam.lLat1 = - gds->lam.lLat1;                /* multiply by -1 */
       bytecnt += 3;

/*
*                 FUNCTION gbyte !get Longitude of First Point
*/
       gbyte(in,&something,&skip,24); 
       DPRINT0 ("Sign & gds->lam.lLon1)\n");
       sign = (int)(something >> 23) & 1;                   /* get sign */
       gds->lam.lLon1 = (long) (something) & 8388607;       /* get Lo1 */
       if(sign)                                             /* negative value */
          gds->lam.lLon1 = - gds->lam.lLon1;                /* multiply by -1 */
       bytecnt += 3;

/*
*                 FUNCTION gbyte !get resolution & comp flag
*/
       gbyte(in,&something,&skip,8); 
       DPRINT0 ("gds->lam.usRes_flag\n");
       gds->lam.usRes_flag = (short) something;  /* resolution & comp flags */
       bytecnt++;

/*
*                 FUNCTION gbyte !get Orientation Longitude
*/
       gbyte(in,&something,&skip,24); 
       DPRINT0 ("Sign & gds->lam.lLon_orient)\n");
       sign = (int)(something >> 23) & 1;                    /* get sign */
       gds->lam.lLon_orient = (long) (something) & 8388607;  /* Orientation */
       if(sign)              /* negative value , multiply by -1 */
          gds->lam.lLon_orient = - gds->lam.lLon_orient;     
       bytecnt += 3;

/*
*                 FUNCTION gbyte !get Increment along a Row
*/
       gbyte(in,&something,&skip,24); 
       DPRINT0 ("gds->lam.ulDx\n");
       gds->lam.ulDx = something;                    /* get Dx */
       bytecnt += 3;

/*
*                 FUNCTION gbyte !get Increment along a Column
*/
       gbyte(in,&something,&skip,24); 
       DPRINT0 ("gds->lam.ulDy\n");
       gds->lam.ulDy =  something;                    /* get Dy */
       bytecnt += 3;

/*
*                 FUNCTION gbyte !get Projection Center
*/
       gbyte(in,&something,&skip,8); 
       DPRINT0 ("gds->lam.usProj_flag\n");
       gds->lam.usProj_flag= (short) something;  /* Projection center flag */
       bytecnt++;

/*
*                 FUNCTION gbyte !get scanning mode flag
*/
       gbyte(in,&something,&skip,8); 
       DPRINT0 ("gds->usScan_mode\n");
       gds->lam.usScan_mode = (short) something;    /* get scaning mode flag */
       bytecnt++;

/*
*                 FUNCTION gbyte !get First lat from pole that intersects Earth
*/
       gbyte(in,&something,&skip,24); 
       DPRINT0 ("gds->lLat_cut1\n");
       gds->lam.lLat_cut1 = (long) something;                /* get latin_1 */
       bytecnt += 3;

/*
*                 FUNCTION gbyte !get Second lat from pole that intersects Earth
*/
       gbyte(in,&something,&skip,24); 
       DPRINT0 ("gds->lLat_cut2\n");
       gds->lam.lLat_cut2 = (long) something;                /* get latin_2 */
       bytecnt += 3;
       if (gds->head.uslength <= 34) goto bail_out;

/*
*                 FUNCTION gbyte !get lat of south pole
*/
       gbyte(in,&something,&skip,24);
       DPRINT0 ("Sign & gds->lLat_southpole\n");
       sign = (int)(something >> 23) & 1;                        /* get sign */
       gds->lam.lLat_southpole = (long) (something) & 8388607;   /* lat S.pole*/
       if(sign)      /* negative value , multiply by -1 */ 
           gds->lam.lLat_southpole = - gds->lam.lLat_southpole;
       bytecnt += 3;
       if (gds->head.uslength <= 37) goto bail_out;

/*
*                 FUNCTION gbyte !get lon of South pole
*/
       gbyte(in,&something,&skip,24); 
       DPRINT0 ("Sign & gds->lLon_southpole\n");
       sign = (int)(something >> 23) & 1;                        /* get sign */
       gds->lam.lLon_southpole = (long) (something) & 8388607;/* lon S.pole */
       if(sign)     /* negative value, multiply by -1 */ 
           gds->lam.lLon_southpole = - gds->lam.lLon_southpole;
       bytecnt += 3;
       if (gds->head.uslength <= 40) goto bail_out;

/*
*                 FUNCTION gbyte !get Reserved zero
*/
       gbyte(in,&something,&skip,16); 
       DPRINT0 ("gds->lam.usZero\n");
       gds->lam.usZero = (int) something;                    /* Reserved zero */
       bytecnt += 2;
       break;

    default :             /* other cases not implemented in this version */
/*
*             default:   ! unsupported data types
*                 SET Status to bad
*/
       DPRINT2 ("%s:  unknown datatype=%d\n",func, gds->head.usData_type);
       sprintf(errmsg,"%s:  unknown datatype=%d\n",func, gds->head.usData_type);
       status=1;         /* set status to failure */
       break;
/*
*
* A.5      ENDSWITCH
*/
  }  /* end switch on data type */

/*
*
* A.6      DEBUG Print
*
* A.7      RETURN (status)
*/
bail_out:
  DPRINT2 ("Exiting %s, stat=%d\n", func,status);
  return(status);
/*
*  END OF FUNCTION 
*
*/
}  


/*
*
************************************************************************
* A.  FUNCTION:   gribgetbms
*       decode the Bitmap Section from the provided pointer location
*       and store its info in the internal BMS structure.
*       Pre-defined Bitmap case is not supported.
*               
*    INTERFACE:
*       int   gribgetbms ( curr_ptr, bms, gds_flag, ulGrid_size, errmsg)
*
*    ARGUMENTS (I=input, O=output, I&O=input and output):
*      (I)   char *curr_ptr;
*            pointer to location where Bitmap Section to decode is expected;
*      (O)   BMS_INPUT *bms;
*            pointer to empty BMS structure; will hold decoded BMS info;
*      (I)   int gds_flag;      
*            flag set if GDS is present
*      (I)   unsigned long ulGrid_size;  
*            size of grid as in Binary Data Section struct
*      (O)   char *errmsg
*            returned filled if error occurred;
* 
*     RETURN CODE:
*     0>  BMS info stored in BMS structure if not using pre-defined bitmap;
*     1>  error, corrupted bms; msg in errmsg;
************************************************************************
*/

int   gribgetbms ( char *curr_ptr, BMS_INPUT *bms, int gds_flag,
		unsigned long ulGrid_size, char *errmsg)
{
  const char *func= "gribgetbms";
  char  *pp;
  int totbits,val, bitpos,stopbit;  /* tmp working vars */
  unsigned long SectLength;       /* message and section size */
  unsigned long ulvar;		    /* tmp var */
  unsigned long skip=0;

/*
*
* A.0      INIT Status to no error
*/
int   status=0;

     DPRINT0 ("Entering gribgetbms():\n");
/* 
*
* A.1      FUNCTION gbyte   !get bitmap length
*/
    skip=0;
    gbyte(curr_ptr,(unsigned long *)&SectLength,&skip,24); 
    DPRINT0 ("SectLength\n");
    bms->uslength= (unsigned short) SectLength;

/* 
*
* A.2      FUNCTION gbyte   !get number of unused bits
*/
    gbyte(curr_ptr,&ulvar,&skip,8); 
    DPRINT0 ("bms->usUnused_bits\n");
    bms->usUnused_bits= (unsigned short) ulvar;

/* 
*
* A.3      FUNCTION gbyte   !get bitmap id (non-zero for a pre-defined bitmap)
*/
    gbyte(curr_ptr,&ulvar,&skip,16); 
    DPRINT0 ("bms->usBMS_id\n");
    bms->usBMS_id= (unsigned short) ulvar;

/*
*
* A.4      IF (Bitmap follows)   !not a predefined bitmap
*/
    if ( bms->uslength > 6)     /* Bitmap follows */
       {

/* 
* A.4.1       CALCULATE Num of bits in bitmap
*/
         /* = (BMS length)*8 bits - 48 header bits - # of unsused bits */
         totbits=SectLength*8 - 48 - bms->usUnused_bits;

/*
* A.4.2       IF (GDS is present AND 
*                      #bits differs from Grid Size)        !Corrupted BMS
*                 RETURN 1
*             ENDIF
*/
          if ( gds_flag && (totbits != (int)ulGrid_size)) {
		DPRINT3( "%s: corrupted BMS, gds_flag set but "\
		"totbits %d != ulgrid_sz %d\n" 
		, func, totbits, ulGrid_size);

		sprintf(errmsg, "%s: corrupted BMS, gds_flag set but "\
		"totbits %d != ulgrid_sz %d\n" , func, totbits, ulGrid_size);
		status=  (1); /* Corrupted BMS */
	 	goto BYE;
		}

/*
* A.4.3       ASSIGN bitmap pointer to 6th byte of BMS
*/
          bms->bit_map =  curr_ptr + 6;
          pp= bms->bit_map; 
          bms->ulbits_set= 0; 
/* 
*
* A.4.4       !SUM up total number of bits set
*             FOR (Each 8-bit block of Total Bits Present in BMS)
*/
          for ( ; totbits > 0 ; totbits-=8) 
          {
/*
* A.4.4.1       IF (any of the 8 bits are set) 
*/
             if ((val=(int)*pp++) != 0) 
               {

/*
* A.4.4.1.1        IF (not within 8 bits of end of bitmap)
*                      SET stopbit to 0
*                  ELSE
*                      SET stopbit to end of bitmap
*                  ENDIF
*/
                 if (totbits > 8) stopbit=0;   /* check all 8 bits */
                 else stopbit= 7-totbits+1;    /* stop at end of bitmap */

/*
* A.4.4.1.2        SUM up number of bits set in this BMS byte
*/
                 for (bitpos= 7; bitpos >= stopbit; bitpos--)
                    if (val >> bitpos & 0x0001) bms->ulbits_set += 1;
/*
* A.4.4.1       ENDIF  ! any of 8 exists
*/
               }
/*
* A.4.4     ENDFOR   !each 8-bit loop
*/
           }
/*
* A.4      ENDIF	!Bitmap follows
*/
	}  

/*  else {
        / * Predefined Bitmap - not supported!! Could add function here 
	    to load a bitmap from local storage * /
         bms->uslength=6;	
         bms->bit_map= Load_predefined_bms (bms->usBMS_id);
       }
*/


BYE:
/*
*
* A.5     DEBUG Print
*
* A.6     RETURN Status 
*/
    DPRINT2 ("Exiting %s, Status=%d;\n", func, status);
    return (status);
/*
* END OF FUNCTION
*/ 
}


/*
  REVISION/MODIFICATION HISTORY:
       03/07/94 written by Mugur Georgescu CSC, Monterey CA
       02/01/96 modified by Steve Lowe SAIC, Monterey CA
       04/17/96 modified by Alice Nakajima SAIC, Monterey CA
       06/19/96 add hdrprint;/nakajima
* 
* ********************************************************************
* A.  FUNCTION:  gribgetbds 
*       decodes the Binary Data Section of the GRIB message 
*       and filling grib_data float array.
*
*    INTERFACE:
*       int gribgetbds (curr_ptr, deci_scale, bms, ppgrib_data, bds_head, 
*                      errmsg)
*
*    ARGUMENTS (I=input, O=output, I&O=input and output):
*      (I)  char *curr_ptr;
*           points to first Octet of the BDS to be decoded;
*      (I)  short  deci_scale;
*           decimal scaling factor to be applied to data;
*      (I)  BMS_INPUT *bms;
*           points to the decoded internal Bit Map Section Struct 
*      (O)  float **ppgrib_data;
*           double pointer to array of float, null upon entry;
*           upon successful exit, holds the unpacked and restored float data
*           in a newly malloced array;
*      (O)  BDS_HEAD_INPUT *bds_head; 
*           points to Binary Data Sect hdr struct, empty upon entry;
*           to be filled with decoded BDS info;
*      (O)  char  *errmsg;
*           Only returned filled when error occurred;
*
*      RETURN CODE:
*        0>   no errors
*        1>   unrecognized packing algorithm
*        2>   number of points does not match bitmap
*        3>   number of points does not match grid size in GDS
*        4>   malloc error
* ********************************************************************
*/

int gribgetbds ( char *curr_ptr, short  deci_scale, BMS_INPUT *bms,
        float **ppgrib_data, BDS_HEAD_INPUT *bds_head, char  *errmsg)
{
  const char *func="gribgetbds";
  char *in = curr_ptr;      /* pointer to beginning of BDS */
  long length;              /* size of the Binary Data Section */
  long scale;               /* scaling factor */
float ref_val;            /* reference value (minimum value) */
unsigned long something;  /* generic value from message */
long data_width;          /* number of bits that data occupies */
int halfBYTE4;            /* the first 4 bits in 4-th byte */
int status=0;
int sign;                 /* sign + or - */
float dscale;             /* 10 to the decimal scaling power */
float bscale;             /* 2 to the binary scaling power   */
unsigned long skip=0;              /* number of bits to be skipped */
long c_ristic;            /* characteristic for float representation */
long mantissa;            /* mantissa for float representation */
long numpts;              /* number of bits left at end of bitstream */
unsigned long data_pts;   /* number of data points in bitstream */
unsigned long num_calc;	  /* temp work var */
float *grib_data=0;       /* local work array for grid data */
float fdata=0;            /* data value stored in reference */
int	i;         /* array counter */


  DPRINT1 ("Entering %s()\n", func);
/*
*
* A.1       FUNCTION gbyte !get bds length
*/
  gbyte(in,(unsigned long *) &length,&skip,24);
  DPRINT0 ("bds_head->length\n");
  bds_head->length = (unsigned long) length;

/*
*
* A.2       FUNCTION gbyte !get BDS flag 
*/
  gbyte(in, (unsigned long *) &halfBYTE4, &skip, 4);
  DPRINT0 ("bds_head->usBDS_flag\n");
  bds_head->usBDS_flag = (short) halfBYTE4;  /* get BDS Flag (Table 11) */

/*
*
* A.3       IF (unsupported packing algorithm)  THEN
*               RETURN 1
*           ENDIF
*/
  /* need to check on packing algorithm */
  if (halfBYTE4)  /* unrecognized packing algorithm */
    {
     DPRINT1 ("%s:  error, unrecognized packing algorithm\n", func);
     sprintf(errmsg, "%s:  unrecognized packing algorithm\n", func);
     status= (1);
     goto BYE;
    }

/*
*
* A.4       FUNCTION gbyte !get number of unused bits
*/
  gbyte(in,(unsigned long *) &numpts,&skip,4); /* get #bits at end of BDS */
  DPRINT0 ("numpts\n");

/*
*
* A.5       FUNCTION gbyte !get Binary Scale Factor
*/
  gbyte(in,&something,&skip,16);
  DPRINT0 ("Sign & bds_head->Bin_sc_fctr\n");
  sign = (int)(something >> 15) & 1;  /* get sign for scale */
  scale = (int)(something) & 32767;   /* get scale */
  if(sign)                            /* scale negative */
     scale = -scale;                  /* multiply scale by -1 */
  bds_head->Bin_sc_fctr = (int) scale;  /* get binary scale factor */
  DPRINT1 ("Binary Scale Factor = %d\n", scale);

/*
*
* A.6       CALCULATE Reference value from IBM representation
*             !FUNCTION gbyte !get the sign of reference
*             !FUNCTION gbyte !get charateristic
*             !FUNCTION gbyte !get the mantissa
*/
  gbyte(in,&something,&skip,8);
  DPRINT0 ("Sign & Reference)\n");
  sign = (int)(something >> 7) & 1; /* get the sign for reference value */

  skip -= 7;
  gbyte(in,(unsigned long *)&c_ristic,&skip,7); /*characteristic for the float*/
  DPRINT0 ("c_ristic\n");

  gbyte(in,(unsigned long*)&mantissa,&skip,24); /*mantissa for the float */
  DPRINT0 ("mantissa\n");
  c_ristic -= 64;                   /* subtract 64 from characteristic */
  ref_val = (float) mantissa * (float)(pow(16.0,(double)c_ristic)) * 
	    (pow(2.0,-24.0));
  if(sign)                          /* negative reference value */
     ref_val = -ref_val;            /* multiply ref_val by -1 */
  bds_head->fReference = (float)ref_val;
  DPRINT1 ("Reference = %f\n", ref_val);

/*
*
* A.7       FUNCTION gbyte !get data width
*/
  gbyte(in, (unsigned long*) &data_width,&skip,8);       /* get data width */
  DPRINT0 ("bds_head->usBit_pack_num\n");
  bds_head->usBit_pack_num = (short)data_width;

/*
*
* A.8       SET Binary and Decimal Scale Factors
*/
  /* set binary scale */
  bscale = (float)pow (2.0,(double) scale);

  /* set decimal scale */
  dscale = (float)pow (10.0, (double) deci_scale);

  DPRINT2 ("Scaled-up BSF= (2**%d) = %f\n", scale, bscale);
  DPRINT2 ("Scaled-up DSF= (10**%d) = %f\n", deci_scale,dscale);

/*
*
* A.9       IF (data_width is zero) THEN
*               ! grid contains a constant value
*               IF expected grid size is invalid THEN
*                  FORCE grid size of 1
*               ENDIF
*               ALLOCATE array for grid of expected grid size
*               FILL grid with the constant value
*               RETURN 0 !success
*           ENDIF
*/
  if (!data_width)   /* grid contains constant value, success, all done */
  {
/* Used to send back array of 1 element:
#     bds_head->ulGrid_size = 1;
#     fdata = (float) (ref_val / dscale);
#     *ppgrib_data = (float *) malloc(sizeof(float));
#     **ppgrib_data = fdata;
*/

     fdata = (float) (ref_val / dscale);

     if (bds_head->ulGrid_size <= 0) {
	fprintf(stdout,
	"WARNING:  gribgetbds detects bad ulGrid_size (%ld); "\
	"Set to 1 to hold constant value %lf\n", bds_head->ulGrid_size, fdata);
	bds_head->ulGrid_size = 1;
	}

     grib_data =(float *) malloc(bds_head->ulGrid_size * sizeof(float));
     if (!grib_data) {
	sprintf(errmsg,
	"%s: failed to create array[%d] for grid to hold Constant data", 
	func, bds_head->ulGrid_size);
	goto BYE;
	}

     *ppgrib_data = grib_data;		/* store address */
     for (i=0; i < (int)bds_head->ulGrid_size ; ) 
	grib_data[i++] = fdata;		/* fill grid with constant val */

     DPRINT3("%s:  grid[%ld] contains convant value %lf\n",
	func, bds_head->ulGrid_size, fdata);

     status = (0);  /* no errors */
     goto BYE;
  }

  /* fill the data array with values from message */
  /*     - Assume that GDS may not be included so that
   *         the number of grid points may not be defined.       
   *     - Compute space to malloc based on BDS length,
   *         data_width, and numpts.
   *     - if grid_size from GDS is zero, use
   *         computed number of points.
   */

/*
*
* A.10      CALCULATE number of data points actually in BDS
*/
  num_calc = ((length - 11)*8 - numpts) / data_width;

  /* Check the number of points computed against info in the BMS
     or GDS, if they are available */

/*
*
* A.11      IF (BMS is present and has included bitmap) THEN
*               IF (#calculated not same as #bits set in BMS) THEN
*                   RETURN 2
*               ENDIF
*/
  if (bms->uslength > 6)
  {
      if (bms->ulbits_set != num_calc) {
	DPRINT3 ("%s:  BMS present, #datapts calculated (%d) " \
	"not same as BMS's set bits (%d)\n",func, num_calc, bms->ulbits_set);

	sprintf(errmsg,"%s:  BMS present, #datapts calculated (%d) " \
	"not same as BMS's set bits (%d)\n",func, num_calc, bms->ulbits_set);
	status= (2); goto BYE;
	}
  }
/*
* A.11.1    ELSE  !no bms
*               IF (GDS is present AND
*                   #calculated not same as GDS's grid size)
*               THEN
*                   RETURN 3
*               ENDIF
*/
  else
  {
      if (bds_head->ulGrid_size && bds_head->ulGrid_size != num_calc) {
	   DPRINT3 ( "%s:  GDS present, #datapts calculated (%d) " \
	   "not same as GDS's grid size (%d)\n",
	   func,num_calc,bds_head->ulGrid_size);

	   sprintf(errmsg,"%s:  GDS present, #datapts calculated (%d) " \
	   "not same as GDS's grid size (%d)\n",
	   func,num_calc,bds_head->ulGrid_size);
	   status=(3); goto BYE;
	 }
  }
/*
* A.11      ENDIF (BMS present)
*/

  /* Only reach this point if number of points in BDS matches info
     in BMS or GDS.  This number is unchecked if no BMS or GDS. */

  /* Make sure number of points in BDS is value used for extracting */
/*
*
* A.12      SET #datapoints
*/
  bds_head->ulGrid_size = num_calc;
  data_pts= num_calc;

/*
*
* A.13      ALLOCATE storage for float array size
*           IF (error) THEN
*               RETURN 4
*           ENDIF
*/
  grib_data =(float *) malloc(data_pts * sizeof(float));
  if (grib_data==NULL) { 
	DPRINT1 ("%s: failed to malloc Grib_Data\n",func);
	sprintf(errmsg,"%s: failed to malloc Grib_Data\n",func);
	status=(4); goto BYE; }

/*
*
* A.14      SET data array pointer to local data array
*/
  *ppgrib_data = grib_data;

/*
*
* A.15      FOR (each data point) DO
*               FUNCTION gbyte_quiet   !get data_width bits
*               INCREMENT skip by data_width
*               COMPUTE and STORE value in float array
*           ENDDO
*/

  DPRINT3 ( "Restore float data by = (float)(%f + X * %f)) / %f;\n",
  ref_val, bscale, dscale);

  for(i=0;i < (int)data_pts ;i++)  
     {
     gbyte_quiet(in,&something,&skip,data_width);
     grib_data[i]= (float)(ref_val + (something * bscale))/dscale;
     }

  DPRINT0 ("Sample of first 30 unpacked & restored datapoints=\n");
  for (i=0; i < 30; i+=5)
     DPRINT6 ("%03d:  %f %f %f %f %f\n",
	i, grib_data[i], grib_data[i+1],grib_data[i+2],
	grib_data[i+3], grib_data[i+4] );
  
BYE:
/*
*
* A.16      RETURN Status;
*/
  DPRINT2 ("Exiting %s, status=%d\n", func, status);
  return(status); 
/* 
* END OF FUNCTION
*
*/
}    
