/*----------------------------------------------------------------------*\ | Some routines to handle I/O of Desert Winds data. | | | | Public symbols: | | | | dw_open open a GEOMET station data file | | dw_read read GEOMET data | | dw_write write GEOMET data | | dw_close close a GEOMET station data file | | | | Fortran compatibility: | | | | Fortran name is composed of the C name plus trailing underscore. If | | your Fortran compiler does things differently, you will have to edit | | the definition of the FNAME macro. | | | | Fortran strings are assumed to be passed as ordinary arguments, with | | lengths of strings passed by value at the end of the argument list. | | If your Fortran compiler does things differently, you will have to | | edit the behavior of dw_open_. Do not call dw_open directly from | | Fortran. | | | | Peter N. Schweitzer (U.S. Geological Survey, Reston, VA 22092) | \*----------------------------------------------------------------------*/ #include #include #include #include #include #include "dw.h" struct compact_dwd { unsigned short year; unsigned short day; unsigned short minute; unsigned short hum; unsigned short ppt; unsigned short bp; unsigned short wd; unsigned short ws20; unsigned short pg20; unsigned short ws88; unsigned short ws4; unsigned short pg4; unsigned short at20; unsigned short at4; unsigned short st4; unsigned short st10; unsigned short st20; }; struct compact_dwsr { unsigned short srsi; unsigned short srli; unsigned short srso; unsigned short srlo; unsigned short sb; }; struct compact_dwbt { unsigned short bt1; unsigned short bt2; unsigned short bt3; unsigned short bt4; }; #define LINE_LEN 128 static char msg [LINE_LEN]; static enum byte_order_t { LITTLE_ENDIAN, BIG_ENDIAN, NOT_DETERMINED } byte_order = NOT_DETERMINED; static void get_byte_order (void) { short w = 255; unsigned char *s = (unsigned char *) &w; if (*s) byte_order = LITTLE_ENDIAN; else byte_order = BIG_ENDIAN; } static struct dw_file *first = NULL; extern void dw_error (char *msg); extern void dw_warn (char *msg); static int dw_bwrite0 (struct dw_file *dwf, struct dwd *d); static struct dwd *dw_bread0 (struct dw_file *dwf, struct dwd *d); static int dw_fwrite0 (struct dw_file *dwf, struct dwd *d); static struct dwd *dw_fread0 (struct dw_file *dwf, struct dwd *d); static int parse_geography (char *string, struct location *g); struct dw_function { struct dwd *(*bread)(struct dw_file *dwf, struct dwd *d); int (*bwrite)(struct dw_file *dwf, struct dwd *d); struct dwd *(*fread)(struct dw_file *dwf, struct dwd *d); int (*fwrite)(struct dw_file *dwf, struct dwd *d); }; static struct dw_function function[] = { {dw_bread0,dw_bwrite0,dw_fread0,dw_fwrite0}, {NULL,NULL,NULL,NULL} }; #define FNAME(x) x##_ static void show_dwd (struct dwd *d) { fprintf (stderr,"d at 0x%X = {\n", d); fprintf (stderr,"\tyear = %02d\n", d->year); fprintf (stderr,"\tday = %03d\n", d->day); fprintf (stderr,"\thour = %02d\n", d->hour); fprintf (stderr,"\tmin = %02d\n", d->minute); fprintf (stderr,"\thum = %6.2f\n", d->hum); fprintf (stderr,"\tppt = %6.2f\n", d->ppt); fprintf (stderr,"\tbp = %7.3f\n", d->bp); fprintf (stderr,"\twd = %6.2f\n", d->wd); fprintf (stderr,"\tws20 = %6.2f\n", d->ws20); fprintf (stderr,"\tpg20 = %6.2f\n", d->pg20); fprintf (stderr,"\tws88 = %6.2f\n", d->ws88); fprintf (stderr,"\tws4 = %6.2f\n", d->ws4); fprintf (stderr,"\tpg4 = %6.2f\n", d->pg4); fprintf (stderr,"\tat20 = %6.2f\n", d->at20); fprintf (stderr,"\tat4 = %6.2f\n", d->at4); fprintf (stderr,"\tst4 = %6.2f\n", d->st4); fprintf (stderr,"\tst10 = %6.2f\n", d->st10); fprintf (stderr,"\tst20 = %6.2f\n", d->st20); fprintf (stderr,"\tsrsi = %6f\n", d->srsi); fprintf (stderr,"\tsrli = %6f\n", d->srli); fprintf (stderr,"\tsrso = %6f\n", d->srso); fprintf (stderr,"\tsrlo = %6f\n", d->srlo); fprintf (stderr,"\tsb = %6f\n", d->sb); fprintf (stderr,"\tbt1 = %6f\n", d->bt1); fprintf (stderr,"\tbt2 = %6f\n", d->bt2); fprintf (stderr,"\tbt3 = %6f\n", d->bt3); fprintf (stderr,"\tbt4 = %6f\n", d->bt4); fprintf (stderr,"\t};\n"); } static void dwd_initialize (struct dwd *d) { d->year = 0; d->day = 0; d->hour = 0; d->minute = 0; d->hum = MISSING_VALUE; d->ppt = MISSING_VALUE; d->bp = MISSING_VALUE; d->wd = MISSING_VALUE; d->ws20 = MISSING_VALUE; d->pg20 = MISSING_VALUE; d->ws88 = MISSING_VALUE; d->ws4 = MISSING_VALUE; d->pg4 = MISSING_VALUE; d->at20 = MISSING_VALUE; d->at4 = MISSING_VALUE; d->st4 = MISSING_VALUE; d->st10 = MISSING_VALUE; d->st20 = MISSING_VALUE; d->srsi = MISSING_VALUE; d->srli = MISSING_VALUE; d->srso = MISSING_VALUE; d->srlo = MISSING_VALUE; d->sb = MISSING_VALUE; d->bt1 = MISSING_VALUE; d->bt2 = MISSING_VALUE; d->bt3 = MISSING_VALUE; d->bt4 = MISSING_VALUE; } /*----------------------------------------------------------------------*\ \*----------------------------------------------------------------------*/ int FNAME(dw_open) (char *name, char *mode, struct dw_file *dwf, int name_len, int mode_len) { int i; char *s; char *pname; char *pdata = NULL; struct dw_file *pf; for (i=0, s=name; i < name_len && !isspace (*s); i++, s++); if (i < name_len) { *s = 0; pname = name; } else { if (!(pname = (char *) malloc (1 + name_len))) { dw_error ("Error: unable to allocate memory for file name string"); return (0); } memcpy (pname,name,name_len); pname[name_len] = 0; pdata = pname; } pf = dw_open (pname,mode,&dwf->where); if (pf) { memcpy (dwf,pf,sizeof(struct dw_file)); dwf->prev = pf->prev; dwf->next = pf->next; if (dwf->prev) dwf->prev->next = dwf; if (dwf->next) dwf->next->prev = dwf; free (pf); if (pdata) free (pdata); return (1); } else { if (pdata) free(pdata); return (0); } } struct dw_file *dw_open (char *name, char *mode, struct location *where) { /*------------------------------------------------------------------*\ | Open the file "name" in mode "mode". | | mode can have the following arguments: | | r read access; the file must already exist. | | a append access; if the file does not exist, it will be | | created as though "w" had been given as the mode. | | ab append access; if the file already exists, the b is ignored.| | w write access, ASCII format. If the file already exists, it | | will be overwritten. | | wb write access, BINARY format. If the file already exists, | | it will be overwritten. | | For write access, the third argument specifies the location of | | the station. If the file is open for read or append, the third | | argument is ignored. This means you can't mix data from more | | than one station in the same file. Is there a reason why you | | would want to? | | | | Allocate a dw_file structure; add it to the linked list of files | | and fill in the members of the structure. | \*------------------------------------------------------------------*/ FILE *f; struct dw_file *dwf; char signature [4]; char *s; char line [LINE_LEN]; char rwa, b; rwa = tolower(*mode); if (!rwa) { dw_error ("Error: empty mode string passed to dw_open"); return (NULL); } b = tolower(mode[1]); if (byte_order == NOT_DETERMINED) get_byte_order(); f = fopen (name,"rb"); if (rwa == 'r') { if (!f) return (NULL); fread (signature,1,4,f); if (memcmp (signature,"DW",2) != 0) { sprintf (msg,"Error: the file %s is not a DW file",name); dw_error (msg); return (NULL); } if (signature[2] == 'b') { /*------------------------------------------------------*\ | File exists and is binary. | | Create a dw_file structure for this file | \*------------------------------------------------------*/ if (!(dwf = (struct dw_file *) malloc (sizeof (struct dw_file)))) { sprintf (msg,"Error: could not allocate space for dw_file %s",name); dw_error (msg); } /*------------------------------------------------------*\ | Link this file into the list \*------------------------------------------------------*/ if (first) { struct dw_file *fp; for (fp = first; fp->next; fp = fp->next); fp->next = dwf; dwf->prev = fp; dwf->next = NULL; } else { first = dwf; dwf->prev = NULL; dwf->next = NULL; } /*------------------------------------------------------*\ | Fill out structure members \*------------------------------------------------------*/ strcpy (dwf->name,name); dwf->f = f; dwf->version = signature[3] & 0x7F; dwf->binary = 1; if (((signature[3] & 0x80 == 0) && byte_order == BIG_ENDIAN) || ((signature[3] & 0x80 != 0) && byte_order == LITTLE_ENDIAN)) dwf->must_swap_bytes = 1; else dwf->must_swap_bytes = 0; fread (line,1,sizeof(struct location),f); if (dwf->must_swap_bytes) swab (line,(char *)&dwf->where,sizeof (struct location)); else memcpy (&dwf->where,line,sizeof (struct location)); dwf->read = function[dwf->version].bread; dwf->write = function[dwf->version].bwrite; } else { /*------------------------------------------------------*\ | File exists but is not binary. Reopen as text. | \*------------------------------------------------------*/ fclose (f); if (!(f = fopen (name,"r"))) { sprintf (msg,"Error: could not reopen %s as text",name); dw_error (msg); return (NULL); } /*------------------------------------------------------*\ | Re-read the header, which occupies one line. | \*------------------------------------------------------*/ fgets (line,LINE_LEN,f); if (s = strrchr (line,'\n')) *s = 0; if (s = strrchr (line,'\r')) *s = 0; if (memcmp (line,"DWa",3) != 0) { sprintf (msg,"Warning: unexpected data in file %s: \"%s\"",name,line); dw_warn (msg); } /*------------------------------------------------------*\ | Create a dw_file structure for this file \*------------------------------------------------------*/ if (!(dwf = (struct dw_file *) malloc (sizeof (struct dw_file)))) { sprintf (msg,"Error: could not allocate space for dw_file %s",name); dw_error (msg); } /*------------------------------------------------------*\ | Link this file into the list \*------------------------------------------------------*/ if (first) { struct dw_file *fp; for (fp = first; fp->next; fp = fp->next); fp->next = dwf; dwf->prev = fp; dwf->next = NULL; } else { first = dwf; dwf->prev = NULL; dwf->next = NULL; } /*------------------------------------------------------*\ | Fill out structure members \*------------------------------------------------------*/ strcpy (dwf->name,name); dwf->f = f; dwf->binary = 0; dwf->version = signature[3] - '0'; dwf->must_swap_bytes = 0; s = line + 4; if (!parse_geography (s,&dwf->where)) { fgets (line,LINE_LEN,f); if (s = strrchr (line,'\n')) *s = 0; if (s = strrchr (line,'\r')) *s = 0; s = line; if (!parse_geography (s,&dwf->where)) { sprintf (msg,"Error: cannot understand geographic location in %s\n",name); dw_error (msg); return (NULL); } } dwf->read = function[dwf->version].fread; dwf->write = function[dwf->version].fwrite; } return (dwf); } if (rwa == 'a') { if (f) { /*----------------------------------------------------------*\ | The file exists already. Read its header and station | | location, then close and reopen for append. | \*----------------------------------------------------------*/ fread (signature,1,4,f); if (memcmp (signature,"DW",2) != 0) { sprintf (msg,"Error: the file %s is not a DW file",name); dw_error (msg); return (NULL); } if (signature[2] == 'b') { /*------------------------------------------------------*\ | File exists and is binary. | | Create a dw_file structure for this file | \*------------------------------------------------------*/ if (!(dwf = (struct dw_file *) malloc (sizeof (struct dw_file)))) { sprintf (msg,"Error: could not allocate space for dw_file %s",name); dw_error (msg); } /*------------------------------------------------------*\ | Link this file into the list \*------------------------------------------------------*/ if (first) { struct dw_file *fp; for (fp = first; fp->next; fp = fp->next); fp->next = dwf; dwf->prev = fp; dwf->next = NULL; } else { first = dwf; dwf->prev = NULL; dwf->next = NULL; } /*------------------------------------------------------*\ | Fill out structure members \*------------------------------------------------------*/ strcpy (dwf->name,name); dwf->f = f; dwf->version = signature[3] & 0x7F; dwf->binary = 1; if (((signature[3] & 0x80 == 0) && byte_order == BIG_ENDIAN) || ((signature[3] & 0x80 != 0) && byte_order == LITTLE_ENDIAN)) dwf->must_swap_bytes = 1; else dwf->must_swap_bytes = 0; fread (line,1,sizeof(struct location),f); if (dwf->must_swap_bytes) swab (line,(char *)&dwf->where,sizeof (struct location)); else memcpy (&dwf->where,line,sizeof (struct location)); dwf->read = function[dwf->version].bread; dwf->write = function[dwf->version].bwrite; /*------------------------------------------------------*\ | Close the file and reopen for append access. | \*------------------------------------------------------*/ fclose (f); if (!(f = fopen (name,"ab"))) { sprintf (msg,"Error: could not reopen %s for append",name); dw_error (msg); return (NULL); } dwf->f = f; return (dwf); } else { /*------------------------------------------------------*\ | File exists but is not binary. Reopen as text. | \*------------------------------------------------------*/ fclose (f); if (!(f = fopen (name,"r"))) { sprintf (msg,"Error: could not reopen %s as text",name); dw_error (msg); return (NULL); } /*------------------------------------------------------*\ | Re-read the header, which occupies one line. | \*------------------------------------------------------*/ fgets (line,LINE_LEN,f); if (s = strrchr (line,'\n')) *s = 0; if (s = strrchr (line,'\r')) *s = 0; if (memcmp (line,"DWf",3) != 0) { sprintf (msg,"Warning: unexpected data in file %s: \"%s\"",name,line); dw_warn (msg); } /*------------------------------------------------------*\ | Create a dw_file structure for this file \*------------------------------------------------------*/ if (!(dwf = (struct dw_file *) malloc (sizeof (struct dw_file)))) { sprintf (msg,"Error: could not allocate space for dw_file %s",name); dw_error (msg); } /*------------------------------------------------------*\ | Link this file into the list \*------------------------------------------------------*/ if (first) { struct dw_file *fp; for (fp = first; fp->next; fp = fp->next); fp->next = dwf; dwf->prev = fp; dwf->next = NULL; } else { first = dwf; dwf->prev = NULL; dwf->next = NULL; } /*------------------------------------------------------*\ | Fill out structure members \*------------------------------------------------------*/ strcpy (dwf->name,name); dwf->f = f; dwf->version = signature[3] - '0'; dwf->binary = 0; dwf->must_swap_bytes = 0; s = line + 4; if (!parse_geography (s,&dwf->where)) { fgets (line,LINE_LEN,f); if (s = strrchr (line,'\n')) *s = 0; if (s = strrchr (line,'\r')) *s = 0; s = line; if (!parse_geography (s,&dwf->where)) { sprintf (msg,"Error: cannot understand geographic location in %s\n",name); dw_error (msg); return (NULL); } } dwf->read = function[dwf->version].fread; dwf->write = function[dwf->version].fwrite; /*------------------------------------------------------*\ | Close the file and reopen for append access. | \*------------------------------------------------------*/ fclose (f); if (!(f = fopen (name,"a"))) { sprintf (msg,"Error: could not reopen %s for append",name); dw_error (msg); return (NULL); } dwf->f = f; } return (dwf); } else { /*----------------------------------------------------------*\ | The file does not exist. Create it, paying attention | | to the second byte of the mode string. | \*----------------------------------------------------------*/ rwa = 'w'; } } if (rwa == 'w') { if (f = fopen (name,mode)) { /*----------------------------------------------------------*\ | Create a dw_file structure for this file | \*----------------------------------------------------------*/ if (!(dwf = (struct dw_file *) malloc (sizeof (struct dw_file)))) { sprintf (msg,"Error: could not allocate space for dw_file %s",name); dw_error (msg); } /*----------------------------------------------------------*\ | Link this file into the list | \*----------------------------------------------------------*/ if (first) { struct dw_file *fp; for (fp = first; fp->next; fp = fp->next); fp->next = dwf; dwf->prev = fp; dwf->next = NULL; } else { first = dwf; dwf->prev = NULL; dwf->next = NULL; } /*----------------------------------------------------------*\ | Fill out structure members | \*----------------------------------------------------------*/ strcpy (dwf->name,name); dwf->f = f; if (b == 'b') { dwf->version = 0; dwf->binary = 1; dwf->must_swap_bytes = 0; dwf->read = function[dwf->version].bread; dwf->write = function[dwf->version].bwrite; strcpy (signature,"DWb"); signature[3] = dwf->version | ((byte_order == LITTLE_ENDIAN) ? 0x00 : 0x80); fwrite (signature,1,4,f); fwrite (where,1,sizeof(struct location),f); } else { dwf->version = 0; dwf->binary = 0; dwf->must_swap_bytes = 0; dwf->read = function[dwf->version].fread; dwf->write = function[dwf->version].fwrite; sprintf (line,"DWa%c %02d %02d' %02d\" N %03d %02d' %02d\" W\n", dwf->version + '0', where->latitude.degrees, where->latitude.minutes, where->latitude.seconds, where->longitude.degrees, where->longitude.minutes, where->longitude.seconds ); fputs (line,f); } return (dwf); } else { sprintf (msg,"Error: could not create file %s",name); dw_error (msg); return (NULL); } } return (NULL); } int FNAME(dw_read) (struct dw_file *f, struct dwd *d) { return ((*f->read)(f,d) != NULL); } struct dwd *dw_read (struct dw_file *f, struct dwd *d) { return((*f->read)(f,d)); } int FNAME(dw_write) (struct dw_file *f, struct dwd *d) { return ((*f->write)(f,d)); } int dw_write (struct dw_file *f, struct dwd *d) { return ((*f->write)(f,d)); } void FNAME(dw_close) (struct dw_file *f) { if (f) { if (f->f) fclose (f->f); if (f == first) if (f->prev) first = f->prev; else if (f->next) first = f->next; else first = NULL; if (f->prev) f->prev->next = f->next; if (f->next) f->next->prev = f->prev; } } void dw_close (struct dw_file *f) { if (f) { if (f->f) fclose (f->f); if (f == first) if (f->prev) first = f->prev; else if (f->next) first = f->next; else first = NULL; if (f->prev) f->prev->next = f->next; if (f->next) f->next->prev = f->prev; free (f); } } #define round(x) ((x - floor(x) < 0.5) ? (x) : (x + 0.5)) static int dw_bwrite0 (struct dw_file *dwf, struct dwd *d) { struct compact_dwd cd; struct compact_dwd scratch; cd.year = d->year; cd.day = d->day; cd.minute = d->hour * 60 + d->minute; cd.hum = (d->hum == MISSING_VALUE) ? 0xFFFF : (unsigned short) round (d->hum * 100); cd.ppt = (d->ppt == MISSING_VALUE) ? 0xFFFF : (unsigned short) round (d->ppt * 100); cd.bp = (d->bp == MISSING_VALUE) ? 0xFFFF : (unsigned short) round (d->bp * 1000); cd.wd = (d->wd == MISSING_VALUE) ? 0xFFFF : (unsigned short) round (d->wd * 100); cd.ws20 = (d->ws20 == MISSING_VALUE) ? 0xFFFF : (unsigned short) round (d->ws20 * 100); cd.pg20 = (d->pg20 == MISSING_VALUE) ? 0xFFFF : (unsigned short) round (d->pg20 * 100); cd.ws88 = (d->ws88 == MISSING_VALUE) ? 0xFFFF : (unsigned short) round (d->ws88 * 100); cd.ws4 = (d->ws4 == MISSING_VALUE) ? 0xFFFF : (unsigned short) round (d->ws4 * 100); cd.pg4 = (d->pg4 == MISSING_VALUE) ? 0xFFFF : (unsigned short) round (d->pg4 * 100); cd.at20 = (d->at20 == MISSING_VALUE) ? 0xFFFF : (unsigned short) round (100 * (d->at20 + 50)); cd.at4 = (d->at4 == MISSING_VALUE) ? 0xFFFF : (unsigned short) round (100 * (d->at4 + 50)); cd.st4 = (d->st4 == MISSING_VALUE) ? 0xFFFF : (unsigned short) round (100 * (d->st4 + 50)); cd.st10 = (d->st10 == MISSING_VALUE) ? 0xFFFF : (unsigned short) round (100 * (d->st10 + 50)); cd.st20 = (d->st20 == MISSING_VALUE) ? 0xFFFF : (unsigned short) round (100 * (d->st20 + 50)); if (dwf->must_swap_bytes) { swab ((char *)&cd,(char *)&scratch,sizeof(struct compact_dwd)); memcpy (&cd,&scratch,sizeof(struct compact_dwd)); } return (fwrite (&cd,sizeof (struct compact_dwd),1,dwf->f)); } static struct dwd *dw_bread0 (struct dw_file *dwf, struct dwd *d) { struct compact_dwd cd; struct compact_dwd scratch; if (fread (&cd,sizeof (struct compact_dwd),1,dwf->f)) { if (dwf->must_swap_bytes) { swab ((char *)&cd,(char *)&scratch,sizeof(struct compact_dwd)); memcpy (&cd,&scratch,sizeof(struct compact_dwd)); } d->year = cd.year; d->day = cd.day; d->hour = cd.minute / 60; d->minute = cd.minute % 60; d->hum = (cd.hum == 0xFFFF) ? MISSING_VALUE : ((float) cd.hum )/100; d->ppt = (cd.ppt == 0xFFFF) ? MISSING_VALUE : ((float) cd.ppt )/100; d->bp = (cd.bp == 0xFFFF) ? MISSING_VALUE : ((float) cd.bp )/1000; d->wd = (cd.wd == 0xFFFF) ? MISSING_VALUE : ((float) cd.wd )/100; d->ws20 = (cd.ws20 == 0xFFFF) ? MISSING_VALUE : ((float) cd.ws20)/100; d->pg20 = (cd.pg20 == 0xFFFF) ? MISSING_VALUE : ((float) cd.pg20)/100; d->ws88 = (cd.ws88 == 0xFFFF) ? MISSING_VALUE : ((float) cd.ws88)/100; d->ws4 = (cd.ws4 == 0xFFFF) ? MISSING_VALUE : ((float) cd.ws4 )/100; d->pg4 = (cd.pg4 == 0xFFFF) ? MISSING_VALUE : ((float) cd.pg4 )/100; d->at20 = (cd.at20 == 0xFFFF) ? MISSING_VALUE : ((float) cd.at20)/100 - 50; d->at4 = (cd.at4 == 0xFFFF) ? MISSING_VALUE : ((float) cd.at4 )/100 - 50; d->st4 = (cd.st4 == 0xFFFF) ? MISSING_VALUE : ((float) cd.st4 )/100 - 50; d->st10 = (cd.st10 == 0xFFFF) ? MISSING_VALUE : ((float) cd.st10)/100 - 50; d->st20 = (cd.st20 == 0xFFFF) ? MISSING_VALUE : ((float) cd.st20)/100 - 50; d->srsi = MISSING_VALUE; d->srli = MISSING_VALUE; d->srso = MISSING_VALUE; d->srlo = MISSING_VALUE; d->sb = MISSING_VALUE; d->bt1 = MISSING_VALUE; d->bt2 = MISSING_VALUE; d->bt3 = MISSING_VALUE; d->bt4 = MISSING_VALUE; return (d); } else return (NULL); } static int dw_fwrite0 (struct dw_file *dwf, struct dwd *d) { fprintf (dwf->f," %02d",((d->year < 1900) ? d->year : d->year - 1900)); fprintf (dwf->f, "%03d",d->day); fprintf (dwf->f," %02d",d->hour); fprintf (dwf->f, "%02d",d->minute); if (d->hum == MISSING_VALUE) fprintf (dwf->f," ******"); else fprintf (dwf->f," %6.2f",d->hum ); if (d->ppt == MISSING_VALUE) fprintf (dwf->f," *****" ); else fprintf (dwf->f," %5.2f",d->ppt ); if (d->bp == MISSING_VALUE) fprintf (dwf->f," ******"); else fprintf (dwf->f," %6.3f",d->bp ); if (d->wd == MISSING_VALUE) fprintf (dwf->f," ******"); else fprintf (dwf->f," %6.2f",d->wd ); if (d->ws20 == MISSING_VALUE) fprintf (dwf->f," *****" ); else fprintf (dwf->f," %5.2f",d->ws20); if (d->pg20 == MISSING_VALUE) fprintf (dwf->f," *****" ); else fprintf (dwf->f," %5.2f",d->pg20); if (d->ws88 == MISSING_VALUE) fprintf (dwf->f," *****" ); else fprintf (dwf->f," %5.2f",d->ws88); if (d->ws4 == MISSING_VALUE) fprintf (dwf->f," *****" ); else fprintf (dwf->f," %5.2f",d->ws4 ); if (d->pg4 == MISSING_VALUE) fprintf (dwf->f," *****" ); else fprintf (dwf->f," %5.2f",d->pg4 ); if (d->at20 == MISSING_VALUE) fprintf (dwf->f," *****" ); else fprintf (dwf->f," %5.2f",d->at20); if (d->at4 == MISSING_VALUE) fprintf (dwf->f," *****" ); else fprintf (dwf->f," %5.2f",d->at4 ); if (d->st4 == MISSING_VALUE) fprintf (dwf->f," *****" ); else fprintf (dwf->f," %5.2f",d->st4 ); if (d->st10 == MISSING_VALUE) fprintf (dwf->f," *****" ); else fprintf (dwf->f," %5.2f",d->st10); if (d->st20 == MISSING_VALUE) fprintf (dwf->f," *****" ); else fprintf (dwf->f," %5.2f",d->st20); return (fprintf (dwf->f,"\n")); } static struct dwd *dw_fread0 (struct dw_file *dwf, struct dwd *d) { char string [LINE_LEN]; char *s,*t,*e; char number[8]; int i; int ok = 0; float *v; static int field_width [14] = {7,6,7,7,6,6,6,6,6,6,6,6,6,6}; if (!dwf) return (NULL); if (!dwf->f) return (NULL); if (!d) return (NULL); while (!ok) { if (!fgets (string,LINE_LEN,dwf->f)) return (NULL); if (s = strrchr (string,'\n')) *s = 0; if (s = strrchr (string,'\r')) *s = 0; s = string; while (*s && isspace (*s)) s++; if (*s) ok = 1; } e = string + strlen (string); dwd_initialize (d); d->year = *s++ - '0'; d->year *= 10; d->year += *s++ - '0'; d->day = *s++ - '0'; d->day *= 10; d->day += *s++ - '0'; d->day *= 10; d->day += *s++ - '0'; while (*s && isspace (*s)) s++; d->hour = *s++ - '0'; d->hour *= 10; d->hour += *s++ - '0'; d->minute = *s++ - '0'; d->minute *= 10; d->minute += *s++ - '0'; v = &d->hum; for (i=0; s < e; i++) { memcpy (number,s,field_width[i]); s += field_width[i]; number[field_width[i]] = 0; for (t = number; *t && isspace (*t); t++); if (*t == '-') t++; if (isdigit (*t)) { *v = (float) atof (number); if (*v == -77.0) *v = MISSING_VALUE; if (*v == -999.0) *v = MISSING_VALUE; v++; } else *v++ = MISSING_VALUE; } d->srsi = MISSING_VALUE; d->srli = MISSING_VALUE; d->srso = MISSING_VALUE; d->srlo = MISSING_VALUE; d->sb = MISSING_VALUE; d->bt1 = MISSING_VALUE; d->bt2 = MISSING_VALUE; d->bt3 = MISSING_VALUE; d->bt4 = MISSING_VALUE; return (d); } /*----------------------------------------------------------------------*\ | Routine to read a string containing a numerical description of a | | geographic location. Latitude comes first, longitude second. | | Two formats are permitted, strict format and free format. | | | | Strict format is as follows: | | ddmmss [N|S] dddmmss [W|E] | | where d, m, and s are numerals, and the letters N, S, E, or W need | | not be present. If they are absent, the location is assumed to be | | in the northern and western hemispheres. | | | | Free format is as follows: | | dd['d'] [mm[']] [ss["]] [N|S] ddd['d'] [mm[']] [ss["]] [W|E] | | where d, m, and s are numerals. | \*----------------------------------------------------------------------*/ static int parse_geography (char *string, struct location *g) { char *s,*t; int deg; int min; int sec; char hemisphere; int n; int i; struct item_t { int n; char c; } item[8]; if (string == NULL) return (0); if (*string == 0) return (0); if (g == NULL) return (0); s = string; while (*s && isspace (*s)) s++; /*------------------------------------------------------------------*\ | Try to read string in strict format. If you can't, try free. | \*------------------------------------------------------------------*/ for (n=0,t=s; *t && isdigit (*t); n++) t++; if (n == 6) { deg = *s++ - '0'; deg *= 10; deg += *s++ - '0'; min = *s++ - '0'; min *= 10; min += *s++ - '0'; sec = *s++ - '0'; sec *= 10; sec += *s++ - '0'; while (*s && isspace (*s)) s++; if (toupper(*s) == 'N' || toupper(*s) == 'S') hemisphere = toupper(*s++); if (hemisphere == 'S') deg = -deg; g->latitude.degrees = deg; g->latitude.minutes = min; g->latitude.seconds = sec; while (*s && isspace (*s)) s++; for (n=0,t=s; *t && isdigit (*t); n++) t++; if (n == 7) { deg = *s++ - '0'; deg *= 10; deg += *s++ - '0'; deg *= 10; deg += *s++ - '0'; min = *s++ - '0'; min *= 10; min += *s++ - '0'; sec = *s++ - '0'; sec *= 10; sec += *s++ - '0'; while (*s && isspace (*s)) s++; if (toupper(*s) == 'W' || toupper(*s) == 'E') hemisphere = toupper(*s++); #ifdef NEGATIVE_WEST if (hemisphere == 'W') deg = -deg; #endif g->longitude.degrees = deg; g->longitude.minutes = min; g->longitude.seconds = sec; return (1); } } /*------------------------------------------------------------------*\ | Strict format didn't work. Read as free format. | | | | This is carried out in three steps: | | 1. Find numbers and the characters that follow them. | | 2. Interpret the numbers by their sequence and the characters. | | 3. Figure out whether the results make sense, and if so, zero | | out any missing quantities. | \*------------------------------------------------------------------*/ s = string; while (*s && isspace (*s)) s++; i = 0; while (*s) { item[i].n = 999; item[i].c = -1; if (isdigit (*s)) item[i].n = *s++ - '0'; if (isdigit (*s)) { item[i].n *= 10; item[i].n += *s++ - '0'; } if (isdigit (*s)) { /* should happen only in degrees longitude */ item[i].n *= 10; item[i].n += *s++ - '0'; } item[i].c = *s++; while (*s && isspace (*s)) s++; i++; if (i > 7) break; } /*------------------------------------------------------------------*\ | Initialize the target values to some invalid number. | \*------------------------------------------------------------------*/ g->latitude.degrees = g->latitude.minutes = g->latitude.seconds = 999; g->longitude.degrees = g->longitude.minutes = g->longitude.seconds = 999; /*------------------------------------------------------------------*\ | Interpret the items by looking at the character following each | | item and remembering that the numbers have to be given in the | | proper sequence. | \*------------------------------------------------------------------*/ i = 0; if (item[i].c == 'd' || isspace (item[i].c)) g->latitude.degrees = item[i++].n; if (item[i].c == '\'' || isspace (item[i].c)) g->latitude.minutes = item[i++].n; if (item[i].c == '"' || isspace (item[i].c)) g->latitude.seconds = item[i++].n; if (toupper(item[i].c) == 'N') { if (g->latitude.degrees == 999) g->latitude.degrees = item[i].n; i++; } if (toupper(item[i].c) == 'S') { if (g->latitude.degrees == 999) g->latitude.degrees = item[i].n; g->latitude.degrees *= -1; i++; } if (item[i].c == 'd' || isspace (item[i].c)) g->longitude.degrees = item[i++].n; if (item[i].c == '\'' || isspace (item[i].c)) g->longitude.minutes = item[i++].n; if (item[i].c == '"' || isspace (item[i].c)) g->longitude.seconds = item[i++].n; if (toupper(item[i].c) == 'E') { if (g->longitude.degrees == 999) g->longitude.degrees = item[i].n; i++; } if (toupper(item[i].c) == 'W') { if (g->longitude.degrees == 999) g->longitude.degrees = item[i].n; #ifdef NEGATIVE_WEST g->longitude.degrees *= -1; #endif i++; } /*------------------------------------------------------------------*\ | Data are valid only if degrees latitude and degrees longitude | | were both specified. | \*------------------------------------------------------------------*/ if (g->latitude.degrees != 999 && g->longitude.degrees != 999) { if (g->latitude.minutes == 999) g->latitude.minutes = 0; if (g->latitude.seconds == 999) g->latitude.seconds = 0; if (g->longitude.minutes == 999) g->longitude.minutes = 0; if (g->longitude.seconds == 999) g->longitude.seconds = 0; return (1); } return (0); } /*----------------------------------------------------------------------*\ \*----------------------------------------------------------------------*/