/*----------------------------------------------------------------------*\ | GEOMET data output routines for popular file formats. Steps needed | | to add a format are (1) devise textual name for the format and add | | it to the list in geomet_output_function_table, (2) write the output | | routine itself, indicating its address in the table also. | | | | Peter N. Schweitzer (U.S. Geological Survey, Reston, VA 22092) | \*----------------------------------------------------------------------*/ #include #include #include #include "dw.h" static char msg [1024]; #ifdef MS_DOS #define EOL "\x0D\x0A" #else #ifdef MAC #define EOL "\x0D" #else #define EOL "\x0A" #endif #endif extern char *get_variable_name (int offset); extern struct location *current_station_location (void); /*----------------------------------------------------------------------*\ | Code to handle byte-ordering problems. | \*----------------------------------------------------------------------*/ enum byte_order_t { LSBfirst, MSBfirst }; static enum byte_order_t get_byte_order (void) { unsigned short w = 255; unsigned char *s = (unsigned char *) &w; if (*s) return (LSBfirst); else return (MSBfirst); } static enum byte_order_t byte_order = LSBfirst; #ifndef ASM_SWAB static void swab_word (void *p) { unsigned char *s,q; s = (unsigned char *) p; q = *(s+0); *(s+0) = *(s+1); *(s+1) = q; } static void swab_dword (void *p) { unsigned char *s,q; s = (unsigned char *) p; q = *(s+0); *(s+0) = *(s+3); *(s+3) = q; q = *(s+1); *(s+1) = *(s+2); *(s+2) = q; } static void swab_qword (void *p) { unsigned char *s,q; s = (unsigned char *)p; q = *(s+0); *(s+0) = *(s+7); *(s+7) = q; q = *(s+1); *(s+1) = *(s+6); *(s+6) = q; q = *(s+2); *(s+2) = *(s+5); *(s+5) = q; q = *(s+3); *(s+3) = *(s+4); *(s+4) = q; } #else extern void swab_word (void *p); extern void swab_dword (void *p); extern void swab_qword (void *p); #endif /*----------------------------------------------------------------------*\ | Missing cells can be output blank, with the numeric value -99, or | | with asterisks. | \*----------------------------------------------------------------------*/ static char *missing_value_code_table[] = { "", "-99", "***", NULL }; static char *missing_value_code = ""; /*----------------------------------------------------------------------*\ | Tab-delimited ASCII format | \*----------------------------------------------------------------------*/ static FILE *geomet_open_text_tab (char *name, int *order) { FILE *out; if (out = fopen (name,"wb")) { sprintf (msg,"%s","Date"); fwrite (msg,1,strlen(msg),out); sprintf (msg,"\t%s","Time"); fwrite (msg,1,strlen(msg),out); while (*order != -1) { *msg = '\t'; strcpy (msg+1,get_variable_name (*order)); fwrite (msg,1,strlen(msg),out); order++; } strcpy (msg,EOL); fwrite (msg,1,strlen(msg),out); } return (out); } static int geomet_output_text_tab (FILE *out, struct dwd *d, int *order) { size_t n; float *f; float value; char *s; int *p; for (p=order; *p != -1; p++) { f = (float *) (((char *)d) + *p); if (*f != MISSING_VALUE) break; } if (*p == -1) return (0); sprintf (msg,"%02d%03d\t%02d%02d",d->year,d->day,d->hour,d->minute); s = msg + strlen (msg); for (p=order; *p != -1; p++) { f = (float *) (((char *)d) + *p); if (*f == MISSING_VALUE) sprintf (s,"\t%s",missing_value_code); else sprintf (s,"\t%.3f",*f); s += strlen (s); } strcpy (s,EOL); n = strlen (msg); fwrite (msg,1,n,out); return ((int)n); } static void geomet_close_text_tab (FILE *out) { if (out) fclose (out); } /*----------------------------------------------------------------------*\ | Comma-delimited ASCII format | \*----------------------------------------------------------------------*/ static FILE *geomet_open_text_comma (char *name, int *order) { FILE *out; if (out = fopen (name,"wb")) { sprintf (msg,"%s","Date"); fwrite (msg,1,strlen(msg),out); sprintf (msg,",%s","Time"); fwrite (msg,1,strlen(msg),out); while (*order != -1) { *msg = ','; strcpy (msg+1,get_variable_name (*order)); fwrite (msg,1,strlen(msg),out); order++; } strcpy (msg,EOL); fwrite (msg,1,strlen(msg),out); } return (out); } static int geomet_output_text_comma (FILE *out, struct dwd *d, int *order) { size_t n; float *f; float value; char *s; int *p; for (p=order; *p != -1; p++) { f = (float *) (((char *)d) + *p); if (*f != MISSING_VALUE) break; } if (*p == -1) return (0); sprintf (msg,"%02d%03d,%02d%02d",d->year,d->day,d->hour,d->minute); s = msg + strlen (msg); for (p=order; *p != -1; p++) { f = (float *) (((char *)d) + *p); if (*f == MISSING_VALUE) sprintf (s,",%s",missing_value_code); else sprintf (s,",%.3f",*f); s += strlen (s); } strcpy (s,EOL); n = strlen (msg); fwrite (msg,1,n,out); return ((int)n); } static void geomet_close_text_comma (FILE *out) { if (out) fclose (out); } /*----------------------------------------------------------------------*\ | WKS is the worksheet file format for Lotus 123 version 1. | | These symbols are the opcodes common to 123 and Symphony. | \*----------------------------------------------------------------------*/ #define WKS_BOF 0x0000 #define WKS_EOF 0x0001 #define WKS_CALCMODE 0x0002 #define WKS_CALCORDER 0x0003 #define WKS_RANGE 0x0006 #define WKS_COLW1 0x0008 #define WKS_BLANK 0x000C #define WKS_INTEGER 0x000D #define WKS_NUMBER 0x000E #define WKS_LABEL 0x000F #define WKS_FORMULA 0x0010 #define WKS_TABLE 0x0018 #define WKS_FRANGE 0x001C #define WKS_HRANGE 0x0020 #define WKS_PROTEC 0x0024 #define WKS_LABELFMT 0x0029 #define WKS_CALCCOUNT 0x002F #define WKS_UNFORMATTED 0x0030 #define WKS_CURSORW12 0x0031 static unsigned short wks_row, wks_column; static void write_wks_blank (FILE *out, char format) { struct wks_blank_t { unsigned short opcode; unsigned short length; unsigned char format; unsigned char c0,c1; unsigned char r0,r1; } *b = (struct wks_blank_t *) &msg; unsigned short r,c; b->opcode = WKS_BLANK; b->length = 5; b->format = format; r = wks_row; c = wks_column; if (byte_order == MSBfirst) { swab_word (&b->opcode); swab_word (&b->length); swab_word (&r); swab_word (&c); } memcpy (&b->c0,&c,2); memcpy (&b->r0,&r,2); fwrite (b,1,9,out); } static void write_wks_label (FILE *out, char *label) { struct wks_label_t { unsigned short opcode; unsigned short length; unsigned char format; unsigned char c0,c1; unsigned char r0,r1; unsigned char string[1]; } *b = (struct wks_label_t *) &msg; unsigned short r,c; b->opcode = WKS_LABEL; b->length = 7 + strlen (label); b->format = 0x75; r = wks_row; c = wks_column; if (byte_order == MSBfirst) { swab_word (&b->opcode); swab_word (&b->length); swab_word (&r); swab_word (&c); } memcpy (&b->c0,&c,2); memcpy (&b->r0,&r,2); b->string[0] = '\''; strcpy (&b->string[1],label); fwrite (b,1,11+strlen(label),out); } static void write_wks_integer (FILE *out, int value, char format) { struct wks_integer_t { unsigned short opcode; unsigned short length; unsigned char format; unsigned char c0,c1; unsigned char r0,r1; unsigned char d0,d1; } *b = (struct wks_integer_t *) &msg; unsigned short r,c; short v; b->opcode = WKS_INTEGER; b->length = 7; b->format = format; r = wks_row; c = wks_column; v = (short) value; if (byte_order == MSBfirst) { swab_word (&b->opcode); swab_word (&b->length); swab_word (&r); swab_word (&c); swab_word (&v); } memcpy (&b->c0,&c,2); memcpy (&b->r0,&r,2); memcpy (&b->d0,&v,2); fwrite (b,1,11,out); } static void write_wks_number (FILE *out, double value, char format) { struct wks_number_t { unsigned short opcode; unsigned short length; unsigned char format; unsigned char c0,c1; unsigned char r0,r1; unsigned char value[8]; } *b = (struct wks_number_t *) &msg; unsigned short r,c; b->opcode = WKS_NUMBER; b->length = 13; b->format = format; r = wks_row; c = wks_column; if (byte_order == MSBfirst) { swab_word (&b->opcode); swab_word (&b->length); swab_word (&r); swab_word (&c); swab_qword (&value); } memcpy (&b->c0,&c,2); memcpy (&b->r0,&r,2); memcpy (&b->value[0],&value,8); fwrite (b,1,17,out); } static FILE *geomet_open_wks (char *name, int *order) { FILE *out; byte_order = get_byte_order(); if (out = fopen (name,"wb")) { unsigned short opcode; unsigned short length; unsigned short revision; opcode = WKS_BOF; length = 2; revision = 0x0404; if (byte_order == MSBfirst) { swab_word (&opcode); swab_word (&length); /* swab_word (&revision); */ } memcpy (msg+0,&opcode,2); memcpy (msg+2,&length,2); memcpy (msg+4,&revision,2); fwrite (msg,1,6,out); wks_row = 0; wks_column = 0; write_wks_label (out,"Date"); wks_column++; write_wks_label (out,"Time"); wks_column++; while (*order != -1) { write_wks_label (out,get_variable_name (*order)); wks_column++; order++; } wks_column = 0; wks_row++; } return (out); } static double day_number_since_691231 (int year, int day) { int y; double d; d = 25568.0; for (y=70; y < year; y++) if (y & 3) d += 365.0; else d += 366.0; d += day; return (d); } static int geomet_output_wks (FILE *out, struct dwd *d, int *order) { double value; float *f; char format; int *p; for (p=order; *p != -1; p++) { f = (float *) (((char *)d) + *p); if (*f != MISSING_VALUE) break; } if (*p == -1) return (0); value = day_number_since_691231(d->year,d->day); format = 0x72; write_wks_number (out,value,format); wks_column++; value = ((double) (d->hour * 60 + d->minute))/1440.0; format = 0x78; write_wks_number (out,value,format); wks_column++; format = 0x03; for (p=order; *p != -1; p++) { value = (double) *((float *) (((char *)d) + *p)); if (value == MISSING_VALUE) write_wks_blank (out,0xF1); else write_wks_number (out,value,format); wks_column++; } wks_column = 0; wks_row++; return (1); } static void geomet_close_wks (FILE *out) { unsigned short opcode; unsigned short length; opcode = WKS_EOF; length = 0; if (byte_order == MSBfirst) { swab_word (&opcode); /* swab_word (&length); */ } memcpy (msg,&opcode,2); memcpy (msg+2,&length,2); fwrite (msg,1,4,out); fclose (out); } /*----------------------------------------------------------------------*\ | Desert Winds project internal format | \*----------------------------------------------------------------------*/ static FILE *geomet_open_text_dwp (char *name, int *order) { FILE *out; if (out = fopen (name,"wb")) { strcpy (msg," 20FT 20FT 8.8FT 4FT 4FT 20FT 4FT 4CM 10CM 20CM"); strcat (msg,EOL); fwrite (msg,1,strlen(msg),out); strcpy (msg," DATE LAT LONG TIME HUMID PRECIP BARO WIND WIND PEAK WIND WIND PEAK AIR AIR SOIL SOIL SOIL"); strcat (msg,EOL); fwrite (msg,1,strlen(msg),out); strcpy (msg," PRESS DIR SPEED GUST SPEED SPEED GUST TEMP TEMP TEMP TEMP TEMP"); strcat (msg,EOL); fwrite (msg,1,strlen(msg),out); strcpy (msg,EOL); fwrite (msg,1,strlen(msg),out); } return (out); } static int geomet_output_text_dwp (FILE *out, struct dwd *d, int *order) { size_t n; float *f; float value; char *s; int *p; struct location *L; L = current_station_location(); s = msg; sprintf (s," %02d%03d",d->year,d->day); s += strlen(s); sprintf (s," %3d%02d%02d",L->latitude.degrees,L->latitude.minutes,L->latitude.seconds); s += strlen(s); sprintf (s," %3d%02d%02d",L->longitude.degrees,L->longitude.minutes,L->longitude.seconds); s += strlen(s); sprintf (s," %02d%02d",d->hour,d->minute); s += strlen(s); if (d->hum == MISSING_VALUE) sprintf (s," ******"); else sprintf (s,"%7.2f",d->hum); s += 7; if (d->ppt == MISSING_VALUE) sprintf (s," *****"); else sprintf (s,"%6.2f",d->ppt); s += 6; if (d->bp == MISSING_VALUE) sprintf (s," ******"); else sprintf (s,"%7.3f",d->bp); s += 7; if (d->wd == MISSING_VALUE) sprintf (s," ******"); else sprintf (s,"%7.2f",d->wd); s += 7; if (d->ws20 == MISSING_VALUE) sprintf (s," *****"); else sprintf (s,"%6.2f",d->ws20); s += 6; if (d->pg20 == MISSING_VALUE) sprintf (s," *****"); else sprintf (s,"%6.2f",d->pg20); s += 6; if (d->ws88 == MISSING_VALUE) sprintf (s," *****"); else sprintf (s,"%6.2f",d->ws88); s += 6; if (d->ws4 == MISSING_VALUE) sprintf (s," *****"); else sprintf (s,"%6.2f",d->ws4); s += 6; if (d->pg4 == MISSING_VALUE) sprintf (s," *****"); else sprintf (s,"%6.2f",d->pg4); s += 6; if (d->at20 == MISSING_VALUE) sprintf (s," *****"); else sprintf (s,"%6.2f",d->at20); s += 6; if (d->at4 == MISSING_VALUE) sprintf (s," *****"); else sprintf (s,"%6.2f",d->at4); s += 6; if (d->st4 == MISSING_VALUE) sprintf (s," *****"); else sprintf (s,"%6.2f",d->st4); s += 6; if (d->st10 == MISSING_VALUE) sprintf (s," *****"); else sprintf (s,"%6.2f",d->st10); s += 6; if (d->st20 == MISSING_VALUE) sprintf (s," *****"); else sprintf (s,"%6.2f",d->st20); s += 6; strcpy (s,EOL); n = strlen (msg); fwrite (msg,1,n,out); return ((int)n); } static void geomet_close_text_dwp (FILE *out) { if (out) fclose (out); } /*----------------------------------------------------------------------*\ | Function to return a pointer to a function that writes one geomet | | data record, given a format name. | \*----------------------------------------------------------------------*/ typedef FILE*(*geomet_open_function)(char *name, int *order); typedef int(*geomet_output_function)(FILE *f, struct dwd *d, int *order); typedef void(*geomet_close_function)(FILE *f); struct geomet_output_function_table_t { char *name; geomet_open_function opener; geomet_output_function writer; geomet_close_function closer; }; static struct geomet_output_function_table_t geomet_output_function_table [] = { {"Tab-delimited ASCII", geomet_open_text_tab, geomet_output_text_tab, geomet_close_text_tab}, {"Comma-delimited ASCII", geomet_open_text_comma, geomet_output_text_comma, geomet_close_text_comma}, {"Desert Winds project", geomet_open_text_dwp, geomet_output_text_dwp, geomet_close_text_dwp}, {"WKS (Lotus 123)", geomet_open_wks, geomet_output_wks, geomet_close_wks}, {NULL, NULL, NULL, NULL} }; geomet_open_function get_open_function (char *format_name) { int i; for (i=0; geomet_output_function_table[i].name; i++) if (strcmp (format_name,geomet_output_function_table[i].name) == 0) return (geomet_output_function_table[i].opener); sprintf (msg,"Error: unrecognized output format \"%s\"",format_name); dw_error (msg); return (NULL); } geomet_output_function get_output_function (char *format_name) { int i; for (i=0; geomet_output_function_table[i].name; i++) if (strcmp (format_name,geomet_output_function_table[i].name) == 0) return (geomet_output_function_table[i].writer); sprintf (msg,"Error: unrecognized output format \"%s\"",format_name); dw_error (msg); return (NULL); } geomet_close_function get_close_function (char *format_name) { int i; for (i=0; geomet_output_function_table[i].name; i++) if (strcmp (format_name,geomet_output_function_table[i].name) == 0) return (geomet_output_function_table[i].closer); sprintf (msg,"Error: unrecognized output format \"%s\"",format_name); dw_error (msg); return (NULL); } /*----------------------------------------------------------------------*\ \*----------------------------------------------------------------------*/