[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GEMPAK #MMY-409918]: gpwarn segmentation fault



Brendon,

I've had to modify one of the cgemlib rounties in order to fix this problem.  
I've attached the updated source file so you'll have to compile it and add it 
to cgemlib.

So two steps are needed, the first to fix the seg fault, the second to fix the 
path truncation.

The first attached file is clowhich.c

* Save it to $GEMPAK/source/cgemlib/clo/ (you may want to backup the previous 
version to clowhich.c.orig)
* Assuming your environmental variables are correct (from sourcing Gemenviron), 
in that directory type "make all"
* You will now have an object file clowhich.o
* Add/replace the object file in the cgemlib library: type "ar -r 
$OS_LIB/cgemlib.a clowhich.o"

now to fix the truncation error:

The second attached file is read_bull.c

* Save it to $NAWIPS/unidata/programs/gpwarn/ (you may want to backup the 
previous version to read_bull.c.orig)
* In the same directory type "make all" and then "make install"

After this, try to run gpwarn both with WWFIL = nonpcpwarn and with the full 
path, hopefully this will solve both the seg fault and the truncation problems.

Please let me know if you run into any snags.

Michael James
Unidata User Support


> Hi Brendon,
> 
> Still investigating this one for you.
> 
> Discovered that when the full path name is specified 
> (WWFIL=/home/data/gempak/nwx/watch_warn/NPW/2009051814.NPW) it becomes 
> truncated after 20 characters.  I have fixed this but am still trying to 
> pin-point the source of the segmentation fault.  When I do I will send you 
> the new source file to recompile and I'll wrap the change into the current 
> 5.11.4 source distribution.
> 
> Best,
> 
> Michael James
> Unidata User Support
> 
> 
> > Hello,
> >
> > I'm getting a segmentation fault any time I try to plot a graphic with
> > GPWARN using
> >
> > WWFIL=nonpcpwarn
> >
> > I'm able to plot other types of watches successfully.  I tried cat'ing
> > everything in the NPW directory to a single file, and specifying the
> > path in WWFIL, but I still get a fault, making me wonder if the program
> > is choking on something that was ingested.  At first, I thought this was
> > a one-time bug, as it happened last week, but now after scouring, it's
> > happening again on newer files.
> >
> > If I specify an individual file:
> >
> > WWFIL=/home/data/gempak/nwx/watch_warn/NPW/2009051814.NPW
> >
> > I get no fault, but I do not see the frost/freeze warnings that I would
> > like to plot either.
> >
> > Thanks,
> > Brendon
> > --
> > Brendon Hoch
> > Technology Manager
> > Judd Gregg Meteorology Institute
> > MSC 48, Boyd Hall 321A
> > Plymouth State University
> > Plymouth, NH 03264
> > (603)535-2818 Fax: (603)535-2723
> > http://vortex.plymouth.edu/~bhoch
> >
> >
> 


Ticket Details
===================
Ticket ID: MMY-409918
Department: Support GEMPAK
Priority: Normal
Status: Open
#include "geminc.h"
#include "gemprm.h"
#include "clocmn.h"

extern  CLO_t   clo;

int clo_which ( char *type )
/************************************************************************
 * clo_which                                                            *
 *                                                                      *
 * This function returns an integer pointer into the master CLO         *
 * structure indicating which entry matches the input CLO name.         *
 *                                                                      *
 * int clo_which ( type )                                               *
 *                                                                      *
 * Input parameters:                                                    *
 *      *type           char            Name of CLO parameter           *
 *                                                                      *
 * Output parameters:                                                   *
 *      clo_which       int             Return value                    *
 *                                      =  < 0 - no match               *
 *                                                                      *
 **                                                                     *
 * Log:                                                                 *
 * D.W.Plummer/NCEP      1/00   Create                                  *
 * M.James/Unidata       5/09   Changed clo.nloc to clo.nloc+1          *
 ***********************************************************************/
{
int     which;
/*---------------------------------------------------------------------*/

        which = 0;

        while ( which < clo.nloc+1 ) {
            if ( strcmp( type, clo.loc[which].name ) == 0 )  
                return ( which );
            which++;
        }

        return ( -1 );

}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <clocmn.h>

#include "geminc.h"
#include "gemprm.h"

#include "gpwarn.h"


#ifdef UNDERSCORE
#define gline           gline_
#define gfill           gfill_
#define gscolr          gscolr_
#define gsline          gsline_
#define ti_mdif         ti_mdif_

#define read_bull       read_bull_
#define text_output     text_output_
#define gpwarn_color_init       gpwarn_color_init_
#endif

/* global time for plotting valid watches */
char valid[13];

char t_outstr[132];

int CLASS;
int PIL;

FILE *fp;

int PRIOR,FUTURE,ADVANCE;

int *outluns, *outnlun;

gpwarn_config_type gpwarn_config[NUMTYP];
 

/*****************************************************************************/
/* 20020912: function for initializing and reading gpwarn color/line attr.   */
/*  - takes array of gpwarn_config_type, sets defaults, and attempts to find */
/*  - and replace values from some gpwarn.config file.                       */
/*  - No return (void).                                                      */
void gpwarn_read_config(gpwarn_config_type *config)
{

   FILE         *ipf = NULL; /* FILE * for existing gpwarn.config reads  */
   char         *cpos = NULL; /* substring pointer */
   char         new_line[256]; /* each new line read from config file    */
   int          i, lbtid, iarr[10], inum, iret;

   static int   defcolrs[NUMTYP][10] = {
        { 2, 5, 1, 2, 1, 13, 10, 1, 1, 1 },     /* TORNADO */
        { 14, 5, 1, 2, 1, 13, 10, 1, 1, 1 },    /* SEVERE */
        { 4, 5, 1, 2, 1, 26, 10, 1, 1, 1 },     /* WINTER */
        { 6, 5, 1, 2, 1, 24, 26, 1, 1, 1 },     /* SPECIAL */
        { 7, 5, 1, 2, 1, 29, 10, 1, 1, 1 },     /* NONPRCP */
        { 21, 5, 1, 2, 1, 19, 18, 1, 1, 1 },    /* FWATCH */
        { 23, 5, 1, 2, 1, 19, 18, 1, 1, 1 },    /* FWARN */
        { 21, 5, 1, 2, 1, 19, 18, 1, 1, 1 },    /* FSTATE */
        { 2, 2, 1, 2, 1, 13, 10, 1, 1, 1 },     /* HURRS */
        { 5, 2, 1, 2, 1, 1, 1, 1, 1, 2 },       /* SLSTSTM */
        { 13, 5, 1, 2, 1, 1, 1, 1, 1, 2 },      /* SLSTORN */
        { 23, 5, 1, 2, 1, 1, 1, 1, 1, 2 }       /* SLSFFW */
        };

        /* 
         * Set default colors 
         */
        for ( i = 0; i < NUMTYP; i++ ) {
           config[i].current_fill_color = defcolrs[i][0];
           config[i].current_line_color = defcolrs[i][1];
           config[i].current_line_type = defcolrs[i][2];
           config[i].current_line_width = defcolrs[i][3];
           config[i].current_fill_type = defcolrs[i][4];
           config[i].expired_fill_color = defcolrs[i][5];
           config[i].expired_line_color = defcolrs[i][6];
           config[i].expired_line_type = defcolrs[i][7];
           config[i].expired_line_width = defcolrs[i][8];
           config[i].expired_fill_type = defcolrs[i][9];
        }



        /* 
         * Open config file, if exists
         */
        ipf = cfl_tbop ( "gpwarn.config", "unidata", &iret );
        if(iret != 0) return;


        /*
         * Load config file values
         */
        while ((fgets(new_line, (sizeof(new_line) - 1), ipf)) != NULL) {
                if (new_line[0] == '#') continue;

                if ((cpos = strchr(new_line, ':')) != NULL) {
                        if(new_line[strlen(new_line) - 1] == '\n')
                           new_line[strlen(new_line) - 1] = '\0';
                        cpos[0] = '\0';
                        if(strcmp(new_line,"TORNADO") == 0)
                                lbtid = TORNADO;
                        else if (strcmp(new_line,"SEVERE") == 0)
                                lbtid = SEVERE;
                        else if (strcmp(new_line,"WINTER") == 0)
                                lbtid = WINTER;
                        else if (strcmp(new_line,"SPECIAL") == 0)
                                lbtid = SPECIAL;
                        else if (strcmp(new_line,"NONPRCP") == 0)
                                lbtid = NONPRCP;
                        else if (strcmp(new_line,"FWATCH") == 0)
                                lbtid = FWATCH;
                        else if (strcmp(new_line,"FWARN") == 0)
                                lbtid = FWARN;
                        else if (strcmp(new_line,"FSTATE") == 0)
                                lbtid = FSTATE;
                        else if (strcmp(new_line,"HURRS") == 0)
                                lbtid = HURRS;
                        else if (strcmp(new_line,"SLSTSTM") == 0)
                                lbtid = SLSTSTM;
                        else if (strcmp(new_line,"SLSTORN") == 0)
                                lbtid = SLSTORN;
                        else if (strcmp(new_line,"SLSFFW") == 0)
                                lbtid = SLSFFW;
                        else
                                lbtid = -1;

                        if ( lbtid != -1 ) {
                              cpos++;
                              cst_ilst ( cpos, ':', 1, 10, iarr, &inum, &iret);
                              config[lbtid].current_fill_color = iarr[0];
                              config[lbtid].current_line_color = iarr[1];
                              config[lbtid].current_line_type = iarr[2];
                              config[lbtid].current_line_width = iarr[3];
                              config[lbtid].current_fill_type = iarr[4];
                              config[lbtid].expired_fill_color = iarr[5];
                              config[lbtid].expired_line_color = iarr[6];
                              config[lbtid].expired_line_type = iarr[7];
                              config[lbtid].expired_line_width = iarr[8];
                              config[lbtid].expired_fill_type = iarr[9];
                        }
                                
                }
        }
        fclose(ipf);
        return;
}
/*****************************************************************************/

int is_valid(char *expires, int *isval)
/**********************************************************************
*  This subroutine determines the time difference between the bulletin
*  expiration time, and the plot valid time (current or user selected).
*  If the bulletin expiration time is not set, the subroutine returns
*  -1, otherwise the return value from ti_mdif is returned.
*  A time difference < 0 signifies the bulletin has expired.
***********************************************************************/
{
int iexpire[5],ivalid[5];
int ier,i,idif;

if(expires[0] == '\0') return(-1);

if(strcmp(expires,"DDHHMM") == 0) return(-1);

sscanf(valid,"%2d%2d%2d/%2d%2d",ivalid,ivalid+1,ivalid+2,ivalid+3,ivalid+4); 
iexpire[0] = ivalid[0];
iexpire[1] = ivalid[1];
ier = sscanf(expires,"%2d%2d%2d",iexpire+2,iexpire+3,iexpire+4);
if(ier < 3)
   {
   printf("Invalid expiration %s\n",expires);
   return(-1);
   }

if((iexpire[2] < 3)&&(ivalid[2] > 26))
   {
   iexpire[1] += 1;
   if(iexpire[1] > 12)
      {
      iexpire[1] = 1;
      iexpire[0] += 1;
      }
   }

if((ivalid[2] < 3)&&(iexpire[2] > 26))
   {
   iexpire[1] -= 1;
   if(iexpire[1] < 1)
      {
      iexpire[1] = 12;
      iexpire[0] -= 1;
      }
   }

ti_mdif(iexpire,ivalid,&idif,&ier);
*isval = idif;
return(ier);
}




void get_map(char *zone, char *expires)
/**********************************************************************
*  This subroutine draws the filled county/zone area for a given
*  identifier. The line and fill colors are predefined for several
*  known types, otherwise a default combination is used. Plotting
*  attributes are determined based on the expiration time of the
*  bulletin (Expired, Valid, Valid but outside disired plot window).
***********************************************************************/
{
int isval;
int i,TYPE;

int iret;

int FCOLOR, OCOLOR, LTYPE, LWIDTH, FTYPE;
int cur_fil, cur_lin, cur_ltype, cur_lwidth, cur_ftyp;
int exp_fil, exp_lin, exp_ltype, exp_lwidth, exp_ftyp;
static int oth_fil = 1, oth_lin = 30;


/* return if can't determine valid time */
if(is_valid(expires,&isval) == -1) return;

/* return if bulletin is expired, and outside plot range */
if((isval < 0)&&(-isval > PRIOR)) return;
if((isval > FUTURE)&&(ADVANCE == 1)) return;


/* determine plot color values */

switch(CLASS)
{
  case TORNADO:
  case SEVERE:
  case WINTER:
  case SPECIAL:
  case NONPRCP:
  case FWATCH:
  case FWARN:
  case FSTATE:
  case HURRS:
        {
        cur_fil = gpwarn_config[CLASS].current_fill_color;
        cur_lin = gpwarn_config[CLASS].current_line_color;
        cur_ltype = gpwarn_config[CLASS].current_line_type;
        cur_lwidth = gpwarn_config[CLASS].current_line_width;
        cur_ftyp = gpwarn_config[CLASS].current_fill_type;
        exp_fil = gpwarn_config[CLASS].expired_fill_color;
        exp_lin = gpwarn_config[CLASS].expired_line_color;
        exp_ltype = gpwarn_config[CLASS].expired_line_type;
        exp_lwidth = gpwarn_config[CLASS].expired_line_width;
        exp_ftyp = gpwarn_config[CLASS].expired_fill_type;
        break;
        }
  default:
        {
        cur_fil = 8;
        cur_lin = 5;
        cur_ltype = 1;
        cur_lwidth = 2;
        cur_ftyp = 1;
        exp_fil = 9;
        exp_lin = 10;
        exp_ltype = 1;
        exp_lwidth = 1;
        exp_ftyp = 1;
        }
}

if (isval < 0) {
   FCOLOR = exp_fil;
   OCOLOR = exp_lin;
   LTYPE = exp_ltype;
   LWIDTH = exp_lwidth;
   FTYPE = exp_ftyp;
}
else if (isval <= FUTURE) {
   FCOLOR = cur_fil;
   OCOLOR = cur_lin;
   LTYPE = cur_ltype;
   LWIDTH = cur_lwidth;
   FTYPE = cur_ftyp;
   }
else {
   FCOLOR = oth_fil;
   OCOLOR = oth_lin;
   LTYPE = 1;
   LWIDTH = 2;
   FTYPE = 1;
}

/* determine bulletin type */
if(zone[2] == 'C')
   TYPE = 0;
else
   if(zone[2] == 'Z')
      {
      TYPE = 1;
      }
   else
      TYPE = -1;


if(TYPE < 0)
   {
   printf("Error in zone string %s\n",zone);
   return;
   }

plot_ugc(TYPE, zone, FCOLOR, OCOLOR, LTYPE, LWIDTH, FTYPE);
}


void do_all(char *zone, int *nzones,zonelist **head)
{
zonelist *zone_list;
int iret,i,bindex;
char srchstr[30],*pos1,*pos2;
extern  CLO_t   clo;

/* read the zone table, if not already */
clo_init(&iret);

bindex = clo_which("ZONE_BNDS");
sprintf(srchstr,"CLASS=%c%c\0",zone[0],zone[1]);

/* find all zones in this state */
for(i=0;i<clo.loc[bindex].bnd.nbnd;i++)
   {
   if(strstr(clo.loc[bindex].bnd.bound[i].info,srchstr) != 0)
      {
      pos1 = strchr(clo.loc[bindex].bnd.bound[i].info,'=');
      zone_list = (zonelist *)malloc(sizeof(zonelist));
      zone_list->zone = (char *)malloc(7);
      strncpy(zone_list->zone,pos1+1,6);
      zone_list->zone[6] = '\0';
      zone_list->next = *head;
      *head = zone_list;
      *nzones = *nzones + 1;
      }
   }

}


void do_range(char *zline, char *lzone, int *cpos, int *nzones, zonelist **head)
/**********************************************************************
*  This routine creates a zone/county entry for each number in the 
*  range zone1>zone2.
***********************************************************************/
{
char zone[20];
int i,zstart,zstop;
zonelist *zone_list;
char *tpos;


if(zline[*cpos] != '>')
   {
   printf("error in zone range %d %s\n",cpos,zline);
   return;
   }

*cpos = *cpos + 1;
zone[0] = '\0';
strncat(zone,lzone,3);

tpos = zline + (*cpos);
if(strncmp(tpos,zone,3) == 0) /* the second number in range is ssZ### */
   *cpos = *cpos + 3;

i = 0;
while((zline[*cpos+i] >= '0')&&(zline[*cpos+i] <= '9'))
   {
   strncat(zone,zline+*cpos+i,1);
   i++;
   }
*cpos = *cpos + i;
sscanf(lzone+3,"%d",&zstart);
sscanf(zone+3,"%d",&zstop);
i = zstart+1;
while((i <= zstop)&&(i < 1000))
   {
   zone[0] = '\0';
   sprintf(zone,"%03d\0",i);
   lzone[3] = '\0';
   strncat(lzone,zone,strlen(zone));
   zone_list = (zonelist *)malloc(sizeof(zonelist));
   zone_list->zone = (char *)malloc( (strlen(lzone)+1)*sizeof(char) );
   strcpy(zone_list->zone,lzone);
   zone_list->next = *head;
   *head = zone_list;
   *nzones = *nzones + 1;
   i++;
   }
}


void get_zones(char *line)
/**********************************************************************
*  This subroutine determines the county/zone identifiers and expiration
*  time from the bulletin identification line, and calls the mapping
*  routine. A linked list is used to store the county/zone ids found
*  in the identifier line. Each county is plotted by traversing the
*  list.
***********************************************************************/
{
int nzones;
char *lpos,zone[20],lzone[20],*zline;
int cpos,llen,i,spos,zstart,zstop,line2;
int FOUND;

char expires[13];

zonelist *zone_list,*head;

lzone[0] = '\0';
expires[0] = '\0'; 
nzones = 0;

zone_list = head = NULL;

llen = strlen(line);
zline = (char *)malloc(llen+1);
zline[0] = '\0';

for(i=0;i<llen;i++)
   if(line[i] >= ' ') strncat(zline,line+i,1);

llen = strlen(zline);

sprintf(t_outstr,"\nzones %s\0",zline);
text_output(outnlun, outluns, t_outstr, strlen(t_outstr) );

cpos = 0; spos = 0; line2 = 0;
while((cpos < llen)||(line2 == 0))
   {
   if(cpos >= llen)
      {
      line2 = -1;
      if((expires[0] == '\0')&&(cpos-spos >= 6)) /* check for no '-' after 
expiration date */
         {
         FOUND = 0;
         for(i=spos;i<cpos;i++) if((zline[i] < '0')||(zline[i] > '9')) FOUND = 
1;
         if(FOUND == 0) strncat(expires,zline+spos,12);
         if(FOUND == 0) printf("Assuming expires %s\n",expires);   
         }
      if(expires[0] == '\0')
         {
         if(cpos-spos > 0) 
            {
            /*printf("probably need to save leftovers %d 
%s\n",cpos-spos,zline+spos);*/
            strncpy(line,zline+spos,cpos-spos);
            lpos = line+cpos-spos;
            }
         else
            lpos = line;

         cpos = 0; spos = 0;
         if(fgets(lpos,255,fp) == NULL) continue;

         line2 = 0;
         llen = strlen(line);
         free(zline);
         zline = (char *)malloc(llen+1);
         zline[0] = '\0';

         for(i=0;i<llen;i++)
            if(line[i] >= ' ') strncat(zline,line+i,1);
         printf("  + %s\n",zline);
         }
      continue;
      }

   if((zline[cpos] == '-') || (zline[cpos] == '>'))
      {
      zone[0] = '\0';
      if((cpos - spos) < 20)
         strncat(zone,zline+spos,cpos-spos);
      else
         strncat(zone,zline+spos,19);

      if((zone[0] >= 'A')&&(zone[0] <= 'Z')&&(strcmp(zone,"DDHHMM") != 0))
         {
         if(strncmp(zone+2,"ZALL",4) == 0)
            do_all(zone,&nzones,&head);
         else
            {
            lzone[0] = '\0';
            strncat(lzone,zone,strlen(zone));
            zone_list = (zonelist *)malloc(sizeof(zonelist));
            zone_list->zone = (char *)malloc( (strlen(lzone)+1)*sizeof(char) );
            strcpy(zone_list->zone,lzone);
            zone_list->next = head;
            head = zone_list;
            nzones++;
            if(zline[cpos] == '>') 
               do_range(zline,lzone,&cpos,&nzones,&head);
            }
         }
      else
         if(strlen(zone) >= 6)
            {
            /* OK, too many rediculous reports where DDHHMM isn't filled in, 
            eg: zones LAZ024-026-MSZ059>067-072>076-078-079-DDHHMM  or blank!
            We'll catch it in is_valid()!!!*/
            if(strcmp(zone,"DDHHMM") == 0) printf("Invalid expiration time 
%s\n",zline);
            if((zone[0] < '0')||(zone[0] > '9'))
               {
               printf("Not a valid expiration time\n");
               line2 = -1;
               }
            else
               strncat(expires,zone,12);
            }
         else
            {
            if((lzone[0] != '\0')&&(zone[0] != '\0'))
               {
               lzone[3] = '\0';
               strncat(lzone,zone,strlen(zone));
               zone_list = (zonelist *)malloc(sizeof(zonelist));
               zone_list->zone = (char *)malloc( (strlen(lzone)+1)*sizeof(char) 
);
               strcpy(zone_list->zone,lzone);
               zone_list->next = head;
               head = zone_list;
               nzones++;
               if(zline[cpos] == '>')
                  do_range(zline,lzone,&cpos,&nzones,&head);
               }
            else
               if(zone[0] != '\0') printf("Improper zone %s\n",zone);
            }

      cpos = cpos + 1;
      while((zline[cpos] == ' ')&&(cpos < llen)) cpos += 1;
      spos = cpos;
      }
   else
      cpos = cpos + 1;
   }

/*if(expires[0] == '\0') printf("No expiration time\n");*/

zone_list = head;
while(head != NULL)
   {
   get_map(head->zone,expires);
   zone_list = head;
   head = head->next;
   free(zone_list->zone);
   free(zone_list);
   }

free(zline);

}

void get_valid(char *wws)
/**********************************************************************
*  This routine returns the time for the plot. Current time is determined
*  from the system time, otherwise the user must provide the yymmdd/hhmm
*  time for the plot.
***********************************************************************/
{
int istarr[5],irtarr[5];
int ier, itype=1;
char sysdt[13];

if((wws[0] >= '0')&&(wws[0] <= '9'))
   { /* assume this will be a GEMPAK time */
   valid[0] = '\0';
   strncat(valid,wws,12);
   }
else
   { /* use the current system clock */
   css_gtim( &itype, valid, &ier);
   }

}


int check_bullet(char *line, int state)
{

if((line[0] < 'A')||(line[0] > 'Z')) return(0); /* first 2 letters must be 
state */
if((line[1] < 'A')||(line[1] > 'Z')) return(0); /* first 2 letters must be 
state */
/* allow for STZALL or STZ###-etc */
if(strncmp(line+3,"ALL",3) == 0) 
   {
   if((line[6] == '-')||(line[6] == '>')) return(1);
   }
if((line[3] < '0')||(line[3] > '9')) return(0); /* next 3 letters are fips 
number */
if((line[4] < '0')||(line[4] > '9')) return(0); /* next 3 letters are fips 
number */
if((line[5] < '0')||(line[5] > '9')) return(0); /* next 3 letters are fips 
number */
if((line[6] == '-')||(line[6] == '>')) return(1);
if(state == 2) printf("is this a fips %s?\n",line);

return(0);
}

void templregex (char *instr, char *outstr)
{
int ier;
cst_rpst(instr, "YYYY", "[0-9][0-9][0-9][0-9]", outstr, &ier);
cst_rpst(outstr, "YY", "[0-9][0-9]", outstr, &ier);
cst_rpst(outstr, "MMM", "[A-Za-z][A-Za-z][A-Za-z]", outstr, &ier);
cst_rpst(outstr, "MM", "[01][0-9]", outstr, &ier);
cst_rpst(outstr, "DD", "[0-3][0-9]", outstr, &ier);
cst_rpst(outstr, "HH", "[0-2][0-9]", outstr, &ier);
cst_rpst(outstr, "NN", "[0-6][0-9]", outstr, &ier);
cst_rpst(outstr, "DWK", "[A-Za-z][A-Za-z][A-Za-z]", outstr, &ier);
cst_rpst(outstr, "FFF", "[0-9][0-9][0-9]", outstr, &ier);
cst_rpst(outstr, "FF", "[0-9][0-9]", outstr, &ier);
}

void warn_search()
{
#define MAXSZ   4096
char line[MAXSZ];
char bulletin[81];
int DONE;
int STATE;
int i;
char *cpos,strpart[80];


DONE = 0;

STATE = 0;
while((DONE == 0)&&(fgets(line,255,fp)!=NULL))
   {
   if((STATE > 0)&&(strchr(line,'\001') != 0))
      {
      if(STATE == 2) printf(": %s does not conform\n",bulletin);
      STATE = 0;
      }
   if((STATE == 0) &&
      ((strstr(line,"WUUS") != 0)||(strstr(line,"WFUS") != 0)||
       (strstr(line,"WWUS") != 0)||(strstr(line,"RWUS") != 0)||
       (strstr(line,"WRUS") != 0)||(strstr(line,"WGUS") != 0)||
       (strstr(line,"WMUS") != 0) ))
      {
      CLASS = -1; PIL = -1;
      /* set some basic classes in case PIL is missing */
      if(strstr(line,"WFUS") != 0) CLASS = TORNADO; 
      if(strstr(line,"WUUS") != 0) CLASS = SEVERE; 
      if(strstr(line,"WWUS4") != 0) CLASS = WINTER; 
      if(strstr(line,"WWUS3") != 0) CLASS = SPECIAL; 
      if(strstr(line,"WWUS8") != 0) CLASS = SPECIAL; 
      if(strstr(line,"WWUS7") != 0) CLASS = NONPRCP; 
      if(strstr(line,"RWUS") != 0) CLASS = FWATCH;
      if(strstr(line,"WRUS") != 0) CLASS = FWARN;
      if(strstr(line,"WGUS") != 0) CLASS = FSTATE;
      if(strstr(line,"WWUS31") != 0) CLASS = HURRS;
      STATE = 1;
      bulletin[0] = '\0';
      for(i=0;i<strlen(line);i++)
         if(line[i] >= ' ') strncat(bulletin,line+i,1);
      sprintf(t_outstr,"\n\nbulletin %s \0",bulletin);
      text_output(outnlun, outluns, t_outstr, strlen(t_outstr) );
      
      continue;
      }
   switch(STATE)
      {
      case 1:
         if(line[0] != '\0')
            {
            if(strncmp(line,"WSW",3) == 0) PIL = WINTER;
            if(strncmp(line,"NPW",3) == 0) PIL = NONPRCP;
            if(strncmp(line,"SPS",3) == 0) PIL = SPECIAL;
            if(strncmp(line,"SVR",3) == 0) PIL = SEVERE;
            if(strncmp(line,"TOR",3) == 0) PIL = TORNADO;
            if(strncmp(line,"FLW",3) == 0) PIL = FWARN;
            if(strncmp(line,"FFW",3) == 0) PIL = FWARN;
            if(strncmp(line,"FLA",3) == 0) PIL = FWATCH;
            if(strncmp(line,"FFA",3) == 0) PIL = FWATCH;
            if((PIL != -1)&&(PIL != CLASS))
               CLASS = PIL;
            }
         STATE = 2;
         break;
      case 2:
      case 4:
         if(strlen(line) < 7) continue; /* look for a FIPS line */
         if(((line[2] == 'C')||(line[2] == 'Z'))&&(check_bullet(line,STATE) == 
1))
            {
            get_zones(line);
            STATE = 4;
            }
         break;
      }
   
   
   }

}

void gpwarn_color_init()
{
/* read configuration table */
memset((void *)gpwarn_config, 0, sizeof(gpwarn_config));
gpwarn_read_config(gpwarn_config);
}

void read_bull(char *wwtmpl, char *wws, char *wwatt, int *nlun, int *luns, int 
*ier)
/**********************************************************************
*  This routine is the driver routine. It should be called with the
*  information for the bulletin file and plot attributes. After
*  a valid bulletin is found, the first line of the county/zone
*  identifier is passed to the plotting routine. The file handle for
*  The bulletin file is stored in a global variable in case a second
*  line is used - which must be read if the expiration time is not
*  found on the first line.
***********************************************************************/
{

#define MAXSZ   4096
#define MAXTMPL 100
char line[MAXSZ];
char bulletin[81];
int DONE;
int STATE;
int i;
int iret;
char *cpos,strpart[80];

char path[132],tmplt[132], newtmplt[160], defstr[] = " ";
char filnam[512],*postok;
int tplate, icat, iscat, ifrm, irng, iint, plens, tlens, llen, numstr, numscd;
int maxline=MAXSZ, order=-1;

static char defdir[]="$TEXT_DATA/watch_warn";
static char **arrptr;
static int init=-1, nstrings = 10;

*ier = 0;

if(init == -1)
   {
   init = 0;
   arrptr = (char **) malloc(sizeof(char *) * nstrings);
   for(i=0; i < nstrings; i++)
      arrptr[i] = (char *) malloc(MAXTMPL);
   }

outluns = luns;
outnlun = nlun;

get_valid(wws);

if(wwatt != NULL)
   {
   i = 0;
   cpos = strchr(wwatt,';');
   if(cpos == NULL) cpos = (char *)(wwatt + strlen(wwatt));
   strpart[0] = '\0';
   strncat(strpart,wwatt+i,cpos - wwatt);
   iret = sscanf(strpart,"%d/%d",&PRIOR,&FUTURE);
   if(iret < 2)
      {
      if(iret == 1) 
         FUTURE = PRIOR;
      else
         PRIOR = FUTURE = 1440;
      }
   ADVANCE = 0;
   if(FUTURE < 0)
      {
      FUTURE = -FUTURE;
      ADVANCE = 1;
      }
   
   i = (cpos - wwatt) + 1;
   }



if(strlen(wwtmpl) > 0)
   {
   cst_clst(wwtmpl, ';', defstr,nstrings,MAXTMPL,arrptr, &numstr, &iret);
   for(i=0;i<numstr;i++)
      {
      int ier1, ier2;

      ctb_dtpath ( arrptr[i], path, &ier1 );
      ctb_dttmpl ( arrptr[i], tmplt, &ier2 );

      if ( ( ier1 != 0 ) || ( ier2 != 0 ) )
         {
         fp = cfl_ropn(arrptr[i],defdir,&iret);
         if(iret != 0)
            {
            printf("error opening %s\n",arrptr[i]);
            *ier = -1;
            return;
            }
         else
            {
            warn_search();
            fclose(fp);
            }
         }
      else
         {
         plens = strlen(path);
         templregex ( tmplt, newtmplt ); tlens = strlen(newtmplt);
         cfl_scnd (path, &plens, newtmplt, &tlens, ";", &maxline, &order, line, 
&llen, &numscd, &iret);

         postok = strtok(line,";");
         while(postok != NULL)
            {
            sprintf(filnam,"%s/%s\0",path,postok);
            sprintf(t_outstr, "searching filnam %s\0",filnam);
            text_output(outnlun, outluns, t_outstr, strlen(t_outstr) );
            if((fp = cfl_ropn ( filnam, NULL, &iret)) != NULL)
               {
               warn_search();
               fclose(fp);
               }
            postok = strtok(NULL,";");
            }
         }
      }
   }
else
   *ier = -1;



}