/****************************************************************************/ /* */ /* Dump.h */ /* */ /****************************************************************************/ /****************************************************************************/ /* This is a C language header file that defines a routine for reading */ /* 'dump' format data files into memory. The dump format is a data format */ /* used at Nurmijarvi Observatory to store raw magnetometer data. */ /* */ /* ------------------- Read data from a dump-format file -------------- */ /* */ /* long ReadDump(char *FileName,NetworkPtr Network,char *StartTimeStr, */ /* char *EndTimeStr,char *StationList) */ /* FileName Name of the dump-file containing the data. */ /* If FileName is nil or zero length then standard */ /* input is used. */ /* Network Structure into which the data is read. */ /* Network_struct is defined in file MagnData.h. */ /* StartTimeStr String defining the first time to be read from */ /* the data file (String delimited with '\0'). */ /* String format : YYMMDDHH. If HH is missing then */ /* 00 is assumed. If StartTimeStr is nil or zero */ /* length then start of file is assumed. */ /* EndTimeStr String defining the time not to be read anymore. */ /* Format as before YYMMDDHH. If nil or zero length */ /* then data is read until end of file. */ /* StationList List of stations included in the data. The stations */ /* must be specified with three letter codes */ /* (e.g. SOR) and must be separeted with a space in */ /* the list (e.g. 'SOR MAS KEV'). If nil or zero */ /* length then all stations in the file are included. */ /* */ /* The function result indicates how successfull the file reading was: */ /* 0: OK : File read successfully */ /* 1: FileError : Failed to read the given file */ /* 2: OutOfMemory : Memory allocation failed during reading */ /* 3: FormatError : File to be read is not Dump file */ /* */ /* ------------------- Write data into a dump-format file -------------- */ /* */ /* long WriteDump(char *FileName,NetworkPtr Network,char *StartTimeStr, */ /* char *EndTimeStr,char *StationList) */ /* FileName Name of the Dump file. IF NULL or zero length then */ /* stdout is used. */ /* Network Pointer to the Network structure whose data is to */ /* be written into a file. */ /* StartTimeStr Start date string YYMMDDHHMM. If NULL then same as */ /* the time of the first record of the first station */ /* in the Network data structure. */ /* EndTimeStr End date string YYMMDDHHMM. This record is NOT */ /* included anymore. If NULL then data till the end of */ /* first station in Network structure will be written. */ /* StationList String containing the 3-letter ID's of the station. */ /* Only one station is allowed. */ /* */ /* The function result indicates how successfull the file writing was: */ /* 0: OK : Data written successfully */ /* 1: FileError : Failed to create the given file */ /* */ /* NOTE: Contrary to almost all other data format header files data in */ /* Dump.h is read into Network-structure using 0.01 nT field */ /* resolution. All the others (e.g. IAGA.h) use 0.1 nT resolution. */ /* This must be taken into account e.g. when writing format */ /* conversion filters. */ /****************************************************************************/ /****************************************************************************/ /* Lasse Hakkinen */ /* Finnish Meteorological Institute */ /* Department of Geophysics */ /* P.O.Box 503 */ /* FIN-00101, Helsinki, Finland */ /* e-mail: Lasse.Hakkinen@fmi.fi */ /* phone : (+358)-9-19294634 */ /* fax : (+358)-9-19294603 */ /* */ /* version 1.29 15.01.2020 */ /****************************************************************************/ /****************************************************************************/ /* Version history: */ /* */ /* 1.29 15.01.2020 Modified CheckDumpLine routine for better checking of */ /* data line validity. */ /* 1.28 02.01.2020 Date strings must be YYYYMMDD (four digits for year) */ /* Replaced StrToSecs -> StrToSecsC and */ /* SecsToStr -> SecsToStrC. */ /* 1.27 19.10.2016 Added J = NU2 and L = NU3 codes. */ /* 1.26 21.06.2016 Fixed a bug where the resolution was wrongly read if */ /* the first 'd' line contained invalid data values. */ /* 1.25 17.09.2014 Added Ranua station code 'R'. */ /* 1.24 08.05.2006 Fixed a bug where reading failed when there is a data */ /* gap and more than 24 hours of data. */ /* 1.23 09.11.2005 Changed MaxParamLineCount to 10000. */ /* 1.22 04.10.2004 Added station code 'I' for Mekrijarvi station. */ /* 1.21 08.03.2004 Modified ReadDump so that it does not stop if d-line */ /* contains illegal characters or its length is not OK. */ /* In these situations the erronuous line is neglected. */ /* 1.20 07.11.2003 Added CheckLine-routine for checking illegal characters */ /* in the data file. Also added line length checking. */ /* 1.19 15.10.2001 Fixed a bug which caused a crash when reading unix */ /* format data file in a Mac. */ /* 1.18 18.09.2001 Changed station code 'T' from O_E to TAR (= Tartu) */ /* 1.17 15.10.1999 Modified NextDumpLine so that it neglects the last data */ /* line if it does not end with CR or LF. This prevents */ /* some mysterious behaviour. */ /* 1.16 13.10.1999 Remodified ReadDump so that it no longer breaks program */ /* execution if data lines are not in chronological order. */ /* 1.15 02.02.1999 made GetDumpTime-routine non-static. */ /* 1.14 20.11.1998 Fixed a bug which multiplied field values by 10 if data */ /* was written in Dump format with 0.1 nT resolution. */ /* 1.13 11.11.1998 Changed MaxParamLineCount to 200. */ /* 1.12 05.11.1998 Added station codes R,V,L,Q,W . */ /* 1.11 28.10.1998 Modified read and write routines so that the extra */ /* s-component is read into the A-field in Station_struct. */ /* 1.1 21.10.1998 When reading data into memory a field resolution of */ /* 0.01 nT is used (previously 0.1 nT). WriteDump routine */ /* added. */ /* 1.03 29.09.1998 Modified ReadDump so that it no longer breaks program */ /* execution if data lines are not in chronological order. */ /* 1.02 15.09.1998 Modified ReadDump so that it no longer breaks program */ /* execution if two data lines have same time. */ /* 1.01 17.07.1998 Modified GetFloat so that field values '*********' are */ /* interpreted as missing data values. */ /* 1.0 10.11.1996 First official release */ /****************************************************************************/ #include #include #include /*--------------------------------------------------------------------------*/ /* Define the correspondence between one letter dump station char and the */ /* conventional three letter Station ID (e.g. N = NUR, P = PEL). */ /* New station names may be added by changing StationCodeCount and adding a */ /* new line into the StationName array (the line may be added anywhere in */ /* StationName, not necessarily to end). */ /*--------------------------------------------------------------------------*/ #define StationCodeCount 25 static char *StationName[StationCodeCount] = { "F NUR", "N NUR", "P PEL", "K KIL", "O OUJ", "U OUJ", "H HAN", "I MEK", "M MUO", "E KEV", "S SOR", "A MAS", "R RAN", "L NU3", "3 NJ3", "4 NJ4", "5 NJ5", "6 NJ6", "J NU2", "Q KVI", "W NOR", "V IVA", "G MAN", "B SOD", "T TAR" }; static long LineNbr; /* Current line number */ static char Resolution; /* Number of decimals used in writing */ /* field values in dump file. Must be */ /* either 1 or 2 */ /*--------------------------------------------------------------------------*/ /* Define the variables used for storing information about parameter lines */ /* (= non-d lines = b-,x-,y-,z-,t- ... lines). */ /*--------------------------------------------------------------------------*/ #define MaxParamLineCount 10000 static char ParamLine[MaxParamLineCount][80];/* All non-d lines are stored */ /* into this array */ static Time_sec ParamLineTime[MaxParamLineCount];/* Times of param lines */ static long ParamLineCount = 0; /* Number of parameter lines */ static char ComponentStr[6]; /* Components defined in d-lines. This */ /* must be same in all d-lines. */ static char StationChar; /* One letter station character */ /*--------------------------------------------------------------------------*/ /* Define the offsets of various fields from the beginning of line in a */ /* dump format data file. */ /*--------------------------------------------------------------------------*/ #define Dump_LineID 0 #define Dump_InstrID 1 #define Dump_Components 2 #define Dump_AverageTime 8 #define Dump_Year 12 #define Dump_Month 17 #define Dump_Day 20 #define Dump_Hour 23 #define Dump_Minute 26 #define Dump_Second 29 #define Dump_X 31 #define Dump_Y 40 #define Dump_Z 49 #define Dump_T 58 #define Dump_A 67 #define Dump_TimingChar 15 #define MissingDump 9999999 #define EOFmarker 1 /*--------------------------------------------------------------------------*/ /* Function prototypes */ /*--------------------------------------------------------------------------*/ static long GetFileSize(char *FileName); static long GetPositiveInt(char *p); static long GetFloat(char *p); Time_sec GetDumpTime(char *Line); static void SetDumpStationID(char StatChar,char *StationID); static void SetStationParamsDump(StationPtr Station,char StatChar,char *StatList); static char *NextDumpLine(char *Line); static long CheckLine(char *Line); static long GetLineLength(char *Line); static void AddMissingData(StationPtr Station,Time_sec Time,Time_sec OldTime); static void GetDumpData(StationPtr Station, char *Line, Time_sec Time); static void GetParamLine(char *Line,Time_sec Time); long ReadDump(char *FileName,NetworkPtr Network,char *StartTimeStr, char *EndTimeStr,char *StationList); static void Print1(FILE *DumpFile,long value); static void Print2(FILE *DumpFile,long value); static void WriteXYZ(FILE *DumpFile, StationPtr Station, Time_sec Time); static void WriteParamLine(FILE *DumpFile,char *Line); static void Write_d_line(FILE *DumpFile,StationPtr Station, Time_sec Time); long WriteDump(char *FileName,NetworkPtr Network); /*==========================================================================*/ /* Routines for reading Dump-format files */ /*==========================================================================*/ /*--------------------------------------------------------------------------*/ /* Find size of a data file */ /*--------------------------------------------------------------------------*/ static long GetFileSize(char *FileName) { long dummy = 0; FILE *DataFile; if ((DataFile = fopen(FileName, "r")) != NULL) { dummy = fseek(DataFile,0L,SEEK_END); dummy = ftell(DataFile); fclose(DataFile); } return dummy; } /*--------------------------------------------------------------------------*/ /* Get positive integer value from the Buffer. We could also use sscanf */ /* but this is considerably faster because no checkings are made. */ /*--------------------------------------------------------------------------*/ static long GetPositiveInt(char *p) { long value; while (*p == ' ') p++; /* scan leading spaces */ value = (*p++ -'0'); /* Go through the digits */ while ((*p >= '0') && (*p <= '9')) value = 10*value+(*p++ - '0'); return (value); } /*--------------------------------------------------------------------------*/ /* Get a floating point number from the Buffer. The number may contain */ /* either 1 or 2 decimals. The value is multiplied by 100. This convention */ /* implies the use of 0.01 nT accuracy in field values and 0.01 C accuracy */ /* in temperature values. */ /* We could also use sscanf, but this is considerably faster because no */ /* checkings are made. */ /*--------------------------------------------------------------------------*/ static long GetFloat(char *p) { long value; long negative; while (*p == ' ') p++; /* scan leading spaces */ if (*p == '*') return (MissingValue); /* ignore garbage */ negative = (*p == '-'); /* check the sign */ if (negative) p++; value = (*p++ - '0'); /* get the integer part */ while (*p != '.') value = 10*value+(*p++ - '0'); p++; /* get the first decimal */ value = 10*value+(*p++ -'0'); if ((*p >= '0') && (*p <= '9')) /* get the last decimal */ value = 10*value+(*p++ -'0'); else value *= 10; if (value == MissingDump) /* Missing value may be */ return (MissingValue); /* 99999.99 in dump file */ if (negative) return(-value); /* return the result */ return (value); } /*--------------------------------------------------------------------------*/ /* Get the time of current data line in seconds. 'Line' points to the */ /* first character in the current line. */ /*--------------------------------------------------------------------------*/ Time_sec GetDumpTime(char *Line) { Time_struct MyTime; MyTime.tm_year = GetPositiveInt(Line+Dump_Year)-1900; MyTime.tm_mon = GetPositiveInt(Line+Dump_Month)-1; MyTime.tm_mday = GetPositiveInt(Line+Dump_Day); MyTime.tm_hour = GetPositiveInt(Line+Dump_Hour); MyTime.tm_min = GetPositiveInt(Line+Dump_Minute); MyTime.tm_sec = GetPositiveInt(Line+Dump_Second); return (TmToSecs(&MyTime)); } /*--------------------------------------------------------------------------*/ /* Convert the one character Station code in the dump file into three */ /* letter Station ID string. */ /*--------------------------------------------------------------------------*/ static void SetDumpStationID(char StatChar,char *StationID) { long i = 0; while ((iStationID); /* dump file */ } else { strncpy(Station->StationID,StatList,3); /* Station ID from */ Station->StationID[3] = '\0'; /* command line */ } StationInfo = FindStationInfo(Station->StationID); /* Set the location of the station */ Station->Latitude = StationInfo->Latitude; Station->Longitude = StationInfo->Longitude; /* Set the component markers */ strcpy(Station->Components,"XYZ"); } /*--------------------------------------------------------------------------*/ /* Find the start of next line in the Buffer. The line may be terminated by */ /* a newline (NL) or carriage return (CR) or NL+CR. */ /*--------------------------------------------------------------------------*/ static char *NextDumpLine(char *Line) { register char *ChrPtr = Line; while (*ChrPtr++ > 31); if (*ChrPtr == EOFmarker) return (NULL); /* End of file */ if (*ChrPtr < 32) { /* Linefeed or carriage return */ ChrPtr++; if (*ChrPtr == EOFmarker) return (NULL); } LineNbr++; return(ChrPtr); } /*--------------------------------------------------------------------------*/ /* Check that there are no illegal characters in the line (e.g. letters */ /* after the 7th character). Also check that the spaces are in correct */ /* positions. */ /*--------------------------------------------------------------------------*/ static long CheckLine(char *Line) { register char *p = Line; if (*p == 0) return (0); /* End of file */ if ((Line[0] != 'i') && (Line[0] != 'c')) { if (Line[ 7] != ' ') return (1); if (Line[11] != ' ') return (1); if (Line[16] != ' ') return (1); if (Line[19] != ' ') return (1); if (Line[22] != ' ') return (1); if (Line[25] != ' ') return (1); if (Line[28] != ' ') return (1); if (Line[Dump_X] != ' ') return (1); if (Line[Dump_Y] != ' ') return (1); if (Line[Dump_Z] != ' ') return (1); p = Line+8; while (*p > 31) { if (*p > '9') return (1); if ((*p < '0') && (*p != ' ') && (*p != '-') && (*p != '.')) return (1); p++; } } else { // 'i' or 'c' line may contain letters etc. while (*p > 31) p++; if ((*p != 13) && (*p != 10) && (*p != EOFmarker)) return (1); } return (0); } /*--------------------------------------------------------------------------*/ /* Get the length of the line. */ /*--------------------------------------------------------------------------*/ static long GetLineLength(char *Line) { register char *p = Line; int length = 0; while (*p++ > 31) length++; return (length); } /*--------------------------------------------------------------------------*/ /* Set missing data values from OldTime+TimeStep to Time-TimeStep */ /*--------------------------------------------------------------------------*/ static void SetMissingData(StationPtr Station,Time_sec Time,Time_sec OldTime) { long i,Count; OneDay_struct *p; long *XPtr,*YPtr,*ZPtr,*TPtr,*APtr; /* Find the last OneDayBlock */ for (p = Station->FirstDay; p->NextDay != NULL; p = p->NextDay); /* Set the pointers within the OneDayBlock */ XPtr = (p->X)+(p->XCount); YPtr = (p->Y)+(p->YCount); ZPtr = (p->Z)+(p->ZCount); TPtr = (p->T)+(p->TCount); APtr = (p->A)+(p->TCount); /* Set missing values */ Count = (Time-OldTime)/Station->TimeStep - 1; for (i=0;iXCount += Count; p->YCount += Count; p->ZCount += Count; p->TCount += Count; } /*--------------------------------------------------------------------------*/ /* Copy data from a single data line into the proper OneDayBlock. */ /*--------------------------------------------------------------------------*/ static void GetDumpData(StationPtr Station, char *Line, Time_sec Time) { OneDay_struct *p; long *XPtr,*YPtr,*ZPtr,*TPtr,*APtr; /* Find the last OneDayBlock */ for (p = Station->FirstDay; p->NextDay != NULL; p = p->NextDay); /* Set the pointers within the OneDayBlock */ XPtr = (p->X)+(p->XCount); YPtr = (p->Y)+(p->YCount); ZPtr = (p->Z)+(p->ZCount); TPtr = (p->T)+(p->TCount); APtr = (p->A)+(p->TCount); /* Copy the data */ *XPtr = GetFloat(Line+Dump_X); *YPtr = GetFloat(Line+Dump_Y); *ZPtr = GetFloat(Line+Dump_Z); if (Line[5] == 'T') *TPtr = GetFloat(Line+Dump_T); else *TPtr = MissingValue; if (Line[6] == 's') *APtr = GetFloat(Line+Dump_A); else *APtr = MissingValue; /* Update counters */ p->XCount++; p->YCount++; p->ZCount++; p->TCount++; /* Set the last time */ Station->EndTime = Time+Station->TimeStep; } /*--------------------------------------------------------------------------*/ /* Copy a parameter line into ParamLine-array. */ /*--------------------------------------------------------------------------*/ static void GetParamLine(char *Line,Time_sec Time) { char *p,*q; p = ParamLine[ParamLineCount]; q = Line; while (*q > 31) *p++ = *q++; *p = *q; ParamLineTime[ParamLineCount] = Time; ParamLineCount++; } /*--------------------------------------------------------------------------*/ /* Remove all illegal characters from the buffer. */ /*--------------------------------------------------------------------------*/ static char *Remove_non_ascii_chars(char *Buffer, long count) { char *p = Buffer; char *q = Buffer; long i; for (i = 0; i < count; i++) { if ((*p >= ' ') && (*p <= 'z') || (*p == 10) || (*p == 13) || (*p == EOFmarker)) { *q++ = *p; } p++; } } /*--------------------------------------------------------------------------*/ /* Here is the routine for reading Dump-format data file into memory. */ /* The data is read into a Network structure (see MagnData.h for details). */ /* See the comments at the beginning of this file for more details about */ /* the parameters for this routine. */ /* */ /* The rounite works by reading the data file one line at a time and adds */ /* that data in the particular stations data block. If the data block */ /* becomes full a new one day block is allocated. At the end of the */ /* routine all one day blocks are combined into a single data block. */ /*--------------------------------------------------------------------------*/ long ReadDump(char *FileName,NetworkPtr Network,char *StartTimeStr, char *EndTimeStr,char *StationList) { FILE *Dumpfile; /* The data file to be processed */ char *Line; /* Points to start of current data line */ char *TmpLine; Time_sec Time; /* Time of the current data line */ Time_sec OldTime; /* Time of previous data line */ Time_sec TempTime; /* Time of Current data line */ Time_sec StartTime; /* Time of first record to be read */ Time_sec EndTime; /* Time of record not read anymore */ Time_sec TimeStep; /* Interval between successive points */ Time_sec FirstTime; /* Time of the first data or non-d line */ StationPtr Station; /* Pointer to the current station */ long FirstLine = 1; /* Flag for first valid data line */ long LineLength; /* Length of d-lines */ char TimingChar; /* How mean values are computed ? */ /* S = start, M = middle, E = end */ long DumpFileSize; /* Size of the dump file in bytes */ char *DumpBuffer; /* Read the whole dump file into this */ /* buffer. */ char CurrTime[20]; long i; long TmpLineNbr; InitNetwork(Network); /* Initialize the fields of Network */ /* --- Set the start and end times --- */ if ((StartTimeStr == NULL) || (*StartTimeStr == '\0')) StartTime = MIN_TIME; // else StartTime = StrToSecs(StartTimeStr,0); else StartTime = StrToSecsC(StartTimeStr,0); if ((EndTimeStr == NULL) || (*EndTimeStr == '\0')) EndTime = MAX_TIME; // else EndTime = StrToSecs(EndTimeStr,0); else EndTime = StrToSecsC(EndTimeStr,0); /* --- Try to read the file into memory --- */ if ((FileName == NULL) || (*FileName == '\0')) { fprintf(stderr,"### FileName not specified\n"); return(FileError); } DumpFileSize = GetFileSize(FileName); if (DumpFileSize == 0) { fprintf(stderr,"### Could not open file %s\n",FileName); return FileError; } DumpBuffer = malloc(DumpFileSize+1); if (DumpBuffer == NULL) { fprintf(stderr,"### Out of memory !\n"); return(OutOfMemory); } DumpBuffer[DumpFileSize] = EOFmarker; /* Set our end of file mark */ Dumpfile = fopen(FileName,"r"); if (fread(DumpBuffer,DumpFileSize,1,Dumpfile) == 0) { fprintf(stderr,"### Could not read file %s\n",FileName); return FileError; } fclose(Dumpfile); Remove_non_ascii_chars(DumpBuffer, DumpFileSize+1); /* --- Handle the first line. It should start with letter 'i' ---*/ Line = DumpBuffer; if (*Line != 'i') { fprintf(stderr,"### The first line is not an i-line\n"); fprintf(stderr,"File \"%s\" ; Line 1\n",FileName); free(DumpBuffer); return(FileFormatError); } /* --- Set up some parameters ---*/ TimeStep = GetPositiveInt(Line+Dump_AverageTime); if ((TimeStep < 1) || (TimeStep > 999)) { fprintf(stderr,"### Illegal value for time resolution %d\n",TimeStep); fprintf(stderr,"File \"%s\" ; Line 1\n",FileName); free(DumpBuffer); return(FileFormatError); } TimingChar = Line[Dump_TimingChar]; Station = AddNewStation(Network,TimeStep,TimeStep); StationChar = Line[1]; if (Station != NULL) SetStationParamsDump(Station,StationChar,StationList); else { /* Unable to allocate memory for station data */ free(DumpBuffer); return(OutOfMemory); } ParamLineCount = 0; /* --- Check that the station code is defined --- */ if (strlen(Station->StationID) == 0) { fprintf(stderr,"### The station code %c is undefined\n",StationChar); fprintf(stderr,"File \"%s\" ; Line 1\n",FileName); free(DumpBuffer); return(FileError); } /* --- Find the first valid 'd'-line and get the field resolution --- */ Line = DumpBuffer; LineNbr = 1; while (Line != NULL) { if ((*Line == 'd') && !CheckLine(Line)) break; // Found proper 'd'-line Line = NextDumpLine(Line); } if (Line == NULL) { fprintf(stderr,"### No d-lines found in the input file\n"); free(DumpBuffer); return(FileFormatError); } if (*(Line+37) == '.') Resolution = 2; else Resolution = 1; /* --- Check the components --- */ strncpy(ComponentStr,Line+Dump_Components,6); if (strncmp(ComponentStr,"XYZ",3)) { fprintf(stderr,"### Components are not XYZ: %.3s\n",Line+Dump_Components); fprintf(stderr,"File \"%s\" ; Line %d\n",FileName,LineNbr); free(DumpBuffer); return(FileFormatError); } /* --- Set the components in the station structure --- */ strncpy(Station->Components,ComponentStr,6); for (i=0;i<6;i++) { if (ComponentStr[i] == 's') Station->Components[i] = 'A'; if (ComponentStr[i] == ' ') Station->Components[i] = '\0'; } /* --- Find the first valid 's'-line and get the time. --- */ /* --- It is used in setting the times of 'i' and 'c' lines --- */ Line = DumpBuffer; while ((Line != NULL) && (*Line != 's')) Line = NextDumpLine(Line); // Skip all non-'s' lines if (Line == NULL) { fprintf(stderr,"### No s-lines found in the input file\n"); free(DumpBuffer); return(FileFormatError); } Time = GetDumpTime(Line); // Get the time of the s-line and set it as the time of i-line FirstTime = Time; Line = DumpBuffer; LineNbr = 1; // Time = MIN_TIME; GetParamLine(Line,Time); /* The first line: i-line */ /* --- Read data into one day blocks ---*/ while ((Line = NextDumpLine(Line)) != NULL) { /* Weak check of dump format */ if ((*Line < 'a') || (*Line > 'z')) { fprintf(stderr,"### First character in line %d is illegal:\n",LineNbr); fprintf(stderr,"File \"%s\" ; Line %d\n",FileName,LineNbr); free(DumpBuffer); return(FileFormatError); } /* check the line for illegal characters, except i- and c -lines, */ if ((*Line != 'i') && (*Line != 'c')) { if (CheckLine(Line)) { fprintf(stderr,"### Illegal character(s) in line %d. Line ignored.\n",LineNbr); fprintf(stderr,"File \"%s\" ; Line %d\n",FileName,LineNbr); continue; /* free(DumpBuffer); */ /* return(FileFormatError); */ } } /* Store non-d lines into ParamLine-Array */ if (*Line != 'd') { if ((*Line != 'i') && (*Line != 'c')) { // i and c lines don't contain time Time = GetDumpTime(Line); } else { // Handle 'i' and 'c' lines // Try to find the next 's'-line and get time from there TmpLine = Line; TmpLineNbr = LineNbr; while ((TmpLine != NULL) && (*TmpLine != 's')) TmpLine = NextDumpLine(TmpLine); // Skip all non-'s' lines LineNbr = TmpLineNbr; if (TmpLine == NULL) { // No 's'-lines after 'i' or 'c' line if (Time != FirstTime) Time += TimeStep; // Set time as time of last data line + timestep } else { Time = GetDumpTime(TmpLine); // Get the time of the s-line and set it as the time of i-line } } GetParamLine(Line,Time); if (ParamLineCount == MaxParamLineCount) { fprintf(stderr,"### Sorry, too many parameter lines in dumpfile %s\n",FileName); fprintf(stderr,"### Cannot continue\n"); free(DumpBuffer); return(FileFormatError); } continue; } /* Check that the station code hasn't changed */ if (StationChar != Line[1]) { fprintf(stderr,"### Different station character ? %c\n",Line+1); fprintf(stderr,"File \"%s\" ; Line %d\n",FileName,LineNbr); free(DumpBuffer); return(FileFormatError); } /* Check that the component characters haven't changed */ if (strncmp(ComponentStr,Line+Dump_Components,6)) { fprintf(stderr,"### Different components ? %.6s %.6s\n",Line+Dump_Components, ComponentStr); fprintf(stderr,"File \"%s\" ; Line %d\n",FileName,LineNbr); free(DumpBuffer); return(FileFormatError); } /* Check if we already have all required data */ if ((Time = GetDumpTime(Line)) >= EndTime) break; /* Handle a d-line */ if (Time >= StartTime) { if (FirstLine) { /* First valid data line */ Station->StartTime = Time; OldTime = Time; LineLength = GetLineLength(Line); FirstLine = 0; } else { /* Check times and add missing data if necessary */ if (LineLength != GetLineLength(Line)) { fprintf(stderr,"### Line length not constant ?!. Line ignored.\n"); fprintf(stderr,"File \"%s\" ; Line %d\n",FileName,LineNbr); continue; /* free(DumpBuffer); */ /* return(FileError); */ } else if ((Time - Station->StartTime) % TimeStep != 0) { fprintf(stderr,"### Illegal time %.20s\n",Line+12); fprintf(stderr,"File \"%s\" ; Line %d\n",FileName,LineNbr); /* free(DumpBuffer); */ /* return(FileError); */ continue; } else if (Time < OldTime) { fprintf(stderr,"### Warning: Data lines not in chronological order\n"); fprintf(stderr,"File \"%s\" ; Line %d\n",FileName,LineNbr); /* free(DumpBuffer); */ /* return(FileError); */ continue; } else if (Time == OldTime) { /* same data line twice */ fprintf(stderr,"### Warning: Same time in two lines !\n"); fprintf(stderr,"File \"%s\" ; Line %d\n",FileName,LineNbr); fprintf(stderr,"File \"%s\" ; Line %d\n",FileName,LineNbr); continue; /* do nothing */ } else if (Time-OldTime != TimeStep) { /* Add missing data points */ for (TempTime=OldTime+TimeStep; TempTime < Time; TempTime += TimeStep) { SetMissingData(Station,TempTime+TimeStep,TempTime-TimeStep); if (OneDayFull(Station,'Z')) { if (AddOneDay(Station)) return(OutOfMemory); /* Failed to allocate memory */ } } } } if (OneDayFull(Station,'Z')) { if (AddOneDay(Station)) return(OutOfMemory); /* Failed to allocate memory */ } GetDumpData(Station,Line,Time); /* Finally get data values */ OldTime = Time; } } free(DumpBuffer); /* --- Combine one day blocks into one large block ---*/ /* --- and correct the start and end times according ---*/ /* --- to the TimingChar value. ---*/ Station = Network->StationList; while (Station != NULL) { if (CombineData(Station) == OutOfMemory) return(OutOfMemory); switch (TimingChar) { case 'S' : break; case 'M' : break; /* Station->StartTime -= TimeStep/2; Station->EndTime -= TimeStep/2; break; */ case 'E' : Station->StartTime -= TimeStep; Station->EndTime -= TimeStep; break; } Station = Station->Next; } return OK; } /*==========================================================================*/ /* Routines for writing Dump-format files */ /*==========================================================================*/ /*--------------------------------------------------------------------------*/ /* Write a field value (1 or 2 decimals) to given dump file. */ /*--------------------------------------------------------------------------*/ static void Print1(FILE *DumpFile,long value) { double X; X = value/100.0; if (value != MissingValue) fprintf(DumpFile,"%9.1f",X); else fprintf(DumpFile," 99999.9"); } static void Print2(FILE *DumpFile, long value) { double X; X = value/100.0; if (value != MissingValue) fprintf(DumpFile,"%9.2f",X); else fprintf(DumpFile," 99999.99"); } /*--------------------------------------------------------------------------*/ /* Write X, Y and Z values to the current dump line. Also T is written if */ /* it exists in the original file. */ /*--------------------------------------------------------------------------*/ static void WriteXYZ(FILE *DumpFile, StationPtr Station, Time_sec Time) { long X,Y,Z,T,A; long count; count = (Time - Station->StartTime)/(Station->TimeStep); X = *(Station->X + count); Y = *(Station->Y + count); Z = *(Station->Z + count); if (Resolution == 1) { Print1(DumpFile,X); Print1(DumpFile,Y); Print1(DumpFile,Z); } else { Print2(DumpFile,X); Print2(DumpFile,Y); Print2(DumpFile,Z); } if (ComponentStr[3] != ' ') { T = *(Station->T + count); if (Resolution == 1) Print1(DumpFile,T); else Print2(DumpFile,T); } if (ComponentStr[4] != ' ') { A = *(Station->A + count); if (A == MissingValue) A = 0; if (Resolution == 1) Print1(DumpFile,A); else Print2(DumpFile,A); } fprintf(DumpFile,"\n"); } /*--------------------------------------------------------------------------*/ /* Write a parameter line into dump file. */ /*--------------------------------------------------------------------------*/ static void WriteParamLine(FILE *DumpFile,char *Line) { char *p = Line; long count = 0; while (*p++ > 31) count++; fwrite(Line,count,1,DumpFile); fprintf(DumpFile,"\n"); } /*--------------------------------------------------------------------------*/ /* Write a d-line into dump file. */ /*--------------------------------------------------------------------------*/ static void Write_d_line(FILE *DumpFile,StationPtr Station, Time_sec Time) { char TimeStr[20]; /* d-character, Station character,Components and time step */ fprintf(DumpFile,"d%c%.6s%3d ",StationChar,ComponentStr,Station->TimeStep); /* Time */ // SecsToStr(Time,TimeStr); // if (Time < YEAR2000) // fprintf(DumpFile,"19"); // else // fprintf(DumpFile,"20"); // // fprintf(DumpFile,"%.2s %.2s %.2s %.2s %.2s %.2s",TimeStr,TimeStr+2, // TimeStr+4,TimeStr+6,TimeStr+8,TimeStr+10); SecsToStrC(Time,TimeStr); fprintf(DumpFile,"%.4s %.2s %.2s %.2s %.2s %.2s",TimeStr,TimeStr+4, TimeStr+6,TimeStr+8,TimeStr+10,TimeStr+12); /* Field components */ WriteXYZ(DumpFile,Station,Time); } /*--------------------------------------------------------------------------*/ /* Here is the routine for writing data into a Dump-format file. This */ /* routine can only be used if the data to be written was previousle read */ /* in from a dump-format file. */ /*--------------------------------------------------------------------------*/ long WriteDump(char *FileName,NetworkPtr Network) { FILE *DumpFile; /* The data file to be processed */ Time_sec Time; /* Time of the current data block */ Time_sec StartTime; /* Time of first record to be read */ Time_sec EndTime; /* Time of record not read anymore */ Time_sec ParamTime; /* Time of record not read anymore */ StationPtr Station; /* Pointer to the current station */ long CurrParamLine = 0; /* Number of current Parameter line */ /* --- Check that there is some data in the Network --- */ if (Network->StationList == NULL) return FAIL; /* --- Set the start and end times --- */ Station = Network->StationList; StartTime = Station->StartTime; EndTime = Station->EndTime; /* --- Make sure that param lines are written at the start of the file --- */ ParamTime = ParamLineTime[0]; // Time of i-line if (StartTime < ParamTime) { while ((CurrParamLine < ParamLineCount) && (ParamLineTime[CurrParamLine] == ParamTime)) { if (*ParamLine[CurrParamLine] == 'i') ParamLineTime[CurrParamLine] = StartTime; if (*ParamLine[CurrParamLine] == 'c') ParamLineTime[CurrParamLine] = StartTime; CurrParamLine++; } } /* --- Try to create the file --- */ if ((FileName == NULL) || (*FileName == '\0')) DumpFile = stdout; else if ((DumpFile = fopen(FileName, "w")) == NULL) return FileError; /* --- Write the dump file --- */ Time = StartTime; CurrParamLine = 0; while (Time < EndTime) { /* Write the Parameter lines */ while ((CurrParamLine < ParamLineCount) && (ParamLineTime[CurrParamLine] <= Time)) { WriteParamLine(DumpFile,ParamLine[CurrParamLine++]); } /* Write a d-line */ Write_d_line(DumpFile,Station,Time); Time += Station->TimeStep; } fclose(DumpFile); return OK; }