/* *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* */
/* ** Copyright UCAR (c) 1990 - 2016                                         */
/* ** University Corporation for Atmospheric Research (UCAR)                 */
/* ** National Center for Atmospheric Research (NCAR)                        */
/* ** Boulder, Colorado, USA                                                 */
/* ** BSD licence applies - redistribution and use in source and binary      */
/* ** forms, with or without modification, are permitted provided that       */
/* ** the following conditions are met:                                      */
/* ** 1) If the software is modified to produce derivative works,            */
/* ** such modified software should be clearly marked, so as not             */
/* ** to confuse it with the version available from UCAR.                    */
/* ** 2) Redistributions of source code must retain the above copyright      */
/* ** notice, this list of conditions and the following disclaimer.          */
/* ** 3) Redistributions in binary form must reproduce the above copyright   */
/* ** notice, this list of conditions and the following disclaimer in the    */
/* ** documentation and/or other materials provided with the distribution.   */
/* ** 4) Neither the name of UCAR nor the names of its contributors,         */
/* ** if any, may be used to endorse or promote products derived from        */
/* ** this software without specific prior written permission.               */
/* ** DISCLAIMER: THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS  */
/* ** OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED      */
/* ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.    */
/* *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* */

/* The following define added by Niles, October 1999. 
It is the ceiling, in feet, to assume if the CLR message
is present. */

#define CLR_CEILING 12000.0 /* ft */
#define SKC_CEILING 12000.0 /* ft */
#define CAVOK_CEILING_FT 12000.0
#define NSC_CEILING_FT 12000.0 
#define CAVOK_VIS_KM 10.0


#include <toolsa/toolsa_macros.h>
#include <toolsa/str.h>
#include <rapformats/metar_decode.h>
#include <string.h>                                                             
#include <stdlib.h>                                                             
#include <ctype.h>                                                             
#include "metar_private.h"

/********************************************************************/
/*                                                                  */
/*  Title:         SaveTokenString                                  */
/*  Organization:  W/OSO242 - GRAPHICS AND DISPLAY SECTION          */
/*  Date:          14 Sep 1994                                      */
/*  Programmer:    CARL MCCALLA                                     */
/*  Language:      C/370                                            */
/*                                                                  */
/*  Abstract:      SaveTokenString tokenizes the input character    */
/*                 string based upon the delimeter set supplied     */
/*                 by the calling routine.  The elements tokenized  */
/*                 from the input character string are saved in an  */
/*                 array of pointers to characters.  The address of */
/*                 this array is the output from this function.     */
/*                                                                  */
/*  Input:         string - a pointer to a character string.        */
/*                                                                  */
/*                 delimiters - a pointer to a string of 1 or more  */
/*                              characters that are used for token- */
/*                              izing the input character string.   */
/*                                                                  */
/*  Output:        token  - the address of a pointer to an array of */
/*                          pointers to character strings.  The     */
/*                          array of pointers are the addresses of  */
/*                          the character strings that are token-   */
/*                          ized from the input character string.   */
/*                                                                  */
/*                                                                  */
/*  Modification History:                                           */
/*     NCAR/RAP - F. Hage  Added error checking - use calloc to     */
/*          assure tokens get null terminated, etc                  */
/*      Note: This routines allocates space - It's up to the        */
/* calling routine to free up this space. Also the token array      */
/* may or may not  have a null pointer indicating the end of        */
/* tokens. The calling routine MUST check no                        */
/* more than MAXTOKENS elements in the returned array               */
/*                                                                  */
/********************************************************************/

static char **SaveTokenString ( char *string , char *delimiters )
{

   /***************************/
   /* DECLARE LOCAL VARIABLES */
   /***************************/

   int NDEX;  /* token index */
   char *ptr; /* Temporary pointer */
   static char *token[ MAXTOKENS ], *TOKEN;


   /*********************************/
   /* BEGIN THE BODY OF THE ROUTINE */
   /*********************************/

   /* Make all token pointers NULL to start */
   memset(token,0,(MAXTOKENS * sizeof(char*)));

   /* Bail out on bad parameters */
   if(string == NULL || delimiters == NULL ) {
     return token;
   } 

   /******************************************/
   /* TOKENIZE THE INPUT CHARACTER STRING    */
   /* AND SAVE THE TOKENS TO THE token ARRAY */
   /******************************************/

   NDEX = 0;
   TOKEN = strtok( string, delimiters);

   if(TOKEN == NULL) { /* Bail out if no tokens found */
     token[NDEX] = NULL;
     return token;
   } 

   /* Allocate space for the first token */
   token[NDEX] = (char *) calloc(1,sizeof(char)*(strlen(TOKEN)+1));
   strcpy( token[ NDEX ], TOKEN );
 
 
   /* Find all tokens or give up if space is exausted */
   while ( token[NDEX] != NULL && NDEX < (MAXTOKENS -1))
   {
      NDEX++;
      /* Grab the next token pointer */
      TOKEN = strtok( NULL, delimiters );
 
      if( TOKEN != NULL )
      {
          /* Allocate space for the next token and copy it */
         token[NDEX] = (char *) calloc(1,sizeof(char)*(strlen(TOKEN)+1));
         strcpy( token[NDEX], TOKEN );
	 /* Replace equal signs with null - FH.  */
	 if((ptr = strchr(token[NDEX],'=')) != NULL ) *ptr = '\0';

      } else {
	 token[NDEX] = NULL;  /* here for clarity */
      }
   }
 
   return token;
 
}
/********************************************************************/
/*                                                                  */
/*  Title:         freeTokens                                       */
/*  Organization:  W/OSO242 - GRAPHICS AND DISPLAY SECTION          */
/*  Date:          14 Sep 1994                                      */
/*  Programmer:    CARL MCCALLA                                     */
/*  Language:      C/370                                            */
/*                                                                  */
/*  Abstract:      freeTokens frees the storage allocated for the   */
/*                 character strings stored in the token array.     */
/*                                                                  */
/*  Input:         token  - the address of a pointer to an array    */
/*                          of string tokens.                       */
/*                                                                  */
/*                                                                  */
/*  Output:        None.                                            */
/*                                                                  */
/*                                                                  */
/*  Modification History:                                           */
/*                 F. Hage - Added check so as not to exceed        */
/*               MAXTOKEN Free()'s - See above routines' comments.  */
/*                                                                  */
/********************************************************************/
 
static void freeTokens( char **token )
{
  int i;
  for (i = 0; i < MAXTOKENS; i++) {
    if (token[i] != NULL) {
      free (token[i]);
      token[i] = NULL;
    }
  } /* i */
}
/********************************************************************/
/*                                                                  */
/*  Title:         InitDcdMETAR                                     */
/*  Organization:  W/OSO242 - GRAPHICS AND DISPLAY SECTION          */
/*  Date:          15 Sep 1994                                      */
/*  Programmer:    CARL MCCALLA                                     */
/*  Language:      C/370                                            */
/*                                                                  */
/*  Abstract:  InitDcdMETAR initializes every member of the         */
/*             structure addressed by the pointer Mptr.             */
/*                                                                  */
/*  External Functions Called:                                      */
/*                 None.                                            */
/*                                                                  */
/*  Input:         Mptr - ptr to a decoded_METAR structure.         */
/*                                                                  */
/*  Output:        NONE                                             */
/*                                                                  */
/*  Modification History:                                           */
/*                 None.                                            */
/*                                                                  */
/********************************************************************/
static void InitDcdMETAR( Decoded_METAR *Mptr )
{
 
   /***************************/
   /* DECLARE LOCAL VARIABLES */
   /***************************/
 
 
   int i,
       j;
 
 
 
   /*************************/
   /* START BODY OF ROUTINE */
   /*************************/
 
   memset(Mptr->TornadicType,'\0',15);
   memset(Mptr->TornadicLOC,'\0',10);
   memset(Mptr->TornadicDIR,'\0',4);
   Mptr->BTornadicHour = MAXINT;
   Mptr->BTornadicMinute = MAXINT;
   Mptr->ETornadicHour = MAXINT;
   Mptr->ETornadicMinute = MAXINT;
 
   memset( Mptr->autoIndicator,'\0', 5 );
 
   Mptr->RVRNO = FALSE;
   Mptr->GR = FALSE;
   Mptr->GR_Size = (float) MAXINT;
 
   Mptr->CHINO = FALSE;
   memset(Mptr->CHINO_LOC, '\0', 6);
 
   Mptr->VISNO = FALSE;
   memset(Mptr->VISNO_LOC, '\0', 6);
 
   Mptr->PNO = FALSE;
   Mptr->PWINO = FALSE;
   Mptr->FZRANO  = FALSE;
   Mptr->TSNO   = FALSE;
   Mptr->DollarSign  = FALSE;
   Mptr->hourlyPrecip = (float) MAXINT;
 
   Mptr->ObscurAloftHgt = MAXINT;
   memset(Mptr->ObscurAloft, '\0', 12);
   memset(Mptr->ObscurAloftSkyCond, '\0', 12);
 
   memset(Mptr->VrbSkyBelow, '\0', 4);
   memset(Mptr->VrbSkyAbove, '\0', 4);
   Mptr->VrbSkyLayerHgt = MAXINT;
 
   Mptr->SectorVsby = (float) MAXINT;
   memset( Mptr->SectorVsby_Dir, '\0', 3);
 
   memset(Mptr->codeName, '\0', 6);
   memset(Mptr->stnid, '\0', 5);
   Mptr->ob_hour   = MAXINT;
   Mptr->ob_minute = MAXINT;
   Mptr->ob_date   = MAXINT;
 
   memset(Mptr->synoptic_cloud_type, '\0', 6);
 
   Mptr->CloudLow    = '\0';
   Mptr->CloudMedium = '\0';
   Mptr->CloudHigh   = '\0';
 
   memset(Mptr->snow_depth_group, '\0', 6);
   Mptr->snow_depth = MAXINT;
 
   Mptr->Temp_2_tenths    = (float) MAXINT;
   Mptr->DP_Temp_2_tenths = (float) MAXINT;
 
   Mptr->OCNL_LTG = FALSE;
   Mptr->FRQ_LTG = FALSE;
   Mptr->CNS_LTG = FALSE;
   Mptr->CG_LTG = FALSE;
   Mptr->IC_LTG = FALSE;
   Mptr->CC_LTG = FALSE;
   Mptr->CA_LTG = FALSE;
   Mptr->AP_LTG = FALSE;
   Mptr->OVHD_LTG = FALSE;
   Mptr->DSNT_LTG = FALSE;
   Mptr->VcyStn_LTG = FALSE;
   Mptr->LightningVCTS = FALSE;
   Mptr->LightningTS = FALSE;
 
   memset( Mptr->LTG_DIR, '\0', 3);
 
 
   for( i = 0; i < 3; i++)
   {
      memset(Mptr->ReWx[i].Recent_weather, '\0', 5);
 
      Mptr->ReWx[i].Bhh = MAXINT;
      Mptr->ReWx[i].Bmm = MAXINT;
 
      Mptr->ReWx[i].Ehh = MAXINT;
      Mptr->ReWx[i].Emm = MAXINT;
 
   }
 
   Mptr->NIL_rpt = FALSE;
   Mptr->AUTO = FALSE;
   Mptr->COR = FALSE;
 
   Mptr->winData.windDir = MAXINT;
   Mptr->winData.windSpeed = MAXINT;
   Mptr->winData.windGust = MAXINT;
   Mptr->winData.windVRB  = FALSE;
   Mptr->winData.windEstimated  = FALSE;
   memset(Mptr->winData.windUnits, '\0', 4);
 
   Mptr->minWnDir = MAXINT;
   Mptr->maxWnDir = MAXINT;
 
   memset(Mptr->horiz_vsby, '\0', 5);
   memset(Mptr->dir_min_horiz_vsby, '\0', 3);
 
   Mptr->prevail_vsbySM = (float) MAXINT;
   Mptr->prevail_vsbyM  = (float) MAXINT;
   Mptr->prevail_vsbyKM = (float) MAXINT;
   memset(Mptr->charPrevailVsby, '\0', 12);
 
   memset(Mptr->vsby_Dir, '\0', 3);
 
   Mptr->CAVOK = FALSE;
 
   for ( i = 0; i < 12; i++ )
   {
      memset(Mptr->RRVR[ i ].runway_designator,
              '\0', 6);
 
      Mptr->RRVR[ i ].visRange = MAXINT;
 
      Mptr->RRVR[ i ].vrbl_visRange = FALSE;
      Mptr->RRVR[ i ].below_min_RVR = FALSE;
      Mptr->RRVR[ i ].above_max_RVR = FALSE;
 
 
      Mptr->RRVR[ i ].Max_visRange = MAXINT;
      Mptr->RRVR[ i ].Min_visRange = MAXINT;
   }
 
   Mptr->DVR.visRange = MAXINT;
   Mptr->DVR.vrbl_visRange = FALSE;
   Mptr->DVR.below_min_DVR = FALSE;
   Mptr->DVR.above_max_DVR = FALSE;
   Mptr->DVR.Max_visRange = MAXINT;
   Mptr->DVR.Min_visRange = MAXINT;
 
   for ( i = 0; i < MAXWXSYMBOLS; i++ )
   {
      for( j = 0; j < 8; j++ )
         Mptr->WxObstruct[i][j] = '\0';
   }
 
   /***********************/
   /* PARTIAL OBSCURATION */
   /***********************/
 
   memset( &(Mptr->PartialObscurationAmt[0][0]), '\0', 7 );
   memset( &(Mptr->PartialObscurationPhenom[0][0]), '\0',12);
 
   memset( &(Mptr->PartialObscurationAmt[1][0]), '\0', 7 );
   memset( &(Mptr->PartialObscurationPhenom[1][0]), '\0',12);
 
 
   /***************************************************/
   /* CLOUD TYPE, CLOUD LEVEL, AND SIGNIFICANT CLOUDS */
   /***************************************************/
 
 
   for ( i = 0; i < 6; i++ )
   {
      memset(Mptr->cldTypHgt[ i ].cloud_type,
              '\0', 5);
 
      memset(Mptr->cldTypHgt[ i ].cloud_hgt_char,
              '\0', 4);
 
      Mptr->cldTypHgt[ i ].cloud_hgt_meters = MAXINT;
 
      memset(Mptr->cldTypHgt[ i ].other_cld_phenom,
              '\0', 4);
   }
 
   Mptr->VertVsby = MAXINT;
   memset( Mptr->charVertVsby, '\0', 10 );
 
   Mptr->temp = MAXINT;
   Mptr->dew_pt_temp = MAXINT;
   Mptr->QFE = MAXINT;
 
   Mptr->SLPNO = FALSE;
   Mptr->SLP = (float) MAXINT;
 
   Mptr->A_altstng = FALSE;
   Mptr->inches_altstng = (double) MAXINT;
 
   Mptr->Q_altstng = FALSE;
   Mptr->hectoPasc_altstng = MAXINT;
 
   Mptr->char_prestndcy = MAXINT;
   Mptr->prestndcy = (float) MAXINT;
 
   Mptr->precip_amt = (float) MAXINT;
 
   Mptr->precip_24_amt = (float) MAXINT;
   Mptr->maxtemp       = (float) MAXINT;
   Mptr->mintemp       = (float) MAXINT;
   Mptr->max24temp     = (float) MAXINT;
   Mptr->min24temp     = (float) MAXINT;
 
   Mptr->VIRGA         = FALSE;
   memset( Mptr->VIRGA_DIR, '\0', 3 );
 
   Mptr->VOLCASH       = FALSE;
 
   Mptr->minCeiling    = MAXINT;
   Mptr->maxCeiling    = MAXINT;
 
   Mptr->CIG_2ndSite_Meters = MAXINT;
   memset(Mptr->CIG_2ndSite_LOC, '\0', 10 );
 
   Mptr->minVsby = (float) MAXINT;
   Mptr->maxVsby = (float) MAXINT;
   Mptr->VSBY_2ndSite = (float) MAXINT;
   memset(Mptr->VSBY_2ndSite_LOC,'\0',10);
 
   for( i = 0; i < 6; i++ )
      memset (&(Mptr->SfcObscuration[i][0]), '\0', 10);
 
   Mptr->Num8thsSkyObscured = MAXINT;
 
   Mptr->CIGNO = FALSE;
   Mptr->Ceiling = MAXINT;
   Mptr->Estimated_Ceiling = MAXINT;
 
   Mptr->NOSPECI = FALSE;
   Mptr->LAST    = FALSE;
 
   Mptr->SNINCR = MAXINT;
   Mptr->SNINCR_TotalDepth = MAXINT;
 
   Mptr->WaterEquivSnow = (float) MAXINT;
 
   Mptr->SunshineDur = MAXINT;
   Mptr->SunSensorOut = FALSE;
 
 
   Mptr->WshfTime_hour = MAXINT;
   Mptr->WshfTime_minute = MAXINT;
   Mptr->Wshft_FROPA     = FALSE;
   Mptr->min_vrbl_wind_dir = MAXINT;
   Mptr->max_vrbl_wind_dir = MAXINT;
 
   Mptr->PRESRR        = FALSE;
   Mptr->PRESFR        = FALSE;
 
   Mptr->TWR_VSBY = (float) MAXINT;
   Mptr->SFC_VSBY = (float) MAXINT;
 
   Mptr->PKWND_dir = MAXINT;
   Mptr->PKWND_speed = MAXINT;
   Mptr->PKWND_hour = MAXINT;
   Mptr->PKWND_minute = MAXINT;
 
   return;
 
}
/********************************************************************/
/*                                                                  */
/*  Title:         ResetMETARGroup                                  */
/*  Organization:  W/OSO242 - GRAPHICS AND DISPLAY SECTION          */
/*  Date:          15 Sep 1994                                      */
/*  Programmer:    CARL MCCALLA                                     */
/*  Language:      C/370                                            */
/*                                                                  */
/*  Abstract:  ResetMETARGroup returns a METAR_obGroup enumerated   */
/*             variable that indicates which METAR reporting group  */
/*             might next appear in the METAR report and should be  */
/*             considered for decoding.                             */
/*                                                                  */
/*  External Functions Called:                                      */
/*                 None.                                            */
/*                                                                  */
/*  Input:         StartGroup - a METAR_obGroup variable that       */
/*                              indicates where or on what group    */
/*                              METAR Decoding began.               */
/*                                                                  */
/*                 SaveStartGroup - a METAR_obGroup variable that   */
/*                                  indicates the reporting group   */
/*                                  in the METAR report that was    */
/*                                  successfully decoded.           */
/*                                                                  */
/*  Output:        A METAR_obGroup variable that indicates which    */
/*                 reporting group in the METAR report should next  */
/*                 be considered for decoding                       */
/*                                                                  */
/*  Modification History:                                           */
/*                 None.                                            */
/*                                                                  */
/********************************************************************/
static int ResetMETARGroup( int StartGroup,
                            int SaveStartGroup )
{
 
   enum METAR_obGroup { codename, stnid, NIL1, obDateTime, NIL2,
                        AUTO, COR, windData, MinMaxWinDir, visibility,
                        RVR, presentWX, skyCond, tempGroup,
                        altimStng, NotIDed = 99};
 
   if( StartGroup == NotIDed && SaveStartGroup == NotIDed )
      return NotIDed;
   else if( StartGroup == NotIDed && SaveStartGroup != NotIDed &&
            SaveStartGroup != altimStng )
      return (++SaveStartGroup);
   else
      return (++SaveStartGroup);
 
}
 
/********************************************************************/
/*                                                                  */
/*  Title:         CodedHgt2Meters                                  */
/*  Organization:  W/OSO242 - GRAPHICS AND DISPLAY SECTION          */
/*  Date:          15 Sep 1994                                      */
/*  Programmer:    CARL MCCALLA                                     */
/*  Language:      C/370                                            */
/*                                                                  */
/*  Abstract:  CodedHgt2Meters converts a coded cloud height into   */
/*             meters.                                              */
/*                                                                  */
/*  External Functions Called:                                      */
/*                 None.                                            */
/*                                                                  */
/*  Input:         token - a pointer to a METAR report group.       */
/*                 Mptr - a pointer to a decoded_METAR structure.   */
/*                                                                  */
/*  Output:        Cloud height in meters                           */
/*                                                                  */
/*  Modification History:                                           */
/*                 None.                                            */
/*                                                                  */
/********************************************************************/
 
static int CodedHgt2Meters( char *token, Decoded_METAR *Mptr )
{
   int hgt;
   static int maxhgt = 30000;
 
 
   if( (hgt = atoi(token)) == 999 )
      return maxhgt;
   else
      return ((int)(hgt*30.48+0.5));
}
 
/********************************************************************/
/*                                                                  */
/*  Title:         isPartObscur                                     */
/*  Organization:  W/OSO242 - GRAPHICS AND DISPLAY SECTION          */
/*  Date:          15 Sep 1994                                      */
/*  Programmer:    CARL MCCALLA                                     */
/*  Language:      C/370                                            */
/*                                                                  */
/*  Abstract:  isPartObscur determines whether or not the METAR     */
/*             report element that is passed to it is or is not     */
/*             a partial obscuration indicator for an amount of     */
/*             obscuration.                                         */
/*                                                                  */
/*                                                                  */
/*  External Functions Called:                                      */
/*                 None.                                            */
/*                                                                  */
/*  Input:         token - the address of a pointer to the group    */
/*                         in the METAR report that isPartObscur    */
/*                         determines is or is not a partial        */
/*                         obscuration indicator.                   */
/*                                                                  */
/*                                                                  */
/*                 Mptr - a pointer to a decoded_METAR structure.   */
/*                                                                  */
/*  Output:        TRUE, if the group is a partial obscuration      */
/*                 indicator and FALSE, if it is not.               */
/*                                                                  */
/*                                                                  */
/*  Modification History:                                           */
/*                 None.                                            */
/*                                                                  */
/********************************************************************/
static ubool isPartObscur( char **string, Decoded_METAR *Mptr,
                          int *NDEX )
{
   if( strcmp( *string, "FEW///" ) == 0 ||
       strcmp( *string, "SCT///" ) == 0 ||
       strcmp( *string, "BKN///" ) == 0 ||
       strcmp( *string, "FEW000" ) == 0 ||
       strcmp( *string, "SCT000" ) == 0 ||
       strcmp( *string, "BKN000" ) == 0    ) {
      strcpy( &(Mptr->PartialObscurationAmt[0][0]), *string );
      (*NDEX)++;
      string++;
 
      if( strcmp( (*string+3), "///") ) {
          if( strcmp( *string, "FEW000" ) == 0 ||
              strcmp( *string, "SCT000" ) == 0 ||
              strcmp( *string, "BKN000" ) == 0    ) {
            strcpy( &(Mptr->PartialObscurationAmt[1][0]), *string );
            (*NDEX)++;
         }
      }
      else {
         if( strcmp( *string, "FEW///" ) == 0 ||
             strcmp( *string, "SCT///" ) == 0 ||
             strcmp( *string, "BKN///" ) == 0 ) {
            strcpy( &(Mptr->PartialObscurationAmt[1][0]), *string );
            (*NDEX)++;
         }
      }
      return TRUE;
   }
   else
      return FALSE;
}
 
/********************************************************************/
/*                                                                  */
/*  Title:         isCldLayer                                       */
/*  Organization:  W/OSO242 - GRAPHICS AND DISPLAY SECTION          */
/*  Date:          15 Sep 1994                                      */
/*  Programmer:    CARL MCCALLA                                     */
/*  Language:      C/370                                            */
/*                                                                  */
/*  Abstract:      isCldLayer determines whether or not the         */
/*                 current group has a valid cloud layer            */
/*                 identifier.                                      */
/*                                                                  */
/*                                                                  */
/*  External Functions Called:                                      */
/*                 None.                                            */
/*                                                                  */
/*  Input:         token - pointer to a METAR report group.         */
/*                                                                  */
/*  Output:        TRUE, if the report group is a valid cloud       */
/*                 layer indicator.                                 */
/*                                                                  */
/*                 FALSE, if the report group is not a valid cloud  */
/*                 layer indicator.                                 */
/*                                                                  */
/*                                                                  */
/*  Modification History:                                           */
/*                 None.                                            */
/*                                                                  */
/********************************************************************/
 
static ubool isCldLayer( char *token )
{
 
   if( token == NULL || strlen(token) < 6 )
      return FALSE;
   else
      return ((strncmp(token,"OVC",3) == 0 ||
               strncmp(token,"SCT",3) == 0 ||
               strncmp(token,"FEW",3) == 0 ||
               strncmp(token,"BKN",3) == 0 ||
               (isdigit(*token) &&
                strncmp(token+1,"CU",2) == 0) ||
               (isdigit(*token) &&
                strncmp(token+1,"SC",2) == 0) ) &&
               nisdigit((token+3),3)) ? TRUE:FALSE;
}
 
 
/********************************************************************/
/*                                                                  */
/*  Title:         parseCldData                                     */
/*  Organization:  W/OSO242 - GRAPHICS AND DISPLAY SECTION          */
/*  Date:          15 Sep 1994                                      */
/*  Programmer:    CARL MCCALLA                                     */
/*  Language:      C/370                                            */
/*                                                                  */
/*  Abstract:                                                       */
/*                                                                  */
/*  External Functions Called:                                      */
/*                 None.                                            */
/*                                                                  */
/*  Input:         x                                                */
/*                                                                  */
/*  Output:        x                                                */
/*                                                                  */
/*  Modification History:                                           */
/*                 None.                                            */
/*                                                                  */
/********************************************************************/
 
static void parseCldData( char *token, Decoded_METAR *Mptr, int next)
{
 
 
   if(token == NULL) return;

   if( strlen(token) > 6 )
      strncpy(Mptr->cldTypHgt[next].other_cld_phenom,token+6,
              (strlen(token)-6));
 
   strncpy(Mptr->cldTypHgt[next].cloud_type,token,3);
 
   strncpy(Mptr->cldTypHgt[next].cloud_hgt_char,token+3,3);
 
   Mptr->cldTypHgt[next].cloud_hgt_meters =
                               CodedHgt2Meters( token+3, Mptr );
 
   return;
}
 
 
/********************************************************************/
/*                                                                  */
/*  Title:         isSkyCond                                        */
/*  Organization:  W/OSO242 - GRAPHICS AND DISPLAY SECTION          */
/*  Date:          15 Sep 1994                                      */
/*  Programmer:    CARL MCCALLA                                     */
/*  Language:      C/370                                            */
/*                                                                  */
/*  Abstract:                                                       */
/*                                                                  */
/*  External Functions Called:                                      */
/*                 None.                                            */
/*                                                                  */
/*  Input:         x                                                */
/*                                                                  */
/*  Output:        x                                                */
/*                                                                  */
/*  Returns: 1 if *skycond is a sky condition, 0 otherwise          */
/*                                                                  */
/*  Modification History:                                           */
/*                 None.                                            */
/*                                                                  */
/********************************************************************/
static int isSkyCond( char **skycond, Decoded_METAR *Mptr,
                      int *NDEX )
{
 
// Code replaced by S Sullivan, 2007-06-11
//   ubool first_layer,
//        second_layer,
//        third_layer;
//   int next;
// End code replaced by S Sullivan, 2007-06-11

 
      /********************************************************/
      /* INTERROGATE skycond TO DETERMINE IF "CLR" IS PRESENT */
      /********************************************************/
 
   if( strcmp(*skycond,"CLR") == 0)
   {
      strcpy(Mptr->cldTypHgt[0].cloud_type,"CLR");

      /* The following added by Niles for our
	 Taiwan project. */

      Mptr->Estimated_Ceiling  = CLR_CEILING;
      Mptr->Ceiling  = CLR_CEILING;
      strcpy(Mptr->charPrevailVsby, *skycond);

      /* Additions by Niles end. */

/*
      memset(Mptr->cldTypHgt[0].cloud_hgt_char,'\0',1);
      memset(Mptr->cldTypHgt[0].other_cld_phenom,
              '\0', 1);
*/
      (*NDEX)++;
      return 1;
   }
 
      /********************************************************/
      /* INTERROGATE skycond TO DETERMINE IF "SKC" IS PRESENT */
      /********************************************************/
 
   else if( strcmp(*skycond,"SKC") == 0)
   {
      strcpy(Mptr->cldTypHgt[0].cloud_type,"SKC");

      Mptr->Estimated_Ceiling  = SKC_CEILING;
      Mptr->Ceiling  = SKC_CEILING;
      strcpy(Mptr->charPrevailVsby, *skycond);
/*
      memset(Mptr->cldTypHgt[0].cloud_hgt_char,'\0',1);
      memset(Mptr->cldTypHgt[0].other_cld_phenom,'\0', 1);
*/
      (*NDEX)++;
      return 1;
   }
 
      /********************************************************/
      /* INTERROGATE skycond TO DETERMINE IF "NSC" IS PRESENT */
      /********************************************************/
 
   else if( strcmp(*skycond,"NSC") == 0)
   {
      strcpy(Mptr->cldTypHgt[0].cloud_type,"NSC");

      Mptr->Estimated_Ceiling  = NSC_CEILING_FT;
      Mptr->Ceiling  = NSC_CEILING_FT;
      strcpy(Mptr->charPrevailVsby, *skycond);

      (*NDEX)++;
      return 1;
   }
 
      /****************************************/
      /* INTERROGATE skycond TO DETERMINE IF  */
      /*    VERTICAL VISIBILITY IS PRESENT    */
      /****************************************/
 
   else if( strncmp(*skycond,"VV",2) == 0
             && strlen(*skycond) == 5 &&
                  nisdigit((*skycond+2),3) )
   {
      Mptr->VertVsby = CodedHgt2Meters( (*skycond+2), Mptr);
      strcpy( Mptr->charVertVsby, *skycond);
      (*NDEX)++;
      return 1;
   }
 
      /****************************************/
      /* INTERROGATE skycond TO DETERMINE IF  */
      /*    CLOUD LAYER DATA IS PRESENT       */
      /****************************************/

   else if( strncmp(*skycond, "OVC", 3) == 0 ||
            strncmp(*skycond, "SCT", 3) == 0 ||
            strncmp(*skycond, "FEW", 3) == 0 ||
            strncmp(*skycond, "BKN", 3) == 0 ||
                  ( (isdigit(**skycond) &&
                     strncmp(*skycond+1,"CU",2) == 0) ||
                    (isdigit(**skycond) &&
                     strncmp(*skycond+1,"SC",2) == 0) ) )
   {


// New code by S Sullivan, 2007-06-11
      int ilayer = 0;
      while (ilayer < 6) {
        if (skycond[ilayer] == NULL || ! isCldLayer( skycond[ilayer]))
          break;
        parseCldData( skycond[ilayer], Mptr, ilayer);
        (*NDEX)++;
        ilayer++;
      }
      if (ilayer > 0) return 1;
      else return 0;
// End new code by S Sullivan, 2007-06-11


// Code replaced by above, by S Sullivan, 2007-06-11
//      next = 0;
// 
//      first_layer = FALSE;
//      second_layer = FALSE;
//      third_layer = FALSE;
//
//      if( *skycond && isCldLayer( *skycond ))
//      {
//         parseCldData( *skycond , Mptr, next );
//         first_layer = TRUE;
//         next++;
//      }
//
//      ++skycond;
//      if( first_layer && *skycond && isCldLayer( *skycond ) )
//      {
//         parseCldData( *skycond, Mptr, next );
//         second_layer = TRUE;
//         next++;
//      }
//      ++skycond;
//      if( first_layer && second_layer && *skycond && isCldLayer( *skycond ) )
//      {
//         parseCldData( *skycond , Mptr, next );
//         third_layer = TRUE;
//      }
// 
//      if( third_layer )
//      {
//         (*NDEX)++;
//         (*NDEX)++;
//         (*NDEX)++;
//         return 1;
//      }
//      else if( second_layer )
//      {
//         (*NDEX)++;
//         (*NDEX)++;
//         return 1;
//      }
//      else if( first_layer )
//      {
//         (*NDEX)++;
//         return 1;
//      }
//      else
//         return 0;
// End code replaced by above, by S Sullivan, 2007-06-11


   } // else if *skycond is OVC or SKT or ...


   else
      return 0;
}
/********************************************************************/
/*                                                                  */
/*  Title:         prevailVSBY                                      */
/*  Organization:  W/OSO242 - GRAPHICS AND DISPLAY SECTION          */
/*  Date:          15 Sep 1994                                      */
/*  Programmer:    CARL MCCALLA                                     */
/*  Language:      C/370                                            */
/*                                                                  */
/*  Abstract:                                                       */
/*                                                                  */
/*  External Functions Called:                                      */
/*                 None.                                            */
/*                                                                  */
/*  Input:         x                                                */
/*                                                                  */
/*  Output:        x                                                */
/*                                                                  */
/*  Modification History:                                           */
/*                 None.                                            */
/*                                                                  */
/********************************************************************/
static float prevailVSBY( char *visibility )
{

   float Miles_vsby;
   char *Slash_ptr, *SM_KM_ptr;
   char num_str[32], denom_str[32];
   char str[32];
   int len;

   double num, denom;
   
   if( (SM_KM_ptr = strstr( visibility, "SM" )) == NULL ) {
      SM_KM_ptr = strstr(visibility, "KM");
      if (SM_KM_ptr == NULL) {
	return (0.0);
      }
   }
 
   Slash_ptr = strchr( visibility, '/' );
 
   if( Slash_ptr == NULL )
     {
      memset( str, 0, 32);
      strncpy( str, visibility, (SM_KM_ptr-visibility) );
      Miles_vsby = (float) (atoi(str));
      return Miles_vsby;
   }
   else
   {
     
      memset( num_str, 0, 32);
      memset( denom_str, 0, 32);

      len = Slash_ptr - visibility;
      if (len < 1 || len > 16) {
	return (0.0);
      }
      strncpy(num_str, visibility, len);

      len = SM_KM_ptr - Slash_ptr;
      if (len < 1 || len > 16) {
	return (0.0);
      }
      strncpy(denom_str, Slash_ptr+1, len);

      num = atoi(num_str);
      denom = atoi(denom_str);

      if (denom == 0.0) {
	return (0.0);
      } else {
	return (num / denom);
      }

   }
 
}
 
/********************************************************************/
/*                                                                  */
/*  Title:         isVisibility                                     */
/*  Organization:  W/OSO242 - GRAPHICS AND DISPLAY SECTION          */
/*  Date:          15 Sep 1994                                      */
/*  Programmer:    CARL MCCALLA                                     */
/*  Language:      C/370                                            */
/*                                                                  */
/*  Abstract:                                                       */
/*                                                                  */
/*  External Functions Called:                                      */
/*                 None.                                            */
/*                                                                  */
/*  Input:         x                                                */
/*                                                                  */
/*  Output:        x                                                */
/*                                                                  */
/*  Modification History:                                           */
/*                 None.                                            */
/*                                                                  */
/********************************************************************/
 
 
static ubool isVisibility( char **visblty, Decoded_METAR *Mptr,
                          int *NDEX )
{
   char *achar, *astring, VsbyString[12];
 
   static float KM_2_miles     = 0.62137,
                METERS_2_miles = 0.00062137;
 
   /****************************************/
   /* CHECK FOR CAVOK                      */
   /****************************************/
 
   if( strcmp(*visblty,"CAVOK") == 0 ) {
     Mptr->prevail_vsbySM = KM_2_miles * CAVOK_VIS_KM;
     Mptr->prevail_vsbyM = CAVOK_VIS_KM * 1000.0;
     strcpy(Mptr->charPrevailVsby, *visblty);
     Mptr->Estimated_Ceiling  = CAVOK_CEILING_FT;
     Mptr->Ceiling  = CAVOK_CEILING_FT;
     (*NDEX)++;
     return TRUE;
   }

   /****************************************/
   /* CHECK FOR VISIBILITY MEASURED <1/4SM */
   /****************************************/
 
   if( strcmp(*visblty,"M1/4SM") == 0 ||
       strcmp(*visblty,"<1/4SM") == 0 ) {
      Mptr->prevail_vsbySM = 0.0;
      Mptr->prevail_vsbyM = 0.0;
      Mptr->prevail_vsbyKM = 0.0;
      strcpy(Mptr->charPrevailVsby, *visblty);
      (*NDEX)++;
      return TRUE;
   }
 
   /***********************************************/
   /* CHECK FOR VISIBILITY MEASURED IN KILOMETERS */
   /***********************************************/
 
   if( (achar = strstr(*visblty, "KM")) != NULL )
   {
      if( nisdigit(*visblty,(achar - *visblty)))
      {
         Mptr->prevail_vsbyKM = prevailVSBY( *visblty );
         Mptr->prevail_vsbySM = KM_2_miles * Mptr->prevail_vsbyKM;
         strcpy(Mptr->charPrevailVsby, *visblty);
         (*NDEX)++;
         return TRUE;
      }
      else
         return FALSE;
   }
 
   /***********************************/
   /* CHECK FOR VISIBILITY MEASURED   */
   /* IN A FRACTION OF A STATUTE MILE */
   /***********************************/
 
   else if( (achar = strchr( *visblty, '/' )) !=
                    NULL &&
       (astring = strstr( *visblty, "SM")) != NULL )
   {
      if( nisdigit(*visblty,(achar - *visblty))
                     &&
                nisdigit(achar+1, (astring - (achar+1))) )
      {
         Mptr->prevail_vsbySM = prevailVSBY (*visblty);
         strcpy(Mptr->charPrevailVsby, *visblty);
         (*NDEX)++;
         return TRUE;
      }
      else
         return FALSE;
   }
 
   /***********************************/
   /* CHECK FOR VISIBILITY MEASURED   */
   /*     IN WHOLE STATUTE MILES      */
   /***********************************/
 
   else if( (astring = strstr(*visblty,"SM") ) != NULL )
   {
      if( nisdigit(*visblty,(astring - *visblty)))
      {
         Mptr->prevail_vsbySM = prevailVSBY (*visblty);
         strcpy(Mptr->charPrevailVsby, *visblty);
         (*NDEX)++;
         return TRUE;
      }
      else
         return FALSE;
   }
 
   /***********************************/
   /* CHECK FOR VISIBILITY MEASURED   */
   /* IN WHOLE AND FRACTIONAL STATUTE */
   /*             MILES               */
   /***********************************/
 
   else if( nisdigit( *visblty,
               strlen(*visblty)) &&
                            strlen(*visblty) < 4 )
   {
      char save_token[128];
      if (strlen(*visblty) > 127) return FALSE;
      strcpy(save_token,*visblty);
      if( *(++visblty) == NULL)
      {
         return FALSE;
      }
 
      if( (achar = strchr( *visblty, '/' ) ) != NULL &&
          (astring = strstr( *visblty, "SM") ) != NULL  )
      {
         if( nisdigit(*visblty,
                 (achar - *visblty)) &&
             nisdigit(achar+1, (astring - (achar+1))) )
         {
            Mptr->prevail_vsbySM = prevailVSBY (*visblty);
            Mptr->prevail_vsbySM +=
                                 (float) (atoi(save_token));
 
            memset( VsbyString, ' ',12 );
            strncpy( VsbyString,save_token,strlen(save_token));
            strcpy( VsbyString+strlen(save_token)+1,*visblty);
 
            strcpy(Mptr->charPrevailVsby, VsbyString);
 
            (*NDEX)++;
            (*NDEX)++;
 
            return TRUE;
 
         }
         else {
            return FALSE;
         }
      }
      else {
         return FALSE;
      }
   }
 
   /***********************************/
   /* CHECK FOR VISIBILITY MEASURED   */
   /* IN METERS WITH OR WITHOUT DI-   */
   /*     RECTION OF OBSERVATION      */
   /***********************************/
 
   else if( nisdigit(*visblty,4) &&
                strlen(*visblty) >= 4)
   {
      if( strcmp(*visblty+4,"NE") == 0 )
      {
         memset(Mptr->vsby_Dir,'\0',3);
         strcpy(Mptr->vsby_Dir,*visblty+4);
      }
      if( strcmp(*visblty+4,"NW") == 0 )
      {
         memset(Mptr->vsby_Dir,'\0',3);
         strcpy(Mptr->vsby_Dir,*visblty+4);
      }
      if( strcmp(*visblty+4,"SE") == 0 )
      {
         memset(Mptr->vsby_Dir,'\0',3);
         strcpy(Mptr->vsby_Dir,*visblty+4);
      }
      if( strcmp(*visblty+4,"SW") == 0 )
      {
         memset(Mptr->vsby_Dir,'\0',3);
         strcpy(Mptr->vsby_Dir,*visblty+4);
      }
      if( strcmp(*visblty+4,"N") == 0 )
      {
         memset(Mptr->vsby_Dir,'\0',3);
         strcpy(Mptr->vsby_Dir,*visblty+4);
      }
      if( strcmp(*visblty+4,"S") == 0 )
      {
         memset(Mptr->vsby_Dir,'\0',3);
         strcpy(Mptr->vsby_Dir,*visblty+4);
      }
      if( strcmp(*visblty+4,"E") == 0 )
      {
         memset(Mptr->vsby_Dir,'\0',3);
         strcpy(Mptr->vsby_Dir,*visblty+4);
      }
      if( strcmp(*visblty+4,"W") == 0 )
      {
         memset(Mptr->vsby_Dir,'\0',3);
         strcpy(Mptr->vsby_Dir,*visblty+4);
      }
 
      if( (antoi(*visblty, strlen(*visblty)) >= 50) &&
          (antoi(*visblty, strlen(*visblty)) <= 800) &&
          ((antoi(*visblty, strlen(*visblty)) % 50) == 0) )
      {
         Mptr->prevail_vsbyM =
           (float) (antoi(*visblty,
                       strlen(*visblty)));
         Mptr->prevail_vsbySM = METERS_2_miles *
                                  Mptr->prevail_vsbyM;
         strcpy(Mptr->charPrevailVsby,*visblty);
         (*NDEX)++;
         return TRUE;
      }
      else if( (antoi(*visblty, strlen(*visblty)) >= 800) &&
               (antoi(*visblty, strlen(*visblty)) <= 5000) &&
               ((antoi(*visblty, strlen(*visblty)) % 100) == 0) )
      {
         Mptr->prevail_vsbyM =
            (float) (antoi(*visblty,
                      strlen(*visblty)));
         Mptr->prevail_vsbySM = METERS_2_miles *
                                  Mptr->prevail_vsbyM;
         strcpy(Mptr->charPrevailVsby,*visblty);
         (*NDEX)++;
         return TRUE;
      }
      else if( ((antoi(*visblty, strlen(*visblty)) >= 5000) &&
                (antoi(*visblty, strlen(*visblty)) <= 9999) &&
                ((antoi(*visblty, strlen(*visblty)) % 500) == 0)) ||
               (antoi(*visblty, strlen(*visblty)) == 9999) )
      {
         Mptr->prevail_vsbyM =
                (float) (antoi(*visblty,
                     strlen(*visblty)));
         Mptr->prevail_vsbySM = METERS_2_miles *
                                  Mptr->prevail_vsbyM;
         strcpy(Mptr->charPrevailVsby,*visblty);
         (*NDEX)++;
         return TRUE;
      }
      else
         return FALSE;
 
   }

   return FALSE;          /* added by Jaimi Yee */
 
}
  
 
/********************************************************************/
/*                                                                  */
/*  Title:         isMinMaxWinDir                                   */
/*  Organization:  W/OSO242 - GRAPHICS AND DISPLAY SECTION          */
/*  Date:          15 Sep 1994                                      */
/*  Programmer:    CARL MCCALLA                                     */
/*  Language:      C/370                                            */
/*                                                                  */
/*  Abstract:                                                       */
/*                                                                  */
/*  External Functions Called:                                      */
/*                 None.                                            */
/*                                                                  */
/*  Input:         x                                                */
/*                                                                  */
/*  Output:        x                                                */
/*                                                                  */
/*  Modification History:                                           */
/*                 None.                                            */
/*                                                                  */
/********************************************************************/
static ubool isMinMaxWinDir( char *string, Decoded_METAR *Mptr,
			     int *NDEX )
{
   char buf[ 100 ];
   char *V_char;
 
 
   if( (V_char = strchr(string,'V')) == NULL )
      return FALSE;
   else
   {
      if( nisdigit(string,(V_char - string)) &&
               nisdigit(V_char+1,3) )
      {
         memset( buf, '\0', 100);
         strncpy( buf, string, V_char - string);
         Mptr->minWnDir = atoi( buf );
 
         memset( buf, '\0', 100);
         strcpy( buf, V_char+1 );
         Mptr->maxWnDir = atoi( buf );
 
         (*NDEX)++;
         return TRUE;
      }
      else
         return FALSE;
   }
}
/********************************************************************/
/*                                                                  */
/*  Title:         isRVR                                            */
/*  Organization:  W/OSO242 - GRAPHICS AND DISPLAY SECTION          */
/*  Date:          15 Sep 1994                                      */
/*  Programmer:    CARL MCCALLA                                     */
/*  Language:      C/370                                            */
/*                                                                  */
/*  Abstract:                                                       */
/*                                                                  */
/*  External Functions Called:                                      */
/*                 None.                                            */
/*                                                                  */
/*  Input:         x                                                */
/*                                                                  */
/*  Output:        x                                                */
/*                                                                  */
/*  Modification History:                                           */
/*                 None.                                            */
/*                                                                  */
/********************************************************************/
 
static ubool isRVR( char *token, Decoded_METAR *Mptr, int *NDEX,
                     int ndex )
{
   char *slashPtr, *FT_ptr;
   char *vPtr;
   int length;
 
 
   if(token == NULL) return FALSE;

   if( *token != 'R' || (length = strlen(token)) < 7 ||
        (slashPtr = strchr(token,'/')) == NULL ||
        nisdigit(token+1,2) == FALSE )
      return FALSE;
 
   if( (slashPtr - (token+3)) > 0 )
      if( !nisalpha(token+3,(slashPtr - (token+3))) )
         return FALSE;
 
   if( strcmp(token+(strlen(token)-2),"FT") != 0 )
      return FALSE;
   else
      FT_ptr = token + (strlen(token)-2);
 
   if( strchr(slashPtr+1, 'P' ) != NULL )
      Mptr->RRVR[ndex].above_max_RVR = TRUE;
 
   if( strchr(slashPtr+1, 'M' ) != NULL )
      Mptr->RRVR[ndex].below_min_RVR = TRUE;
 
 
   strncpy(Mptr->RRVR[ndex].runway_designator, token+1,
           (slashPtr-(token+1)));
 
   if( (vPtr = strchr(slashPtr, 'V' )) != NULL )
   {
      Mptr->RRVR[ndex].vrbl_visRange = TRUE;
      Mptr->RRVR[ndex].Min_visRange = antoi(slashPtr+1,
                              (vPtr-(slashPtr+1)) );
      Mptr->RRVR[ndex].Max_visRange = antoi(vPtr+1,
                              (FT_ptr - (vPtr+1)) );
      (*NDEX)++;
      return TRUE;
   }
   else
   {
      if( Mptr->RRVR[ndex].below_min_RVR ||
          Mptr->RRVR[ndex].above_max_RVR    )
         Mptr->RRVR[ndex].visRange = antoi(slashPtr+2,
                           (FT_ptr - (slashPtr+2)) );
      else
         Mptr->RRVR[ndex].visRange = antoi(slashPtr+1,
                           (FT_ptr - (slashPtr+1)) );
 
      (*NDEX)++;
      return TRUE;
   }
 
}
 
 
/********************************************************************/
/*                                                                  */
/*  Title:         isAltimStng                                      */
/*  Organization:  W/OSO242 - GRAPHICS AND DISPLAY SECTION          */
/*  Date:          15 Sep 1994                                      */
/*  Programmer:    CARL MCCALLA                                     */
/*  Language:      C/370                                            */
/*                                                                  */
/*  Abstract:                                                       */
/*                                                                  */
/*  External Functions Called:                                      */
/*                 None.                                            */
/*                                                                  */
/*  Input:         x                                                */
/*                                                                  */
/*  Output:        x                                                */
/*                                                                  */
/*  Modification History:                                           */
/*                 None.                                            */
/*                                                                  */
/********************************************************************/
 
static ubool isAltimStng( char *token, Decoded_METAR *Mptr, int *NDEX )
{

  int val;
  char tmpstr[8];

  // ubool foundQA = FALSE; 
  
  if(token == NULL) {
    return FALSE;
  }
  if( strlen(token) < 5 ) {
    return FALSE;
  }
  if( (*token != 'A' && *token != 'Q')) {
    return FALSE;
  }

  // special case to decode Q&A when given: Q1007(A2974)
  if (token[0] == 'Q' && token[6] == 'A')
    {
      char QAstr[strlen(token)+1];
      strcpy(QAstr,token);
      QAstr[5] = '\0';
      QAstr[11] = '\0';
      if (sscanf(QAstr+1, "%d", &val) == 1) {
	Mptr->Q_altstng = TRUE;
	Mptr->hectoPasc_altstng = val;
      } else {
	return FALSE;
      }
      if (sscanf(QAstr+7, "%d", &val) == 1) {
	Mptr->A_altstng = TRUE;
	Mptr->inches_altstng = val * 0.01;
      } else {
	return FALSE;
      }
      return TRUE;
    }

  memset(tmpstr, '\0', 8);
  STRncopy(tmpstr, token, 8);
  
  if(strlen(tmpstr) > 5) {
    tmpstr[5] = '\0';
  }
  Mptr->A_altstng = FALSE;
  Mptr->Q_altstng = FALSE;
  
  if( *tmpstr == 'A' ) {
    
    if (sscanf(tmpstr+1, "%d", &val) == 1) {
      Mptr->A_altstng = TRUE;
      Mptr->inches_altstng = val * 0.01;
    } else {
      return FALSE;
    }

   } else {
     
     if (sscanf(tmpstr+1, "%d", &val) == 1) {
       Mptr->Q_altstng = TRUE;
       Mptr->hectoPasc_altstng = val;
     } else {
       return FALSE;
     }

   }
  
  (*NDEX)++;

  if (Mptr->Q_altstng)
    Mptr->inches_altstng = Mptr->hectoPasc_altstng * 29.92 / 1013.0;
  if (Mptr->A_altstng)
    Mptr->hectoPasc_altstng = Mptr->inches_altstng * 1013.0 / 29.92;

  /*
   *
   * Niles : Commented this out on advice from Greg Thompson.
   * This is properly decoded elsewhere.
   *
  if ((Mptr->A_altstng) || (Mptr->Q_altstng))
    Mptr->SLP = Mptr->hectoPasc_altstng;
    */

  return TRUE;

}
 
 
/********************************************************************/
/*                                                                  */
/*  Title:         isTempGroup                                      */
/*  Organization:  W/OSO242 - GRAPHICS AND DISPLAY SECTION          */
/*  Date:          15 Sep 1994                                      */
/*  Programmer:    CARL MCCALLA                                     */
/*  Language:      C/370                                            */
/*                                                                  */
/*  Abstract:                                                       */
/*                                                                  */
/*  External Functions Called:                                      */
/*                 None.                                            */
/*                                                                  */
/*  Input:         x                                                */
/*                                                                  */
/*  Output:        x                                                */
/*                                                                  */
/*  Modification History:                                           */
/*                 None.                                            */
/*                                                                  */
/********************************************************************/
 
static ubool isTempGroup( char *token, Decoded_METAR *Mptr, int *NDEX)
{
 
   /***************************/
   /* DECLARE LOCAL VARIABLES */
   /***************************/
 
   char *slash;
 
 
   if( (slash = strchr(token,'/')) == NULL)
      return FALSE;
   else
   {
            /******************/
            /* CASE 1 (XX/YY) */
            /******************/
      if( nisdigit(token,(slash-token)) &&
                    *(slash+1) != '\0' &&
           nisdigit(slash+1,strlen(slash+1)) )
      {
         Mptr->temp = antoi(token,(slash-token));
         Mptr->dew_pt_temp = atoi(slash+1);
         (*NDEX)++;
         return TRUE;
      }
            /********************/
            /* CASE 2 (MXX/MYY) */
            /********************/
      else if( *token == 'M' && nisdigit(token+1,(slash-(token+1)))
                && *(slash+1) != '\0' &&
            *(slash+1) == 'M' && nisdigit(slash+2,strlen(slash+2)) )
      {
         Mptr->temp = antoi(token+1,(slash-(token+1))) * -1;
         Mptr->dew_pt_temp = atoi(slash+2) * -1;
         (*NDEX)++;
         return TRUE;
      }
            /*******************/
            /* CASE 3 (MXX/YY) */
            /*******************/
      else if( *token == 'M' && nisdigit(token+1,(slash-(token+1)))
                 && *(slash+1) != '\0' &&
               nisdigit(slash+1,strlen(slash+1)) )
      {
         Mptr->temp = antoi(token+1,(slash-(token+1))) * -1;
         Mptr->dew_pt_temp = atoi(slash+1);
         (*NDEX)++;
         return TRUE;
      }
            /*******************/
            /* CASE 4 (XX/MYY) */
            /*******************/
      else if( nisdigit(token,(slash-(token)))
                 && *(slash+1) != '\0' &&
            *(slash+1) == 'M' && nisdigit(slash+2,strlen(slash+2)) )
      {
         Mptr->temp = antoi(token,(slash-(token)));
         Mptr->dew_pt_temp = atoi(slash+2) * -1;
         (*NDEX)++;
         return TRUE;
      }
            /******************/
            /* CASE 5 (MM/YY) */
            /******************/
      else if( (slash-token ) == 2 &&
                 strncmp( token, "MM", (slash-token) ) == 0 &&
                    *(slash+1) != '\0' &&
                    nisdigit(slash+1,strlen(slash+1)) )
      {
         Mptr->dew_pt_temp = atoi(slash+1);
         (*NDEX)++;
         return TRUE;
      }
            /******************/
            /* CASE 6 (XX/MM) */
            /******************/
      else if( nisdigit(token, (slash-token)) &&
                    *(slash+1) != '\0' &&
                 strcmp( slash+1,"MM") == 0 )
      {
         Mptr->temp = antoi(token,(slash-token));
         (*NDEX)++;
         return TRUE;
      }
            /*******************/
            /* CASE 7 (MM/MYY) */
            /*******************/
      else if( (slash-token ) == 2 &&
                 strncmp( token, "MM", (slash-token) ) == 0 &&
                    *(slash+1) != '\0' && *(slash+1) == 'M' &&
                    nisdigit(slash+2,strlen(slash+2)) )
      {
         Mptr->dew_pt_temp = atoi(slash+2) * -1;
         (*NDEX)++;
         return TRUE;
      }
            /********************/
            /* CASE 8 (MXX/MM ) */
            /********************/
      else if( *token == 'M' &&
               nisdigit(token+1, (slash-(token+1))) &&
                    *(slash+1) != '\0' &&
                 strcmp( slash+1,"MM") == 0 )
      {
         Mptr->temp = antoi(token+1,(slash-(token+1))) * -1;
         (*NDEX)++;
         return TRUE;
      }
            /******************/
            /* CASE 9 (MM/MM) */
            /******************/
      else if( strcmp(token,"MM/MM") == 0 )
      {
         (*NDEX)++;
         return TRUE;
      }
      else
         return FALSE;
   }
 
}
 
/********************************************************************/
/*                                                                  */
/*  Title:         isPresentWX                                      */
/*  Organization:  W/OSO242 - GRAPHICS AND DISPLAY SECTION          */
/*  Date:          15 Sep 1994                                      */
/*  Programmer:    CARL MCCALLA                                     */
/*  Language:      C/370                                            */
/*                                                                  */
/*  Abstract:                                                       */
/*                                                                  */
/*  External Functions Called:                                      */
/*                 None.                                            */
/*                                                                  */
/*  Input:         x                                                */
/*                                                                  */
/*  Output:        x                                                */
/*                                                                  */
/*  Modification History:                                           */
/*                 None.                                            */
/*                                                                  */
/********************************************************************/
 
static ubool isPresentWX( char *token, Decoded_METAR *Mptr,
                        int *NDEX, int *next )
{
/*
   static char *WxSymbols[] = {"BCFG", "BLDU", "BLSA", "BLPY",
          "DRDU", "DRSA", "DRSN", "DZ", "DS", "FZFG", "FZDZ", "FZRA",
          "FG", "FC", "FU", "GS", "GR", "HZ", "IC", "MIFG",
          "PE", "PO", "RA", "SHRA", "SHSN", "SHPE", "SHGS",
          "SHGR", "SN", "SG", "SQ", "SA", "SS", "TSRA",
          "TSSN", "TSPE", "TSGS", "TSGR", "TS", "VA", "VCFG", "VCFC",
          "VCSH", "VCPO", "VCBLDU", "VCBLSA", "VCBLSN", NULL};
*/
   static char *WxSymbols[] = {"BCFG", "BLDU", "BLSA", "BLPY",
          "BLSN","BR", "FZBR", "VCBR", "+FC", "BCFG",
          "DRDU", "DRSA", "DRSN", "DZ", "DS", "FZFG", "FZDZ", "FZRA",
          "FG", "FC", "FU", "GS", "GR", "HZ", "IC", "MIFG",
          "PE", "PO", "RA", "SHRA", "SHSN", "SHPE", "SHGS",
          "SHGR", "SN", "SG", "SQ", "SA", "SS", "TSRA",
          "TSSN", "TSPE", "TSGS", "TSGR", "TS","UP",
          "VA", "VCFG", "VCFC", "VCTS", "VCSS", "VCDS", "PRFG",
	  "VCSH", "VCPO", "VCBLDU", "VCBLSA", "VCBLSN", "DU", "SA", 
          "SS", NULL};

   int i;
   char *ptr,
        *temp_token,
        *save_token;

   char token_buf[128];
 
   if (strlen(token) > 127) return FALSE;
   strcpy(token_buf, token);
   temp_token = token_buf;
   while( temp_token != NULL && (*next) < MAXWXSYMBOLS )
   {
      i = 0;
      save_token = NULL;
 
      if( *temp_token == '+' || *temp_token == '-' )
      {
         save_token = temp_token;
         temp_token++;
      }
 
      while( WxSymbols[i] != NULL )
         if( strncmp(temp_token, WxSymbols[i],
               strlen(WxSymbols[i])) != 0 )
            i++;
         else
            break;
 
      if( WxSymbols[i] == NULL ) {
         return FALSE;
      }
      else
      {
 
         if( save_token != NULL )
         {
            strncpy( Mptr->WxObstruct[*next], save_token, 1);
            strcpy( (Mptr->WxObstruct[*next])+1,
                              WxSymbols[i]);
            (*next)++;
         }
         else
         {
            strcpy( Mptr->WxObstruct[*next], WxSymbols[i]);
            (*next)++;
         }
 
 
         if( strcmp(temp_token, WxSymbols[i]) != 0)
         {
            ptr = strstr(temp_token, WxSymbols[i]);
            temp_token = ptr + strlen(WxSymbols[i]);
         }
         else
         {
            temp_token = NULL;
         }
 
      }
 
   }
 
   (*NDEX)++;
   return TRUE;
 
}
 
/********************************************************************/
/*                                                                  */
/*  Title:         isStnID                                          */
/*  Organization:  W/OSO242 - GRAPHICS AND DISPLAY SECTION          */
/*  Date:          15 Sep 1994                                      */
/*  Programmer:    CARL MCCALLA                                     */
/*  Language:      C/370                                            */
/*                                                                  */
/*  Abstract:                                                       */
/*                                                                  */
/*  External Functions Called:                                      */
/*                 None.                                            */
/*                                                                  */
/*  Input:         x                                                */
/*                                                                  */
/*  Output:        x                                                */
/*                                                                  */
/*  Modification History:                                           */
/*                 None.                                            */
/*                                                                  */
/********************************************************************/
 
static ubool isStnId( char *stnID, Decoded_METAR *Mptr, int *NDEX)
{
   if( strlen(stnID) == 4 && nisalnum(stnID, 4) )
   {
      strcpy(Mptr->stnid,stnID);
      (*NDEX)++;
      return TRUE;
   }
   else
      return FALSE;
 
}
 
/********************************************************************/
/*                                                                  */
/*  Title:         isCodeName                                       */
/*  Organization:  W/OSO242 - GRAPHICS AND DISPLAY SECTION          */
/*  Date:          15 Sep 1994                                      */
/*  Programmer:    CARL MCCALLA                                     */
/*  Language:      C/370                                            */
/*                                                                  */
/*  Abstract:                                                       */
/*                                                                  */
/*  External Functions Called:                                      */
/*                 None.                                            */
/*                                                                  */
/*  Input:         x                                                */
/*                                                                  */
/*  Output:        x                                                */
/*                                                                  */
/*  Modification History:                                           */
/*                 None.                                            */
/*                                                                  */
/********************************************************************/
 
static ubool isCodeName( char *codename, Decoded_METAR *Mptr, int *NDEX)
{
   if( strcmp(codename,"METAR") == 0 ||
       strcmp(codename,"SPECI") == 0   )
   {
      strcpy(Mptr->codeName, codename );
      (*NDEX)++;
      return TRUE;
   }
   else
      return FALSE;
 
}
 
 
/********************************************************************/
/*                                                                  */
/*  Title:         isNIL                                            */
/*  Organization:  W/OSO242 - GRAPHICS AND DISPLAY SECTION          */
/*  Date:          15 Sep 1994                                      */
/*  Programmer:    CARL MCCALLA                                     */
/*  Language:      C/370                                            */
/*                                                                  */
/*  Abstract:                                                       */
/*                                                                  */
/*  External Functions Called:                                      */
/*                 None.                                            */
/*                                                                  */
/*  Input:         x                                                */
/*                                                                  */
/*  Output:        x                                                */
/*                                                                  */
/*  Modification History:                                           */
/*                 None.                                            */
/*                                                                  */
/********************************************************************/
 
static ubool isNIL( char *token, Decoded_METAR *Mptr, int *NDEX)
{
   if( strcmp(token, "NIL") == 0 )
   {
      Mptr->NIL_rpt = TRUE;
      (*NDEX)++;
      return TRUE;
   }
   else
      return FALSE;
 
}
 
/********************************************************************/
/*                                                                  */
/*  Title:         isAUTO                                           */
/*  Organization:  W/OSO242 - GRAPHICS AND DISPLAY SECTION          */
/*  Date:          15 Sep 1994                                      */
/*  Programmer:    CARL MCCALLA                                     */
/*  Language:      C/370                                            */
/*                                                                  */
/*  Abstract:                                                       */
/*                                                                  */
/*  External Functions Called:                                      */
/*                 None.                                            */
/*                                                                  */
/*  Input:         x                                                */
/*                                                                  */
/*  Output:        x                                                */
/*                                                                  */
/*  Modification History:                                           */
/*                 None.                                            */
/*                                                                  */
/********************************************************************/
 
static ubool isAUTO( char *token, Decoded_METAR *Mptr, int *NDEX)
{
   if( strcmp(token, "AUTO") == 0 )
   {
      Mptr->AUTO = TRUE;
      (*NDEX)++;
      return TRUE;
   }
   else
      return FALSE;
 
}
 
/********************************************************************/
/*                                                                  */
/*  Title:         isCOR                                            */
/*  Organization:  W/OSO242 - GRAPHICS AND DISPLAY SECTION          */
/*  Date:          20 Nov 1995                                      */
/*  Programmer:    CARL MCCALLA                                     */
/*  Language:      C/370                                            */
/*                                                                  */
/*  Abstract:                                                       */
/*                                                                  */
/*  External Functions Called:                                      */
/*                 None.                                            */
/*                                                                  */
/*  Input:         x                                                */
/*                                                                  */
/*  Output:        x                                                */
/*                                                                  */
/*  Modification History:                                           */
/*                 None.                                            */
/*                                                                  */
/********************************************************************/
 
static ubool isCOR( char *token, Decoded_METAR *Mptr, int *NDEX)
{
   if( strcmp(token, "COR") == 0 )
   {
      Mptr->COR = TRUE;
      (*NDEX)++;
      return TRUE;
   }
   else
      return FALSE;
 
}
/********************************************************************/
/*                                                                  */
/*  Title:         isTimeUTC                                        */
/*  Organization:  W/OSO242 - GRAPHICS AND DISPLAY SECTION          */
/*  Date:          15 Sep 1994                                      */
/*  Programmer:    CARL MCCALLA                                     */
/*  Language:      C/370                                            */
/*                                                                  */
/*  Abstract:                                                       */
/*                                                                  */
/*  External Functions Called:                                      */
/*                 None.                                            */
/*                                                                  */
/*  Input:         x                                                */
/*                                                                  */
/*  Output:        x                                                */
/*                                                                  */
/*  Modification History:                                           */
/*                 None.                                            */
/*                                                                  */
/********************************************************************/
 
static ubool isTimeUTC( char *UTC, Decoded_METAR *Mptr, int *NDEX )
{
   if( strlen( UTC ) == 5 &&
       (nisdigit(UTC,4) && (*(UTC+4) == 'Z')) )
   {
      Mptr->ob_hour = antoi(UTC,2);
      Mptr->ob_minute = antoi(UTC+2,2);
      (*NDEX)++;
      return TRUE;
   }
   else if( strlen( UTC ) == 7 &&
            (nisdigit(UTC,6) && (*(UTC+6) == 'Z')) )
   {
      Mptr->ob_date = antoi(UTC,2);
 
      Mptr->ob_hour = antoi(UTC+2, 2);
      Mptr->ob_minute = antoi(UTC+4, 2 );
      (*NDEX)++;
 
      return TRUE;
   }
   else
      return FALSE;
}
 
 
/********************************************************************/
/*                                                                  */
/*  Title:         isWindData                                       */
/*  Organization:  W/OSO242 - GRAPHICS AND DISPLAY SECTION          */
/*  Date:          15 Sep 1994                                      */
/*  Programmer:    CARL MCCALLA                                     */
/*  Language:      C/370                                            */
/*                                                                  */
/*  Abstract:                                                       */
/*                                                                  */
/*  External Functions Called:                                      */
/*                 None.                                            */
/*                                                                  */
/*  Input:         x                                                */
/*                                                                  */
/*  Output:        x                                                */
/*                                                                  */
/*  Modification History:                                           */
/*                 None.                                            */
/*                                                                  */
/********************************************************************/
 
/* Original version  **********************************************

static ubool isWindData( char *wind, Decoded_METAR *Mptr, int *NDEX )
{
 
   char *GustPtr,
        *unitsPtr;
 
Modifed version P.Neilley 7/96, Handles Estimated winds  
Modified version M.Dixon 3/99, cleaned up, checks added.
****************************************************************** */

static ubool isWindData( char *windptr, Decoded_METAR *Mptr, int *NDEX )
{
 
   char *GustPtr, *wind, *unitsPtr, *endPtr;

   /*
    * basic failure
    */
   
   if (windptr == NULL) {
     return FALSE;
   }

   if (strlen(windptr) < 6) {
     return FALSE;
   }

   /*
    * check for estimated wind
    */

   wind = windptr;
   if ( strncmp(wind,"E",1) == 0 ) {
     wind++;
     Mptr->winData.windEstimated = TRUE;
   } else {
     Mptr->winData.windEstimated = FALSE;
   }

   /* 
    * set units
    */
   
   if( ( unitsPtr = strstr( wind, "KMH" ) ) != NULL ) {
     strcpy( Mptr->winData.windUnits, "KMH" );
   } else if( (unitsPtr = strstr( wind, "KT") ) != NULL ) {
     strcpy( Mptr->winData.windUnits, "KT" );
   } else if( (unitsPtr = strstr( wind, "MPS") ) != NULL ) {
     strcpy( Mptr->winData.windUnits, "MPS" );
   } else {
     return FALSE;
   }

   /*
    * is gust included?
    */
   
   if((GustPtr = strchr( wind, 'G' )) != NULL ) {
     endPtr = GustPtr;
     if (unitsPtr-(GustPtr+1) < 2) return FALSE;
     if (unitsPtr-(GustPtr+1) > 3) return FALSE;
     if (!nisdigit(GustPtr+1,(unitsPtr-(GustPtr+1)))) return FALSE;
     Mptr->winData.windGust = antoi(GustPtr+1,(unitsPtr- (GustPtr+1)));
   } else {
     Mptr->winData.windGust = 0;
     endPtr = unitsPtr;
   }

   if (endPtr-wind < 5) return FALSE;
   if (endPtr-wind > 6) return FALSE;

   if (nisdigit(wind, endPtr-wind)) {

     Mptr->winData.windSpeed = antoi(wind+3, endPtr-(wind+3));
     Mptr->winData.windDir = antoi(wind,3);

   } else if (strncmp(wind,"VRB",3) == 0 &&
	      nisdigit(wind+3, endPtr-(wind+3))) {
     
     Mptr->winData.windSpeed = antoi(wind+3, endPtr-(wind+3));
     Mptr->winData.windVRB = TRUE;
     Mptr->winData.windDir = 0;
     
   } else {
     
     return FALSE;
     
   }

   (*NDEX)++;
   return TRUE;

}

/********************************************************************/
/*                                                                  */
/*  Title:         DcdMETAR                                         */
/*  Organization:  W/OSO242 - GRAPHICS AND DISPLAY SECTION          */
/*  Date:          14 Sep 1994                                      */
/*  Programmer:    CARL MCCALLA                                     */
/*  Language:      C/370                                            */
/*                                                                  */
/*  Abstract:      DcdMETAR takes a pointer to a METAR report char- */
/*                 acter string as input, decodes the report, and   */
/*                 puts the individual decoded/parsed groups into   */
/*                 a structure that has the variable type           */
/*                 Decoded_METAR.                                   */
/*                                                                  */
/*  Input:         string - a pointer to a METAR report character   */
/*                          string.                                 */
/*                 clear_flag - Set to Non Zero to clear out        */
/*                 Decoded_METAR struct.                            */
/*                                                                  */
/*  Output:        Mptr   - a pointer to a structure that has the   */
/*                          variable type Decoded_METAR.            */
/*                                                                  */
/*  Modification History:                                           */
/*                Added clear_flag to optionally reset metar struct */
/*                F. Hage - NCAR.                                   */
/*                                                                  */
/********************************************************************/
 
 
int DcdMETAR( char *string , Decoded_METAR *Mptr,int  clear_flag)
{
 
   /***************************/
   /* DECLARE LOCAL VARIABLES */
   /***************************/
 
 
   enum METAR_obGroup { codename, stnid, NIL1, obDateTime, NIL2,
                        AUTO, COR, windData, MinMaxWinDir, visibility,
                        RVR, presentWX, PartialObscur,
                        skyCond, tempGroup,
                        altimStng, NotIDed = 99 }
     StartGroup = NotIDed,
     SaveStartGroup = NotIDed,
     MetarGroup = NotIDed;
 
 
   int    ndex,
          NDEX,
          skyCondRet;
 
 
   char   **token,
          *delimiters = {" \n\t\r"};
 
 
 
/*********************************/
/* BEGIN THE BODY OF THE ROUTINE */
/*********************************/
 
   /********************************************************/
   /* ONLY PARSE OR DECOCODE NON-NULL METAR REPORT STRINGS */
   /********************************************************/
 

   if( string == NULL )
      return 8;
 
 
   /*****************************************/
   /*   INITIALIZE STRUCTURE THAT HAS THE   */
   /*      VARIABLE TYPE Decoded_METAR      */
   /*****************************************/
 

   if(clear_flag != 0) {
       InitDcdMETAR( Mptr );
    } else {
       {               /* Only clear out the weather strings */
       int i;
       for ( i = 0; i < MAXWXSYMBOLS; i++ ) memset( Mptr->WxObstruct[i], '\0', 8);
       }
    }

 
 
   /****************************************************/
   /* TOKENIZE AND STORE THE INPUT METAR REPORT STRING */
   /****************************************************/
 
   /* Don't return without free'ing the tokens! - FH. */
   token = SaveTokenString( string, delimiters );
 
#ifdef  PRTOKEN
   printf("\n\nFROM DcdMETAR:  Print TOKEN list...\n\n");
   NDEX = 0;
   while( token[NDEX] != NULL ) {
      printf("Token[%d] = %s\n",NDEX,token[NDEX]);
      NDEX++;
   }
#endif
   /*********************************************************/
   /* DECODE THE METAR REPORT (POSITIONAL ORDER PRECEDENCE) */
   /*********************************************************/
 
   
   MetarGroup = codename;
 
   NDEX = 0;
   while(NDEX < MAXTOKENS && token[NDEX] != NULL &&
            (strcmp( token[NDEX], "RMK" )     != 0 &&
             strcmp( token[NDEX], "RMRK" )    != 0 &&
             strcmp( token[NDEX], "REMARK" )  != 0 &&
             strcmp( token[NDEX], "REMARKS" ) != 0  ) ) {

      StartGroup = NotIDed;
 
      /**********************************************/
      /* SET ID_break_CODE TO ITS DEFAULT VALUE OF  */
      /* 99, WHICH MEANS THAT NO SUCCESSFUL ATTEMPT */
      /* WAS MADE TO DECODE ANY METAR CODED GROUP   */
      /* FOR THIS PASS THROUGH THE DECODING LOOP    */
      /**********************************************/
 
      switch( MetarGroup ) {

         case( codename ):
            if( token[NDEX] && isCodeName( token[NDEX], Mptr, &NDEX ) ) {
               SaveStartGroup = StartGroup = codename;
               MetarGroup = stnid;
            }
            else
               MetarGroup = stnid;
            break;
         case( stnid ):
            if( token[NDEX] && isStnId( token[NDEX], Mptr, &NDEX ) ) {
               SaveStartGroup = StartGroup = stnid;
               MetarGroup = obDateTime;
            }
            else {
               freeTokens( token );
               return 12;
            }
            break;
         case( NIL1 ):
            if( token[NDEX] && isNIL( token[NDEX], Mptr, &NDEX ) ) {
               SaveStartGroup = StartGroup = NIL1;
               MetarGroup = obDateTime;
            }
            else
               MetarGroup = obDateTime;
            break;
         case( obDateTime ):
            if( token[NDEX] && isTimeUTC( token[NDEX], Mptr, &NDEX ) ) {
               SaveStartGroup = StartGroup = obDateTime;
               MetarGroup = NIL2;
            }
            else
               MetarGroup = NIL2;
            break;
         case( NIL2 ):
            if( token[NDEX] && isNIL( token[NDEX], Mptr, &NDEX ) ) {
               SaveStartGroup = StartGroup = NIL2;
               MetarGroup = AUTO;
            }
            else
               MetarGroup = AUTO;
            break;

         case( AUTO ):
            if( token[NDEX] && isAUTO( token[NDEX], Mptr, &NDEX ) ) {
               SaveStartGroup = StartGroup = AUTO;
               MetarGroup = COR;
            }
            else
               MetarGroup = COR;
            break;
         case( COR ):
            if( token[NDEX] && isCOR( token[NDEX], Mptr, &NDEX ) ) {
               SaveStartGroup = StartGroup = COR;
               MetarGroup = windData;
            }
            else
               MetarGroup = windData;
            break;
         case( windData ):
            if( token[NDEX] && isWindData( token[NDEX], Mptr, &NDEX ) ) {
               SaveStartGroup = StartGroup = windData;
               MetarGroup = MinMaxWinDir;
            }
            else
               MetarGroup = MinMaxWinDir;
            break;
         case( MinMaxWinDir ):
            if( token[NDEX] && isMinMaxWinDir( token[NDEX], Mptr, &NDEX ) ) {
               SaveStartGroup = StartGroup = MinMaxWinDir;
               MetarGroup = visibility;
            }
            else
               MetarGroup = visibility;
            break;
         case( visibility ):
            if( token[NDEX] && isVisibility( &(token[NDEX]), Mptr, &NDEX ) ) {
               SaveStartGroup = StartGroup = visibility;
               MetarGroup = RVR;
            }
            else
               MetarGroup = presentWX;
            break;
         case( RVR ):
            ndex = 0;
            MetarGroup = presentWX;
 
            while (token[NDEX] && isRVR( token[NDEX], Mptr, &NDEX, ndex ) &&
                               ndex < 12 ) {
               ndex++;
               SaveStartGroup = StartGroup = RVR;
               MetarGroup = presentWX;
            }
            break;

         case( presentWX ):
            ndex = 0;
            MetarGroup = skyCond;
 
            while( token[NDEX] && isPresentWX( token[NDEX], Mptr, &NDEX,
                          &ndex ) && ndex < MAXWXSYMBOLS) {
               SaveStartGroup = StartGroup = presentWX;
               MetarGroup = PartialObscur;
            }
            break;

         case( PartialObscur ):
            if( token[NDEX] && isPartObscur( &(token[NDEX]), Mptr, &NDEX ) ) {
               SaveStartGroup = StartGroup = PartialObscur;
               MetarGroup = skyCond;
            }
            else
               MetarGroup = skyCond;
            break;

         case( skyCond ):
	   if (token[NDEX] == NULL) {
	     freeTokens( token );
	     return 12;
	   }
            skyCondRet = isSkyCond( &(token[NDEX]), Mptr, &NDEX );
            if( skyCondRet == 1 ) {
               SaveStartGroup = StartGroup = skyCond;
               MetarGroup = tempGroup;
            } 
            else if( skyCondRet == 0 )
	       MetarGroup = tempGroup;
            else {
               freeTokens( token );
               return 12;
            }
            break;

         case( tempGroup ):
            if( token[NDEX] && isTempGroup( token[NDEX], Mptr, &NDEX ) ) {
               SaveStartGroup = StartGroup = tempGroup;
               MetarGroup = altimStng;
            }
            else
               MetarGroup = altimStng;
            break;
         case( altimStng ):
            if( token[NDEX] && isAltimStng( token[NDEX], Mptr, &NDEX ) ) {
               SaveStartGroup = StartGroup = altimStng;
               MetarGroup = NotIDed;
            }
            else
               MetarGroup = NotIDed;
            break;

         default:
            NDEX++;
            MetarGroup = ResetMETARGroup( StartGroup,
                                          SaveStartGroup );
            break;
      }
 
#ifdef  PRTOKEN
   printf("\n\nFROM DcdMETAR:  Print Decoded METAR...\n\n");
   prtDMETR( Mptr );
#endif
 
   }
 
                                     /******************************/
                                     /* DECODE GROUPS FOUND IN THE */
                                     /*  REMARKS SECTION OF THE    */
                                     /*       METAR REPORT         */
                                     /******************************/

#ifdef  PRTOKEN
   printf("\n\nPrior to Decision whether or "
            "not to call DcdMTRmk...\n");
   printf("\n\nFROM DcdMETAR:  Current token[%d] = %s\n\n",NDEX,
               token[NDEX]);
#endif

   if( NDEX < MAXTOKENS && ( token[NDEX] != NULL ) &&
       ( strcmp( token[NDEX], "RMK" )     == 0 ||
         strcmp( token[NDEX], "RMRK" )    == 0 ||
         strcmp( token[NDEX], "REMARK" )  == 0 ||
         strcmp( token[NDEX], "REMARKS" ) == 0 )  )
     DcdMTRmk( token, Mptr ); 

#ifdef  PRTOKEN
   printf("\n\nFollowing decision whether or "
            "not to call DcdMTRmk...\n");
   prtDMETR( Mptr );
#endif
 
                           /****************************************/
   freeTokens( token );    /* FREE THE STORAGE ALLOCATED FOR THE   */
                           /* ARRAY USED TO HOLD THE METAR REPORT  */
                           /*                GROUPS                */
                           /****************************************/
   return 0;
 
}