/****************************************************************************//*																			*//*								IAGA_to_TEXT.c								*//*																			*//****************************************************************************//****************************************************************************//* This is a filter program that reads a IAGA format data file and writes	*//* out the same data in text columns.										*//*																			*//* Usage:																	*//*  IAGA_to_TEXT [-s] [-e | -h] [-o] [-c] [-a] [-v | -g] [-y] [-z]			*//*											[<] IAGAFile > TEXTFile			*//*		[-s YYMMDDHH]		Time of the first record included. If missing	*//*							then start of file is assumed.					*//*		[-e YYMMDDHH]		Time of the record not included anymore. If		*//*							missing then end of file is assumed.			*//*		[-h HH]				Number of hours included. Either -e or -h can	*//*							be specified, not both.							*//*		[-o 'Station list']	List of stations delimited by aposthropes		*//*							If missing then all stations included.			*//*							Stations are identified by three-letter code	*//*							and separated by exactly one space.				*//*		[-c 'CompList']		Components to be written. Possible values are	*//*							tXYZT (=time,X,Y,Z,Temperature). Default value	*//*							is tXYZ (so temperature is not written.). Time	*//*							is written in the format YYYY MM DD HH MM SS.	*//*		[-a AverPeriod]		Don't write all data values but averages over	*//*							AverPeriod.										*//*		[-v]				Write headers (= Station name + Component)		*//*							If missing then no headers are written			*//*		[-g]				Write the geographic coordinates of stations	*//*							into the first line. This can be used only if	*//*							-c option is not given (=tXYZ) and then the		*//*							format of the line is:							*//*							0 0 0 0 0 0 lat_1 lon_1 0 ... lat_N lon_N 0.	*//*		[-y]				Write the year string with two digits. Default	*//*							value is 4 digits (century included).			*//*		[-z]				For FMI internal use only. This option writes   *//*							the time in Finnish local time. The times 		*//*							defined in -s and -e options must be, however,	*//*							in UT.											*//*		IAGAFile			Name of IAGA-format file.						*//*		TEXTFile			Name of TEXT file.								*//*																			*//****************************************************************************//****************************************************************************//*                            Lasse Hakkinen                                *//*                    Finnish Meteorological Institute                      *//*                        Geophysical Research Division                     *//*                              P.O.Box 503                                 *//*                      FIN-00101, Helsinki, Finland                        *//*                      e-mail: Lasse.Hakkinen@fmi.fi                       *//*                      phone : (+358)-9-19294634                           *//*                      fax   : (+358)-9-19294603                           *//*																			*//*						version 1.08		15.03.2006						*//****************************************************************************//****************************************************************************//*	Version history:														*//*																			*//*	1.08 15.03.2006	Added -z option.										*//*	1.07 12.05.2005	Fixed a bug in IAGA.h where the data was incorrectly	*//*					read if there were missing data blocks in the IAGA file.*//*	1.06 14.11.2002	Added -g option.										*//*	1.05 19.01.2000	Added -y option and changed the default year string		*//*					format to YYYY. Also added the checking of magnetic		*//*					components.												*//*	1.04 09.09.1999	Fixed a Y2K bug in NewTime.h file which resulted in     *//*					incorrect year in date strings if year >= 2000.			*//*	1.03 19.11.1998 Added the invisible -m option.							*//*	1.02 22.10.1998 Internal modification due to change of the MissingValue	*//*					data marker.											*//*	1.01 16.10.1998 Fixed a bug where some data was not read if StartTime	*//*					given in the command line was not exactly same as the	*//*					start time of an IAGA block.							*//*	1.0  15.01.1997	First official release									*//****************************************************************************/#include <stdio.h>#include <string.h>#include <stdlib.h>#include "Usage.h"#include "MagnData.h"#include "IAGA.h"char *version = "1.07";char *date = "12.05.2005";#define HeaderLineCount 4#define UsageLineCount 28char *HeaderText[HeaderLineCount] = {"**************************************************************************","This program reads an IAGA-format magnetometer data file and writes out   ","the data for given components and stations in columnar format (TEXT).     ","**************************************************************************",};char *UsageText[UsageLineCount] = {" [-s] [-e | -h] [-o] [-c] [-a] [-v | -g] [-y] [<] IAGAFile > TEXTFile","       [-s YYMMDDHH]       Time of the first record included. If missing   ","                           then start of file is assumed.                  ","       [-e YYMMDDHH]       Time of the record not included anymore. If     ","                           missing then end of file is assumed.            ","       [-h HH]             Number of hours included. Either -e or -h can   ","                           be specified, not both.                         ","       [-o 'Station list'] List of stations delimited by aposthropes       ","                           If missing then all stations included.          ","                           Stations are identified by three-letter code    ","                           and separated by exactly one space.             ","       [-c 'CompList']     List of components to be printed. Possible      ","                           values for the components are t,X,Y,Z,T. Here   ","                           t is time and T is temperature. The format of   ","                           time is YYYY MM DD HH MM SS. Default value for  ","                           CompList is tXYZ (temperature is not written).  ","       [-a AverPeriod]     Write data values as averages over AverPeriod.  ","       [-v]                Write headers (= Station names + components).   ","                           If missing then no headers are written.         ","       [-g]                Write the geographic coordinates of the stations","                           into the first line. This can be used only if   ","                           the -c option is not defined (= -tXYZ, default).","                           The format of the first line is then:           ","                           0 0 0 0 0 0 lat_1 lon_1 0 ... lat_N lon_N 0     ","       [-y]                Write year string with two digits. Default value","                           is four (century included).                     ","       IAGAFile            Name of IAGA-format file.                       ","       TEXTFile            Name of ASCII file.                             ",};/*--------------------------------------------------------------------------*//*	Write headers (= Station name + component).								*//*--------------------------------------------------------------------------*/void WriteHeaders(NetworkPtr NETWORK, char *CompStr, long Year2option){	long i,CompCount;	StationPtr s;		CompCount = strlen(CompStr);		/* Write time */	if (CompStr[0] == 't') {		if (Year2option == 1) 			printf("YY MM DD HH MM SS   ");		else			printf("YYYY MM DD HH MM SS   ");		CompCount--;	}		/* Write station names and components */	s = NETWORK->StationList;	while (s != NULL) {		for (i = strlen(CompStr)-CompCount; i < strlen(CompStr); i++)			printf("  %s %c ",s->StationID,CompStr[i]);		s = s->Next;	}	printf("\n");}/*--------------------------------------------------------------------------*//*	Write horizontal line.													*//*--------------------------------------------------------------------------*/void WriteHorLine(NetworkPtr NETWORK, char *CompStr, long Year2option){	long i,CompCount;		CompCount = strlen(CompStr);			/* Write a dashed line */	if (CompStr[0] == 't') {		if (Year2option == 1)			printf("--------------------");		else			printf("----------------------");		CompCount--;	}	for (i = 0; i < CompCount*(NETWORK->StationCount);i++)		printf("--------");	printf("\n");}/*--------------------------------------------------------------------------*//*	Write geographic locations of the stations in format:					*//*	0 0 0 0 0 0 lat_1 lon_1 0  ...  lat_N lon_N 0							*//*--------------------------------------------------------------------------*/void WriteLocations(NetworkPtr NETWORK, char *CompStr, long Year2option){	long i,CompCount;	StationPtr s;		CompCount = strlen(CompStr);			/* Write time */	if (CompStr[0] == 't') {		if (Year2option == 1) 			printf(" 0  0  0  0  0  0   ");		else			printf("   0  0  0  0  0  0   ");		CompCount--;	}		/* Write station locations */	s = NETWORK->StationList;	while (s != NULL) {		printf("   %5.2f   %5.2f     0  ",(s->Latitude)/100.0,(s->Longitude)/100.0);		s = s->Next;	}	printf("\n");}/*--------------------------------------------------------------------------*//*	Write headers in a special format used by Ari. This is defined by the	*//*	invisible option -m.													*//*--------------------------------------------------------------------------*/void WriteAriHeaders(NetworkPtr NETWORK, char *CompStr){	long i,CompCount;	StationPtr s;	char DateStr[14];	long First = 1;		CompCount = strlen(CompStr);	if (CompStr[0] == 't') {		CompCount--;	}	/* Write first comment line including station names and components */	printf("%%       ");	s = NETWORK->StationList;	while (s != NULL) {		for (i = strlen(CompStr)-CompCount; i < strlen(CompStr); i++)			printf("  %s %c ",s->StationID,CompStr[i]);		s = s->Next;	}	printf("\n");	/* Write time */	s = NETWORK->StationList;	SecsToStr(s->StartTime,DateStr);	if (s->StartTime < YEAR2000)		printf("19%");	else		printf("20");		printf("%.2s %.2s %.2s",DateStr,DateStr+2,DateStr+4);	while (s != NULL) {		for (i = strlen(CompStr)-CompCount; i < strlen(CompStr); i++) {			if (First) {				printf("   0");				First = 0;			} else				printf("       0");		}		s = s->Next;	}	printf("\n");}/*--------------------------------------------------------------------------*//*	Find if summer time is in effect in Finland at the specified time.		*//*	Returns 1 if yes and 0 if not.											*//*	Summer time in Finland starts on last sunday in March and ends on last	*//*	sunday on October.														*//*--------------------------------------------------------------------------*/long SummerTime(Time_sec T){	Time_struct SummerStart = {0,0,1,31, 2, 0};	/* {secs,mins,...,years}	*/	Time_struct SummerEnd   = {0,0,1,31, 9, 0};	/* {secs,mins,...,years}	*/	Time_struct CurrentTime;	Time_struct RefSunday   = {0,0,0, 4, 0,81};	Time_sec SummerStartSec,SummerEndSec,RefSundaySec;		SecsToTm(T,&CurrentTime);	SummerStart.tm_year = CurrentTime.tm_year;	SummerEnd.tm_year   = CurrentTime.tm_year;		SummerStartSec = TmToSecs(&SummerStart);	SummerEndSec   = TmToSecs(&SummerEnd);	RefSundaySec   = TmToSecs(&RefSunday);	SummerStartSec -= 86400*(((SummerStartSec - RefSundaySec)/86400) % 7);	SummerEndSec   -= 86400*(((SummerEndSec - RefSundaySec)/86400) % 7);		if ((T > SummerStartSec) && (T < SummerEndSec)) return 1;	else return 0;}/*--------------------------------------------------------------------------*//*							The main procedure								*//*--------------------------------------------------------------------------*/int main(int argc, char *argv[]){	long params;	long status    = 0;	long FileCount = 0;	long HourCount = 0;	long AvePeriod = 0;	long i,Ave;	char FileName[100]    = "";	char StartTimeStr[14] = "";	char EndTimeStr[14]   = "";	char StationStr[200]  = "";	char ComponentStr[14] = "";	StationPtr s;	Time_sec t,EndTime,CurrTime;	long FirstComp;	long HeaderFlag = 0;	long AriOption = 0;			/* A special formatting option used by Ari	*/	long LocationFlag = 0;		/* Flag for writing geographic locations	*/	long Year2option = 0;		/* Print year with two digits, default = 4	*/	char TimeStr[20];	long Finnish = 0;			/* Use Finnish local time. -z option		*/		Network_struct NETWORK;		/*==========================*/	/* Analyse the command line */	/*==========================*/	if (argc == 1) {		/* No arguments, show the usage text */		PrintUsage(argv[0],0,HeaderLineCount,UsageLineCount);		return OK;	}	for (params = 1; params < argc; params++) {		if (*argv[params] != '-') {			strcpy(FileName,argv[params]);			FileCount++;		} else {			switch (*(argv[params]+1)) {				case 's' : strcpy(StartTimeStr,argv[++params]); break;				case 'e' : strcpy(EndTimeStr,argv[++params]);   break;				case 'h' : HourCount = atol(argv[++params]);    break;				case 'o' : strcpy(StationStr,argv[++params]);   break;				case 'c' : strcpy(ComponentStr,argv[++params]);	break;				case 'a' : AvePeriod = atol(argv[++params]); 	break;				case 'v' : HeaderFlag = 1;					 	break;				case 'm' : AriOption = 1;					 	break;				case 'g' : LocationFlag = 1;				 	break;				case 'y' : Year2option = 1;					 	break;				case 'z' : Finnish = 1;							break;				case 'p' : /* Do nothing */						break;				default  :					fprintf(stderr,"\n### %s: \"%s\" is not an option.\n\n",							argv[0], argv[params]);					PrintUsage(argv[0],1,HeaderLineCount,UsageLineCount);					return FAIL;					break;			}		}	}		/*====================================*/	/* Check the values of the parameters */	/*====================================*/		if (FileCount > 1) {		PrintUsage(argv[0],1,HeaderLineCount,UsageLineCount);		return FAIL;	}	if ((HourCount != 0) && (strlen(EndTimeStr) > 0)) {		PrintUsage(argv[0],1,HeaderLineCount,UsageLineCount);		return FAIL;	}	if ((HourCount != 0) && (strlen(StartTimeStr) == 0)) {		PrintUsage(argv[0],1,HeaderLineCount,UsageLineCount);		return FAIL;	}	if ((LocationFlag == 1) && (strlen(ComponentStr) > 0)) {		PrintUsage(argv[0],1,HeaderLineCount,UsageLineCount);		return FAIL;	}	if (HourCount != 0) {		SecsToStr(StrToSecs(StartTimeStr,0)+3600*HourCount,EndTimeStr);	}	/*====================================================*/	/* Read the data from an IAGA format file into memory */	/*====================================================*/	status = ReadIAGA(FileName,&NETWORK,StartTimeStr,EndTimeStr,StationStr);	if (status != 0) {		if (status == FileError)			fprintf(stderr,"Error in reading file %s\n",FileName);		if (status == OutOfMemory)			fprintf(stderr,"Out of memory while reading file %s\n",FileName);		if (status == FileFormatError)			fprintf(stderr,"%s is not an IAGA format file\n",FileName);		return FAIL;	}	/*===============================*/	/* Check the magnetic components */	/*===============================*/	if (strlen(ComponentStr) == 0) {		*ComponentStr = 't';		strcpy(ComponentStr+1,NETWORK.StationList->Components);	}	else {		for (i=0;i<strlen(ComponentStr);i++) {			if (ComponentStr[i] == 't') continue;			if (strchr(NETWORK.StationList->Components,ComponentStr[i]) == NULL) {				fprintf(stderr,"Component %c not found in data file %s\n",													ComponentStr[i],FileName);				return FAIL;			}		}	}	/*==========================================*/	/* Write the data in columns into stdout	*/	/*==========================================*/		if (AriOption)		WriteAriHeaders(&NETWORK,ComponentStr);	else {		if (HeaderFlag) WriteHeaders(&NETWORK,ComponentStr,Year2option);		if (LocationFlag) WriteLocations(&NETWORK,ComponentStr,Year2option);		if (HeaderFlag) WriteHorLine(&NETWORK,ComponentStr,Year2option);	}	if (AvePeriod == 0) AvePeriod = NETWORK.StationList->TimeStep;		if (strlen(StartTimeStr) == 0)		t = NETWORK.StationList->StartTime;	else		t = StrToSecs(StartTimeStr,0);	if (strlen(EndTimeStr) == 0)		EndTime = NETWORK.StationList->EndTime;	else		EndTime = StrToSecs(EndTimeStr,0);			while (t < EndTime) {		FirstComp = 0;		if (AriOption) {			SecsToStr(t,TimeStr);			printf("%.2s %.2s %.2s",TimeStr+6,TimeStr+8,TimeStr+10);						FirstComp++;		}		else			if (ComponentStr[0] == 't') {		/* Write time */								CurrTime = t;				if (Finnish) {	/* Display time in Finnish time */  					CurrTime += (2 + SummerTime(CurrTime))*3600;				}				SecsToStr(CurrTime,TimeStr);				if (Year2option == 0) {		/* Write century */					if (CurrTime >= YEAR2000)						printf("20");					else						printf("19");				}				printf("%.2s %.2s %.2s %.2s %.2s %.2s   ",TimeStr,TimeStr+2,						TimeStr+4,TimeStr+6,TimeStr+8,TimeStr+10);							FirstComp++;			}				s = NETWORK.StationList;			/* go through the stations */		while (s != NULL) {			for (i=FirstComp;i<strlen(ComponentStr);i++) {				Ave = ComputeAverage(s,ComponentStr[i],t,AvePeriod);				if (Ave != MissingValue)					printf(" %7.1f",Ave/10.0);				else					printf(" 99999.9");			}			s = s->Next;		}		printf("\n");				t += AvePeriod;	}	FreeNetwork(&NETWORK);	return OK;}
