[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
20000727: UPC mods to 7.70 code
- Subject: 20000727: UPC mods to 7.70 code
- Date: Thu, 27 Jul 2000 14:05:22 -0600
>From: Russ Dengel <address@hidden>
>Organization: SSEC
>Keywords: Keywords: 200007271758.e6RHwaT24691 McIDAS-X 7.70 UPC mods
Russ,
>I'm on your mods to the station data base code for DEC machines.
>Can you send me your copies of stncpy.c and stations.h.
The first file should be stnqry.c. I have attached these files at the end of
this email. My mods are demarked or described by '<<<<< UPC ...'. Please
let me know if you have any questions.
>I will get these into our code ASAP. You can assume that the code will be
>changed identically unless I let you know.
Thanks!
--------------------------- stnqry.c -----------------------------------------
/*
* Copyright(c) 1998, Space Science and Engineering Center, UW-Madison
* Refer to "McIDAS Software Acquisition and Distribution Policies"
* in the file mcidas/data/license.txt
*/
/**** $Id: stnqry.c,v 1.9 2000/04/14 18:39:53 chadj Tst $ *** */
#include <stdlib.h>
#include <stdio.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include "mcidas.h"
#include "stations.h"
#include "m0arg.h"
#define MAXQUERIES 255
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
/* function prototypes */
static int M0STNQuery (STATION_QRY *q_info, STATION ***stn_info,
int *num_sta);
int M0STNGetDatatypes (char ***names, int *num);
static int FinalQuery (char *file, int *locs, int num_locs,
STATION ***stations, int *num_stn,
STATION_QRY *q_info);
static STATION * ReadAsciiStation (char *buf);
int QueryUserDB (char *file, STATION_QRY *q_info,
STATION ***stn_info, int *num_sta);
static int QueryCoreDB (char *file, STATION_QRY *q_info,
STATION ***stn_info, int *num_sta);
static int idn_ok (STATION_QRY *q_info, STATION *stn, int idx);
static int id_ok (STATION_QRY *q_info, STATION *stn, int idx);
static int userid_ok (STATION_QRY *q_info, STATION *stn, int idx);
static int latlon_ok (STATION_QRY *q_info, STATION *stn);
static int country_ok (STATION_QRY *q_info, STATION *stn);
static int state_ok (STATION_QRY *q_info, STATION *stn);
static int name_ok (STATION_QRY *q_info, STATION *stn);
static int datatype_ok (STATION_QRY *q_info, STATION *stn);
static int validdate_ok (STATION_QRY *q_info, STATION *stn);
static int HaveStation (STATION **stn_array, int num,STATION *stn,
STATION_QRY *query);
static STATION * PluckStation (char *file, int loc);
static int GetNextHandle(void);
static STATION * NewStation (void);
static void FreeStation (STATION *stn);
static int LoadDatatypes (void);
static int LoadTypesIndex (STNTYPESINDEX **t_index);
static int LoadCoreHeaders (void);
static int AddTypename (char *t_name, char ***names, int *num);
static int DatatypeMatch (STATION *st1, STATION *st2);
int LoadUserDatatypes (const char *file);
void print_query (STATION_QRY *q);
void print_station (STATION *s);
/* functions not defined in mcidas.h */
float flalo (Fint *);
/* variables used by various functions internal to these routines */
static STATION **result_stations[MAXQUERIES]; /* list of stations
* matching request */
static int result_num_stn[MAXQUERIES]; /* number of stations
* matching request */
static int next[MAXQUERIES]; /* next station to
* return */
static int num_types=-1; /* number of defined
* datatypes */
static char **type_names=0; /* datatype names */
static int num_user_types=0; /* number of user
* defined datatypes */
static char **user_type_names=0; /* names of user
* datatypes */
static STNHEADER *HEADER = 0; /* core file header */
static STNDATAOFFSET *OFFSETS= 0; /* core file data offset header */
static STNSIZES *SIZES = 0; /* core file data sizes header */
static STNINDEXHEADER *INDEX = 0; /* core file index header */
static char *user_file="STNDB.USER";
static char *site_file="STNDB.SITE";
static char *core_file="STNDB.CORE";
static STATION **invalid_stations; /* list of invalid stations
* due to invalid dates */
static int invalid_num_stn; /* number of invalid stations */
/*
* These are the Fortran instantiations of the STATION and STATION_QRY structs.
* These are the structures filled and retrieved in the fortran
* jacket routines mcstnopenquery_() and mcstngetnextstation_(). Because they
* are global "Fortran" variables, any fortran application can get at the
* variables in the structures by including the file stations.inc.
*/
F_STATION fstn_;
F_STATION_QRY fstnqry_;
/*
* <<<<< UPC mod 20000710: cast second parameter to Mcread to off_t
* cast third parameter to Mcread to size_t
*
* Change was made to reflect the fact that off_t and size_t sizes
* may be different than the size of an int on 64-bit systems like
* DEC OSF/1.
*
* >>>>>
*/
/*
*$ Name:
*$ M0STNSetUserFile - Initializes the name of the user station file
*$
*$ Interface:
*$ #include "mcidas.h"
*$ #include "stations.h"
*$
*$ int
*$ M0STNSetUserFile(const char *file)
*$
*$ Input:
*$ file - name of user file
*$
*$ Input and Output:
*$ none
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ 0 - OK
*$ -1 - file is null
*$
*$ Remarks:
*$ The user station file is an ASCII text file containing station
*$ definitions. The default file is STNDB.USER.
*$
*$ Categories:
*$ system
*$ utility
*$
*$ Filename:
*$ stnqry.c
*/
int
M0STNSetUserFile (const char *file)
{
if (file == (char *)NULL) return -1;
user_file = (char *)file;
return 0;
}
/*
*$ Name:
*$ M0STNSetSiteFile - Initializes the name of the site station file
*$
*$ Interface:
*$ #include "mcidas.h"
*$ #include "stations.h"
*$
*$ void
*$ M0STNSetSiteFile(const char *file)
*$
*$ Input:
*$ file - name of site file
*$
*$ Input and Output:
*$ none
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ 0 - OK
*$ -1 - filename is null
*$
*$ Remarks:
*$ The site station file is an ASCII text file containing station
*$ definitions. The default file is STNDB.SITE.
*$
*$ Categories:
*$ system
*$ utility
*$
*$ Filename:
*$ stnqry.c
*/
int
M0STNSetSiteFile (const char *file)
{
if (file == (char *)NULL) return -1;
site_file = (char *)file;
return 0;
}
/*
*$ Name:
*$ M0STNSetCoreFile - Initializes the name of the core station file
*$
*$ Interface:
*$ #include "mcidas.h"
*$ #include "stations.h"
*$
*$ int
*$ M0STNSetCoreFile(const char *file)
*$
*$ Input:
*$ file - name of core file
*$
*$ Input and Output:
*$ none
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ 0 - OK
*$ -1 - filename is null
*$
*$ Remarks:
*$ The core station file is a binary file containing station definitions.
*$ The default file is STNDB.CORE. It can not be directly modified.
*$
*$ Categories:
*$ system
*$ utility
*$
*$ Filename:
*$ stnqry.c
*/
int
M0STNSetCoreFile (const char *file)
{
if (file == (char *)NULL) return -1;
core_file = (char *)file;
return 0;
}
/*
*$ Name:
*$ McSTNSetQueryDefaults - Initializes the query structure to default
*$ values
*$
*$ Interface:
*$ #include "mcidas.h"
*$ #include "stations.h"
*$
*$ int
*$ McSTNSetQueryDefaults(STATION_QRY *query)
*$
*$ Input:
*$ none
*$
*$ Input and Output:
*$ query - pointer to already allocated station query structure
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ 0 - success
*$ -1 - failed to allocate memory for query structure
*$ -2 - failed to get the current day
*$
*$ Remarks:
*$ This function fills a query structure with the default values for a
*$ query. For example, the valid date range is set to the current date,
*$ and the lat/lon ranges are set to MCMISSING4 to cover the entire globe.
*$
*$ The query structure must already be instantiated before calling this
*$ function.
*$
*$ Categories:
*$ system
*$ utility
*$
*$ Filename:
*$ stnqry.c
*/
int
McSTNSetQueryDefaults (STATION_QRY *query)
{
int ok; /* return code */
int today; /* today's julian day */
ok = Mcgetday (&today);
if (ok < 0) return -2;
if (query == (STATION_QRY *)NULL) return -1;
memset (query, 0, sizeof (STATION_QRY));
query->minlat = MCMISSING4;
query->maxlat = MCMISSING4;
query->minlon = MCMISSING4;
query->maxlon = MCMISSING4;
query->valid.bdate = today;
query->valid.edate = today;
return 0;
}
/*
*$ Name:
*$ mcstnsetquerydefaults - Initializes the query to default values
*$
*$ Interface:
*$ #include 'stations.inc'
*$
*$ integer function
*$ mcstnsetquerydefaults()
*$
*$ Input:
*$ none
*$
*$ Input and Output:
*$ none
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ 0 - success
*$ -2 - failed to get the current day
*$
*$ Remarks:
*$ This function fills a query structure with the default values for a
*$ query. For example, the valid date range is set to the current date,
*$ and the lat/lon ranges are set to MCMISSING4 to cover the entire globe.
*$
*$ The query structure is the common block FSTNQRY.
*$
*$ Categories:
*$ system
*$ utility
*$
*$ Filename:
*$ stnqry.c
*/
Fint
mcstnsetquerydefaults_ (void)
{
int ok; /* return variable */
int today; /* today's julian day */
ok = Mcgetday (&today);
if (ok < 0) return -2;
memset (&fstnqry_, 0, sizeof (F_STATION_QRY));
fstnqry_.q_minlat = MCMISSING4;
fstnqry_.q_maxlat = MCMISSING4;
fstnqry_.q_minlon = MCMISSING4;
fstnqry_.q_maxlon = MCMISSING4;
memset (fstnqry_.q_id, ' ', F_IDLEN);
memset (fstnqry_.q_userid, ' ', F_IDLEN);
memset (fstnqry_.q_state, ' ', F_STATELEN);
memset (fstnqry_.q_country, ' ', F_COUNTRYLEN);
memset (fstnqry_.q_county, ' ', F_COUNTYLEN);
memset (fstnqry_.q_match, ' ', F_NAMELEN);
fstnqry_.q_mindate = today;
fstnqry_.q_maxdate = today;
return 0;
}
int
M0STNGetDatatypes (char ***names, int *num)
{
int ok;
int i;
char **nms;
int n;
ok = LoadDatatypes ();
if (ok < 0) return -1;
nms = *names;
if (num_types > 0)
{
n = num_types;
nms = malloc (sizeof (char *) * n);
if (nms == (char **)0) return -1;
for (i = 0 ; i < num_types ; i++)
{
nms[i] = type_names[i];
}
}
if (num_user_types > 0)
{
int match;
int j;
for (i = 0 ; i < num_user_types ; i++)
{
match = FALSE;
for (j = 0 ; j < *num ; j++)
{
if (strcmp (user_type_names[i], nms[j]) == 0)
{
match = TRUE;
break;
}
}
if (match) continue;
(n)++;
nms = realloc (nms, sizeof (char *) * n);
if (nms == (char **)0) return -1;
nms[n - 1] = user_type_names[i];
}
}
*names = nms;
*num = n;
return 0;
}
static int
LoadDatatypes (void)
{
#define NUM_TYPE_LOC 16
#define TYPENAME_LOC 1024
int ok;
/* have we already loaded the types */
if (num_types != -1) return 0;
num_types = 0;
/* load up the datatypes defined in the core file */
ok = LoadCoreHeaders ();
#if 0
if (ok < -1) return -1;
#endif
/* load up the datatypes defined in the user files */
ok = LoadUserDatatypes (site_file);
ok = LoadUserDatatypes (user_file);
return 0;
}
int
LoadUserDatatypes (const char *file)
{
FILE *pFile;
char *pathname;
char *p;
int num_user;
int ok;
int i;
num_user = 0;
pathname = (char *) Mcpathname (file);
if (pathname == (char *)NULL) return -1;
/* open the file, return 0 if can't open */
if ((pFile = fopen (pathname, "r")) == (FILE *)NULL) return -1;
i = 0;
while (!feof (pFile))
{
char buf[255];
int handle;
char *ctmp;
if (fgets (buf, 255, pFile) == (char *)NULL)
{
fclose (pFile);
return i;
}
/* remove any line feed, otherwise the McIDAS arg parser pukes */
p = buf + strlen (buf);
while (p > buf)
{
if (*p == '\n')
{
*p='\0';
break;
}
p--;
}
handle = Mcargparse (buf, (const McArgSyntax *)NULL, (int *)NULL);
if (handle < 0) continue;
ok = Mcargstr (handle, (const char *)NULL, 0, (char *)NULL,
(const char **)&ctmp);
if (ok < 0 || ctmp == (char *)NULL || strcmp (ctmp, "DATATYPE") != 0)
{
Mcargfree (handle);
fclose (pFile);
return i;
}
ok = Mcargstr (handle, (const char *)NULL, 1, (char *)NULL,
(const char **)&ctmp);
if (ok < 0 || ctmp == (char *)NULL)
{
Mceprintf ("STATION ERROR: error with DATATYPE in %s\n", file);
Mcargfree (handle);
continue;
}
num_user_types++;
# ifdef DEBUG_STATION
Mcdprintf ("LoadUserDatatypes: num_types = %d\n", num_user_types);
# endif
user_type_names = (char **)realloc (user_type_names, num_user_types *
sizeof (char *));
if (user_type_names == (char **)NULL)
{
Mcargfree (handle);
fclose (pFile);
return -1;
}
user_type_names[num_user_types-1] = strdup (ctmp);
i++;
Mcargfree (handle);
}
fclose (pFile);
return i;
}
/*
*$ Name:
*$ McSTNOpenQuery - Opens a query to the station database
*$
*$ Interface:
*$ #include "mcidas.h"
*$ #include "stations.h"
*$
*$ int
*$ McSTNOpenQuery(STATION_QRY *query)
*$
*$ Input:
*$ query - pointer to station query structure
*$
*$ Input and Output:
*$ none
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ >-1 - handle to successful query
*$ -1 - maximum number of queries reached
*$ -2 - query failed
*$
*$ Remarks:
*$ This function opens a query to the station database. The query
*$ structure must be filled with information describing the station(s) you
*$ are looking for before calling this function. Use the function
*$ McSTNSetQueryDefualts to initialize the query structure. Upon
*$ successful completion, a handle to the query is returned.
*$
*$ Call McSTNCloseQuery to close this query after all stations have been
*$ retrieved. This frees memory allocated for the query and releases this
*$ handle so it can be used again.
*$
*$ No more than 255 queries can be active simultaneously.
*$
*$ Categories:
*$ system
*$ utility
*$
*$ Filename:
*$ stnqry.c
*/
int
McSTNOpenQuery (STATION_QRY *q_info)
{
static int first_time = 1;
int handle; /* handle to results of this query */
int ok;
int i;
print_query (q_info);
if (first_time)
{
memset (result_stations, 0, sizeof (STATION **) * MAXQUERIES);
memset (result_num_stn, 0, sizeof (int) * MAXQUERIES);
first_time = 0;
}
invalid_stations = 0;
invalid_num_stn = 0;
/* get the next available handle for this query */
handle = GetNextHandle();
if (handle < 0) return -1;
/* run the query */
ok = M0STNQuery (q_info, &result_stations[handle], &result_num_stn[handle]);
if (ok < 0)
{
return -2;
}
/* free the invalid stations list */
for (i = 0 ; i < invalid_num_stn ; i++)
{
FreeStation (invalid_stations[i]);
}
if (invalid_stations) free (invalid_stations);
invalid_num_stn = 0;
next[handle] = 0;
return handle;
}
/*
*$ Name:
*$ McSTNGetNumStations - Return the number of stations matching a query
*$
*$ Interface:
*$ #include "mcidas.h"
*$ #include "stations.h"
*$
*$ int
*$ McSTNGetNumStations(int handle)
*$
*$ Input:
*$ handle - handle to the query opened with McSTNOpenQuery.
*$
*$ Input and Output:
*$ none
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ >= 0 - number of stations matching query
*$ -1 - invalid handle
*$
*$ Remarks:
*$ The query must first be opened by calling McSTNOpenQuery.
*$
*$ Categories:
*$ system
*$ utility
*/
int
McSTNGetNumStations (int handle)
{
if (handle < 0 || handle >= MAXQUERIES) return -1;
return result_num_stn[handle];
}
/*
*$ Name:
*$ mcstngetnumstations - Return the number of stations matching a query
*$
*$ Interface:
*$ integer function
*$ mcstngetnumstations(integer handle)
*$
*$ Input:
*$ handle - handle to the query opened with mcstnopenquery.
*$
*$ Input and Output:
*$ none
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ >= 0 - number of stations matching query
*$ -1 - invalid handle
*$
*$ Remarks:
*$ The query must first be opened by calling mcstnopenquery.
*$
*$ Categories:
*$ system
*$ utility
*/
Fint
mcstngetnumstations_ (Fint *f_handle)
{
return (Fint) McSTNGetNumStations (*f_handle);
}
/*
*$ Name:
*$ McSTNGetNextStation - Return the next station matching a query
*$
*$ Interface:
*$ #include "mcidas.h"
*$ #include "stations.h"
*$
*$ STATION *
*$ McSTNGetNextStation(int handle)
*$
*$ Input:
*$ handle - handle to the query opened with McSTNOpenQuery.
*$
*$ Input and Output:
*$ none
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ 0 (NULL) - no more stations to retrieve or invalid handle
*$ <>0 - pointer to the station
*$
*$ Remarks:
*$ The query must first be opened by calling McSTNOpenQuery.
*$
*$ The function returns a pointer to a structure containing all
*$ information known about the station.
*$
*$ Continue calling this function to retrieve all stations that match the
*$ query. McSTNGetNumStations will give you the number of stations matching
*$ a particular query.
*$
*$ Categories:
*$ system
*$ utility
*/
STATION *
McSTNGetNextStation (int handle)
{
STATION *s;
int i;
if (next[handle] >= result_num_stn[handle]) return (STATION *)NULL;
i = next[handle];
s = result_stations[handle][i];
next[handle]++;
return s;
}
/*
*$ Name:
*$ McSTNCloseQuery - Closes a station database query
*$
*$ Interface:
*$ #include "mcidas.h"
*$ #include "stations.h"
*$
*$ int
*$ McSTNCloseQuery(int handle)
*$
*$ Input:
*$ handle - handle to the query opened with McSTNOpenQuery.
*$
*$ Input and Output:
*$ none
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ 0 - success
*$ -1 - invalid handle
*$
*$
*$ Remarks:
*$ This function should be called when you are finished retrieving all
*$ stations for a query opened with McSTNOpenQuery. It frees dynamically
*$ memory and releases the handle so it can be used again.
*$
*$ Categories:
*$ system
*$ utility
*/
int
McSTNCloseQuery (int handle)
{
int i;
int num;
if (handle < 0 || handle >= MAXQUERIES) return -1;
if (result_stations[handle] == (STATION **)0 ||
result_num_stn[handle] == 0)
{
return 0;
}
num = McSTNGetNumStations (handle);
/* Free all the stations in the result */
for (i = 0 ; i < num ; i++)
{
FreeStation (result_stations[handle][i]);
}
/* Free the array containing the list of pointers to the stations */
free (result_stations[handle]);
result_num_stn[handle] = 0;
result_stations[handle] = (STATION **)0;
return 0;
}
/*
*$ Name:
*$ mcstnclosequery - Closes a station database query
*$
*$ Interface:
*$ integer function
*$ mcstnclosequery(integer handle)
*$
*$ Input:
*$ handle - handle to the query opened with mcstnopenquery.
*$
*$ Input and Output:
*$ none
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ 0 - success
*$ -1 - invalid handle
*$
*$
*$ Remarks:
*$ This function should be called when you are finished retrieving all
*$ stations for a query opened with mcstnopenquery. It frees dynamically
*$ memory and releases the handle so it can be used again.
*$
*$ Categories:
*$ system
*$ utility
*/
Fint
mcstnclosequery_ (Fint *f_handle)
{
return (Fint) McSTNCloseQuery ((int) *f_handle);
}
/*
* Returns the next available handle to a query
*
* returns
* >= 0 next available handle
* < 0 no handle available
*/
static int
GetNextHandle(void)
{
int handle;
for (handle = 0 ; handle < MAXQUERIES ; handle++)
{
if (result_num_stn[handle] == 0 &&
result_stations[handle] == (STATION **)0) return handle;
}
return -1;
}
/*
*$ Name:
*$ M0STNQuery - Queries the station database
*$
*$ Interface:
*$ #include "mcidas.h"
*$ #include "stations.h"
*$
*$ static int
*$ M0STNQuery(STATION_QRY *q_info, STATION ***stn_info, int *num_sta)
*$
*$ Input:
*$ q_info - pointer to the query structure
*$
*$ Input and Output:
*$ stn_info - pointer to array of pointers to stations matching query
*$ num_sta - pointer to number of stations matching query
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ 0 - success
*$ -1 - invalid handle
*$
*$
*$ Remarks:
*$ This function queries the user and core station definition files and
*$ builds a list of stations matching the query.
*$
*$ Categories:
*$ system
*$ utility
*/
static int
M0STNQuery (STATION_QRY *q_info, STATION ***stn_info, int *num_sta)
{
char *pathname;
int num_user;
int ok;
num_user = 0;
*num_sta = 0;
*stn_info = (STATION **)NULL;
pathname = (char *)Mcpathname (user_file);
if (pathname != (char *)NULL)
{
ok = QueryUserDB (pathname, q_info, stn_info, &num_user);
}
pathname = (char *)Mcpathname (site_file);
if (pathname != (char *)NULL)
{
ok = QueryUserDB (pathname, q_info, stn_info, &num_user);
}
pathname = (char *)Mcpathname (core_file);
if (pathname == (char *)NULL)
{
*num_sta = num_user;
return 0;
}
ok = QueryCoreDB (pathname, q_info, stn_info, &num_user);
*num_sta = num_user;
return 0;
}
/*
*$ Name:
*$ QueryUserDB - Queries a user station definition file
*$
*$ Interface:
*$ #include "mcidas.h"
*$ #include "stations.h"
*$
*$ static int
*$ QueryUserDB(char *file, STATION_QRY *q_info, STATION ***stn_info,
*$ int *num_sta)
*$
*$ Input:
*$ file - name of the user definition file
*$ q_info - pointer to the query structure
*$
*$ Input and Output:
*$ stn_info - pointer to array of pointers to stations matching query
*$ num_sta - pointer to number of stations matching query
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ 0 - success
*$ -1 - unable to open file
*$ -3 - memory allocation failed
*$
*$
*$ Remarks:
*$ This function queries the user station definition files and builds a
*$ list of stations matching the query.
*$
*$ Categories:
*$ system
*$ utility
*/
int
QueryUserDB (char *file, STATION_QRY *q_info, STATION ***stn_info, int *num_stn)
{
FILE *pfile;
STATION **stn_array;
int i;
if ( (pfile = fopen (file, "r")) == (FILE *)NULL)
{
return -1;
}
stn_array = *stn_info;
i = *num_stn;
while (!feof (pfile))
{
char buf[1024];
char *p;
char *q;
short comment_line;
STATION *stn;
int j;
int i_match;
int ok;
p = fgets (buf, 1024, pfile);
if (p == (char *)NULL) break;
/* skip blank lines */
if (*p == '\n') continue;
/* look for a line beginning with a comment character "#" */
comment_line = FALSE;
q = strstr (p, "#");
if (q != (char *)NULL)
{
comment_line = TRUE;
while (q != (char *)NULL && q > p)
{
q--;
if (*q != ' ' && *q != '\t')
{
comment_line = FALSE;
break;
}
}
}
/* if we have a comment, get the next line */
if (comment_line) continue;
/* get the station information */
stn = ReadAsciiStation (buf);
if (stn == (STATION *)NULL)
{
Mceprintf ("Error with station definition in user file:\n");
Mceprintf (" %s\n", buf);
continue;
}
i_match = 0;
for (j = 0 ; j < q_info->n_idn ; j++)
{
if (!idn_ok (q_info, stn, j)) continue;
i_match = 1;
break;
}
/* station ID */
for (j = 0 ; j < q_info->n_id ; j++)
{
if (!id_ok(q_info, stn, j)) continue;
i_match = 1;
break;
}
if (!i_match && (q_info->n_id > 0 || q_info->n_idn))
{
# ifdef DEBUG_STATION
Mcdprintf ("failed id\n");
# endif
FreeStation (stn);
continue;
}
/* station user ID */
for (j = 0 ; j < q_info->n_userid ; j++)
{
if (!userid_ok(q_info, stn, j)) continue;
i_match = 1;
break;
}
if (!i_match && q_info->n_userid > 0)
{
# ifdef DEBUG_STATION
Mcdprintf ("failed user id\n");
# endif
FreeStation (stn);
continue;
}
/* check lat/lon bounds */
if (!latlon_ok (q_info, stn))
{
# ifdef DEBUG_STATION
Mcdprintf ("failed lat/lon\n");
# endif
FreeStation (stn);
continue;
}
/* country of station */
if (!country_ok (q_info, stn))
{
# ifdef DEBUG_STATION
Mcdprintf ("failed country\n");
# endif
FreeStation (stn);
continue;
}
/* state of station */
if (!state_ok (q_info, stn))
{
# ifdef DEBUG_STATION
Mcdprintf ("failed state\n");
# endif
FreeStation (stn);
continue;
}
/* station name */
if (!name_ok (q_info, stn))
{
# ifdef DEBUG_STATION
Mcdprintf ("failed station name\n");
# endif
FreeStation (stn);
continue;
}
/* station type */
if (!datatype_ok (q_info, stn))
{
# ifdef DEBUG_STATION
Mcdprintf ("failed datatype\n");
# endif
FreeStation (stn);
continue;
}
/*
* we have a match on a station, see if we already have this
* station in the array from the user database, otherwise reallocate a
* new STATION pointer to the STATION array and store this station
*/
ok = HaveStation (stn_array, *num_stn, stn, q_info);
if (ok == 1)
{
FreeStation (stn);
continue;
}
if (ok == 2) continue;
/*
* we have a new station, reallocate a new STATION pointer to
* the STATION array and assign it the new station pointer
*/
# ifdef DEBUG_STATION
Mcdprintf (" %05d", stn->idn);
if (stn->id) Mcdprintf (" %s\n", stn->id);
# endif
stn_array = (STATION **)realloc (stn_array,
sizeof (STATION *) * (i + 1));
stn_array[i] = stn;
i++;
}
*stn_info = stn_array;
# ifdef DEBUG_STATION
Mcdprintf ("Scanning %s results in %d matching stations\n", file,
i - *num_stn);
# endif
*num_stn = i;
fclose (pfile);
return 0;
}
/*
*$ Name:
*$ QueryCoreDB - Queries a core station definition file
*$
*$ Interface:
*$ #include "mcidas.h"
*$ #include "stations.h"
*$
*$ static int
*$ QueryCoreDB(char *file, STATION_QRY *q_info, STATION ***stn_info,
*$ int *num_sta)
*$
*$ Input:
*$ file - name of the core definition file
*$ q_info - pointer to the query structure
*$
*$ Input and Output:
*$ stn_info - pointer to array of pointers to stations matching query
*$ num_sta - pointer to number of stations matching query
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ 0 - success
*$ -1 - unable to open file
*$ -3 - incorrect version of station DB
*$ -4 - failed memory allocation
*$ -5 - failed to load core headers
*$ -6 - failed to load core datatypes index
*$
*$
*$ Remarks:
*$ This function queries the core station definition files and builds a
*$ list of stations matching the query.
*$
*$ Categories:
*$ system
*$ utility
*/
static int
QueryCoreDB (char *file, STATION_QRY *q_info, STATION ***stn_info, int *num_stn)
{
#define NSTATIONS HEADER->n_stations
#define ID_ELEM_SIZE (SIZES->id)
#define ID_SIZE (NSTATIONS * ID_ELEM_SIZE)
#define IDN_ELEM_SIZE (SIZES->idn)
#define IDN_SIZE (NSTATIONS * IDN_ELEM_SIZE)
#define ARGOS_ELEM_SIZE (SIZES->argos)
#define ARGOS_SIZE (NSTATIONS * ARGOS_ELEM_SIZE)
#define LATLON_ELEM_SIZE (SIZES->lat)
#define LATLON_SIZE (NSTATIONS * LATLON_ELEM_SIZE)
#define ELE_ELEM_SIZE (SIZES->ele)
#define ELE_SIZE (NSTATIONS * ELE_ELEM_SIZE)
#define CO_ELEM_SIZE (SIZES->country)
#define CO_SIZE (NSTATIONS * CO_ELEM_SIZE)
#define ST_ELEM_SIZE (SIZES->state)
#define ST_SIZE (NSTATIONS * ST_ELEM_SIZE)
#define NAME_ELEM_SIZE (SIZES->description)
#define NAME_SIZE (NSTATIONS * NAME_ELEM_SIZE)
#define NTYPE_ELEM_SIZE (sizeof (int))
#define NTYPE_SIZE (NSTATIONS * NTYPE_ELEM_SIZE)
#define TYPE_OFF_ELEM_SIZE (sizeof (int))
#define TYPE_OFF_SIZE (NSTATIONS * TYPE_OFF_ELEM_SIZE)
#define NCOMM_ELEM_SIZE (sizeof (int))
#define NCOMM (NSTATIONS * NCOMM_ELEM_SIZE)
#define ID_LOC (OFFSETS->id)
#define IDN_LOC (OFFSETS->idn)
#define ARGOS_LOC (OFFSETS->argos)
#define LAT_LOC (OFFSETS->lat)
#define LON_LOC (OFFSETS->lon)
#define ULAT_LOC (OFFSETS->uplat)
#define ULON_LOC (OFFSETS->uplon)
#define ELE_LOC (OFFSETS->ele)
#define UELE_LOC (OFFSETS->upele)
#define CO_LOC (OFFSETS->country)
#define ST_LOC (OFFSETS->state)
#define NAME_LOC (OFFSETS->description)
#define NTYPE_LOC (OFFSETS->n_types)
#define TYPE_OFF_LOC (OFFSETS->types)
#define NCOMM_LOC (OFFSETS->n_comments)
#define COMM_LOC (OFFSETS->comments)
int *locs;
int num_locs;
int ok;
int i;
char *id = 0;
char *state = 0;
char *country = 0;
char *desc = 0;
int *idn = 0;
int *lat = 0;
int *lon = 0;
char *match_str = 0;
int *req_types = 0; /* holds indices of requested types */
int n_req_types = 0; /* number of requested types */
int *last_idx=0;
static STNTYPESINDEX *type_index = 0;
# ifdef DEBUG_STATION
Mcdprintf ("In QueryCoreDB file %s\n", file);
# endif
if (!HEADER)
{
ok = LoadCoreHeaders ();
if (ok < 0) return -1;
}
if (HEADER->version != 1) return -1;
/* malloc an array of locations */
locs = (int *)malloc (NSTATIONS * sizeof (int));
if (!locs) return -4;
num_locs = 0;
/* we don't store userid's in the core file, so return if this was
* requested
*/
if (q_info->userid) return 0;
for (i=0; i<NSTATIONS; i++)
{
int i_match;
int j;
/* if id was search condition, see if this station matches ID */
i_match = 0;
for (j = 0 ; j < q_info->n_id ; j++)
{
char *p;
if (!id)
{
id = (char *)malloc (ID_SIZE);
if (!id) return -4;
Mcread (file, (off_t) ID_LOC, (size_t) ID_SIZE, (void *)id);
}
p = id + i * ID_ELEM_SIZE;
if (strcmp (q_info->id[j], p) != 0) continue;
i_match = 1;
}
#if 0
if (q_info->n_id > 0 && !i_match) continue;
#endif
/* if idn was search condition, see if this station matches IDN */
for (j = 0 ; j < q_info->n_idn ; j++)
{
if (!idn)
{
idn = (int *)malloc (IDN_SIZE);
if (!idn) return -4;
Mcread (file, (off_t) IDN_LOC, (size_t) IDN_SIZE, (void *)idn);
M0swbyt4 (idn, NSTATIONS);
}
if (q_info->idn[j] != idn[i]) continue;
i_match = 1;
}
if ((q_info->n_idn > 0 || q_info->n_id > 0) && !i_match) continue;
/*
* if lat/lon was search condition, see if station is within
* those bounds
*/
#if 0
if ((q_info->minlat != MCMISSING4) || (q_info->minlon != MCMISSING4))
{
if (!lat || !lon)
{
lat = (int *)malloc (LATLON_SIZE);
lon = (int *)malloc (LATLON_SIZE);
if (!lat || !lon) return -4;
{
Mcread (file, (off_t) LAT_LOC, (size_t) LATLON_SIZE, (void
*)lat);
Mcread (file, (off_t) LON_LOC, (size_t) LATLON_SIZE, (void
*)lon);
}
M0swbyt4 (lat, NSTATIONS);
M0swbyt4 (lon, NSTATIONS);
}
if (lat[i] < q_info->minlat ||
lat[i] > q_info->maxlat ||
lon[i] < q_info->minlon ||
lon[i] > q_info->maxlon)
{
continue;
}
}
#endif
if (q_info->minlat != MCMISSING4 || q_info->maxlat != MCMISSING4 ||
q_info->minlon != MCMISSING4 || q_info->maxlon != MCMISSING4)
{
STATION *tmpstn;
if (!lat || !lon)
{
lat = (int *)malloc (LATLON_SIZE);
lon = (int *)malloc (LATLON_SIZE);
if (!lat || !lon) return -4;
{
Mcread (file, (off_t) LAT_LOC, (size_t) LATLON_SIZE, (void
*)lat);
Mcread (file, (off_t) LON_LOC, (size_t) LATLON_SIZE, (void
*)lon);
}
M0swbyt4 (lat, NSTATIONS);
M0swbyt4 (lon, NSTATIONS);
}
tmpstn = NewStation ();
tmpstn->lat = lat[i];
tmpstn->lon = lon[i];
ok = latlon_ok (q_info, tmpstn);
FreeStation (tmpstn);
if (!ok) continue;
}
#if 0
if (q_info->minlat != MCMISSING4 || q_info->maxlat != MCMISSING4)
{
if (!lat)
{
lat = (int *)malloc (LATLON_SIZE);
if (!lat) return -4;
Mcread (file, (off_t) LAT_LOC, (size_t) LATLON_SIZE, (void
*)lat);
M0swbyt4 (lat, NSTATIONS);
}
if (q_info->minlat != MCMISSING4 && lat[i] < q_info->minlat)
{
continue;
}
if (q_info->maxlat != MCMISSING4 && lat[i] > q_info->maxlat)
{
continue;
}
}
if (q_info->minlon != MCMISSING4 || q_info->maxlon != MCMISSING4)
{
if (!lon)
{
lon = (int *)malloc (LATLON_SIZE);
if (!lon) return -4;
Mcread (file, (off_t) LON_LOC, (size_t) LATLON_SIZE, (void
*)lon);
M0swbyt4 (lon, NSTATIONS);
}
if (q_info->minlon != MCMISSING4 && lon[i] < q_info->minlon)
{
continue;
}
if (q_info->maxlon != MCMISSING4 && lon[i] > q_info->maxlon)
{
continue;
}
}
#endif
/* if state was search condition, see if station is in that state */
if (q_info->state)
{
char *p;
if (!state)
{
state = (char *)malloc (ST_SIZE);
if (!state) return -4;
Mcread (file, (off_t) ST_LOC, (size_t) ST_SIZE, (void *)state);
}
p = state + i * ST_ELEM_SIZE;
if (strcmp (q_info->state, p) != 0) continue;
}
/* if country was search condition, see if station is in that country */
if (q_info->country)
{
char *p;
if (!country)
{
country = (char *)malloc (CO_SIZE);
if (!country) return -4;
Mcread (file, (off_t) CO_LOC, (size_t) CO_SIZE, (void
*)country);
}
p = country + i * CO_ELEM_SIZE;
if (strcmp (q_info->country, p) != 0) continue;
}
/*
* if match on station description, see if station matches that desc
* the check is done case insensitive
*/
if (q_info->match)
{
char *p;
char *t_str;
if (!desc)
{
desc = (char *)malloc (NAME_SIZE);
if (!desc) return -4;
Mcread (file, (off_t) NAME_LOC, (size_t) NAME_SIZE, (void
*)desc);
match_str = strdup (q_info->match);
Mclocase (match_str);
}
p = desc + i * NAME_ELEM_SIZE;
t_str = strdup (p);
Mclocase (t_str);
if (strstr (t_str, match_str) == 0)
{
free (t_str);
continue;
}
free (t_str);
}
/*
* if datatype was search condition, load the datatype index and
* see if this station is of that type
*/
if (q_info->n_datatypes > 0)
{
int q_type;
int match;
match = FALSE;
/* load the types index from the file if it hasn't been load yet */
if (!type_index)
{
ok = LoadTypesIndex (&type_index);
# ifdef DEBUG_STATION
Mcdprintf ("QueryCoreDB: LoadTypesIndex return %d\n", ok);
# endif
if (ok < 0) return -7;
}
/* load up the indices of the requested types */
if (n_req_types == 0)
{
req_types = (int *)malloc (q_info->n_datatypes * sizeof (int));
/* locate the index of the typename we are asked for */
for (q_type = 0 ; q_type < q_info->n_datatypes ; q_type++)
{
int t_idx;
for (t_idx = 0 ; t_idx < HEADER->n_types ; t_idx++)
{
if (strcmp (q_info->typenames[q_type],
type_names[t_idx]) == 0) break;
}
/*
* if the requested datatype is a type that isn't defined
* in the file, then go on to the next type
*/
if (t_idx >= HEADER->n_types) continue;
req_types[n_req_types] = t_idx;
n_req_types++;
}
}
if (last_idx == (int *)0)
{
last_idx = (int *)calloc (n_req_types * sizeof (int),
sizeof (int));
if (last_idx == (int *)NULL) return -1;
}
else
{
#if 0
if (i < last_idx[q_type])
{
#endif
free (last_idx);
last_idx = (int *)calloc (n_req_types * sizeof (int),
sizeof (int));
if (last_idx == (int *)NULL) return -1;
#if 0
}
#endif
}
/* look for a match on at least one of the datatypes */
for (q_type = 0 ; q_type < n_req_types ; q_type++)
{
int rt;
rt = req_types[q_type];
while (last_idx[q_type] < type_index->n_list[rt])
{
if (i == type_index->stn_list[rt][last_idx[q_type]])
{
match = TRUE;
break;
}
/*
* if we've passed this station in the index, allow the
* index to catch up
*/
if (i > type_index->stn_list[rt][last_idx[q_type]])
{
last_idx[q_type]++;
continue;
}
/* get the next station */
break;
}
if (match) break;
}
if (!match) continue;
}
/* this station matches the request */
locs[num_locs] = i;
num_locs++;
}
/* free any arrays we may have allocated above */
if (id) free (id);
if (idn) free (idn);
if (country) free (country);
if (state) free (state);
if (desc) free (desc);
if (lat) free (lat);
if (lon) free (lon);
if (match_str) free (match_str);
/*
* if no stations matched the search criteria, then do nothing
*/
if (num_locs == 0)
{
if (locs) free (locs);
return 0;
}
ok = FinalQuery (file, locs, num_locs, stn_info, num_stn, q_info);
/* free the locations array */
if (locs) free (locs);
return 0;
}
/*
*$ Name:
*$ FinalQuery - Pluck the stations from file and add to station list
*$ checking for duplicates
*$
*$ Interface:
*$ #include "mcidas.h"
*$ #include "stations.h"
*$
*$ static int
*$ FinalQuery(char *file, int *locs, int num_locs, STATION ***stations,
*$ int *num_stn, STATION_QRY *q_info)
*$
*$ Input:
*$ file - name of the core definition file
*$ locs - array of offsets into file for stations matching query
*$ num_locs- number of offsets
*$ q_info - pointer to query info
*$
*$ Input and Output:
*$ stations - pointer to array of pointers to stations matching query
*$ num_stn - pointer to number of stations matching query
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ 0 - success
*$ -4 - failed memory allocation
*$
*$
*$ Remarks:
*$
*$ Categories:
*$ system
*$ utility
*/
static int
FinalQuery (char *file, int *locs, int num_locs, STATION ***stations,
int *num_stn, STATION_QRY *q_info)
{
int num_user;
int total;
int i;
int ok;
STATION **stn_array;
STATION *stn;
# ifdef DEBUG_STATION
Mcdprintf ("In FinalQuery\n");
# endif
/*
* if no stations matched the preliminary search criteria,
* then do nothing
*/
if (num_locs == 0) return 0;
stn_array = *stations;
num_user = *num_stn;
total = num_user;
for (i=0; i<num_locs; i++)
{
/* pull all the information for this station out of the file */
stn = PluckStation (file, locs[i]);
if (stn == (STATION *)0) return -4;
/*
* we have a match on a station, see if we already have this
* station in the array from the user database, otherwise reallocate a
* new STATION pointer to the STATION array and store this station
*/
ok = HaveStation (stn_array, num_user, stn, q_info);
if (ok == 1)
{
FreeStation (stn);
continue;
}
if (ok == 2) continue;
# ifdef DEBUG_STATION
Mcdprintf (" %05d", stn->idn);
if (stn->id) Mcdprintf (" %s", stn->id);
if (stn->description) Mcdprintf (" %s\n", stn->description);
# endif
stn_array = (STATION **)realloc (stn_array,
sizeof (STATION *) * (total + 1));
stn_array[total] = stn;
total++;
}
# ifdef DEBUG_STATION
Mcdprintf ("Scanning %s results in %d matching stations\n", file,
total - num_user);
# endif
*num_stn = total;
*stations = stn_array;
return 0;
}
/*
*$ Name:
*$ HaveStation - Check if a station already exists in the list
*$
*$ Interface:
*$ #include "mcidas.h"
*$ #include "stations.h"
*$
*$ static int
*$ HaveStation(STATION **stn_array, int num, STATION *stn,
*$ STATION_QRY *query)
*$
*$ Input:
*$ stn_array - array of pointers to stations to check against
*$ num - number of stations in array
*$ stn - pointer to station to check
*$ query - pointer to query struct
*$
*$ Input and Output:
*$ none
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ 0 - station doesn't exist
*$ 1 - station already exists
*$ 2 - added to the invalid list
*$
*$
*$ Remarks:
*$
*$ Categories:
*$ system
*$ utility
*/
static int
HaveStation (STATION **stn_array, int num, STATION *stn, STATION_QRY *query)
{
int i;
/* if we have a valid date, then check all other paramters */
if (!validdate_ok (query, stn))
{
# ifdef DEBUG_STATION
Mcdprintf ("Failed valid dates\n");
# endif
/* otherwise add it to the invalid dates list of stations */
invalid_stations = (STATION **)realloc (invalid_stations,
sizeof (STATION *) * (invalid_num_stn + 1));
invalid_stations[invalid_num_stn] = stn;
invalid_num_stn++;
return 2;
}
/* first look for this station in the station list */
for (i=0; i<num; i++)
{
if (stn->idn && stn->id && stn_array[i]->id)
{
if (stn->idn == stn_array[i]->idn &&
strcmp (stn->id, stn_array[i]->id) == 0 &&
DatatypeMatch (stn,stn_array[i])) return 1;
}
if (stn->idn == 0 && stn_array[i]->id)
{
if (strcmp (stn->id, stn_array[i]->id) == 0 &&
DatatypeMatch (stn, stn_array[i])) return 1;
}
if (stn->id == (char *)0)
{
if (stn->idn == stn_array[i]->idn &&
DatatypeMatch (stn, stn_array[i])) return 1;
}
}
/* next look for it in the list of stations that have invalid dates */
/* this is so we can redefine a station in the user database with a */
/* different valid date and it will override the definition in the */
/* of this station in the core file and won't be returned to the */
/* caller of the station DB API */
stn_array = invalid_stations;
num = invalid_num_stn;
for (i=0; i<num; i++)
{
if (stn->idn && stn->id && stn_array[i]->id)
{
if (stn->idn == stn_array[i]->idn &&
strcmp (stn->id, stn_array[i]->id) == 0 &&
DatatypeMatch (stn,stn_array[i])) return 1;
}
if (stn->idn == 0 && stn_array[i]->id)
{
if (strcmp (stn->id, stn_array[i]->id) == 0 &&
DatatypeMatch (stn, stn_array[i])) return 1;
}
if (stn->id == (char *)0)
{
if (stn->idn == stn_array[i]->idn &&
DatatypeMatch (stn, stn_array[i])) return 1;
}
}
return 0;
}
static int
DatatypeMatch (STATION *st1, STATION *st2)
{
int i;
int j;
/* neither stations have any datatypes defined */
if (st1->n_datatypes == 0 && st2->n_datatypes == 0) return 1;
/* go through the datatypes */
for (i = 0 ; i < st1->n_datatypes ; i++)
{
for (j = 0 ; j < st2->n_datatypes ; j++)
{
if (strcmp (st1->typenames[i], st2->typenames[j]) == 0) return 1;
}
}
return 0;
}
/*
*$ Name:
*$ PluckStation - Pluck a station from the core station definition file
*$
*$ Interface:
*$ #include "mcidas.h"
*$ #include "stations.h"
*$
*$ static STATION *
*$ PluckStation(char *file, int loc)
*$
*$ Input:
*$ file - name of core stations definition file
*$ loc - location (offset) of station in core file
*$
*$ Input and Output:
*$ none
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ 0 - error
*$ <>0 - pointer to station plucked from file
*$
*$
*$ Remarks:
*$
*$ Categories:
*$ system
*$ utility
*/
static STATION *
PluckStation (char *file, int loc)
{
int ok;
int tmp;
int offset;
char ctmp[255];
STATION *stn;
stn = NewStation();
if (stn == (STATION *)NULL) return (STATION *)NULL;
/* station id */
offset = ID_LOC + (loc * ID_ELEM_SIZE);
ok = Mcread (file, (off_t) offset, (size_t) ID_ELEM_SIZE, (void *)ctmp);
if (ctmp && ctmp[0] != '\0') stn->id = strdup (ctmp);
/* station idn */
offset = IDN_LOC + (loc * IDN_ELEM_SIZE);
ok = Mcread (file, (off_t) offset, (size_t) IDN_ELEM_SIZE, (void *)&tmp);
(void) M0swbyt4 (&tmp, 1);
stn->idn = tmp;
/* station ARGOS ID */
offset = ARGOS_LOC + (loc * ARGOS_ELEM_SIZE);
ok = Mcread (file, (off_t) offset, (size_t) ARGOS_ELEM_SIZE, (void *)&tmp);
(void) M0swbyt4 (&tmp, 1);
stn->ARGOS = tmp;
/* station latitude */
offset = LAT_LOC + (loc * LATLON_ELEM_SIZE);
ok = Mcread (file, (off_t) offset, (size_t) LATLON_ELEM_SIZE, (void *)&tmp);
(void) M0swbyt4 (&tmp, 1);
stn->lat = tmp;
/* station longitude */
offset = LON_LOC + (loc * LATLON_ELEM_SIZE);
ok = Mcread (file, (off_t) offset, (size_t) LATLON_ELEM_SIZE, (void *)&tmp);
(void) M0swbyt4 (&tmp, 1);
stn->lon = tmp;
/* station upper latitude */
offset = ULAT_LOC + (loc * LATLON_ELEM_SIZE);
ok = Mcread (file, (off_t) offset, (size_t) LATLON_ELEM_SIZE, (void *)&tmp);
(void) M0swbyt4 (&tmp, 1);
stn->uplat = tmp;
/* station upper longitude */
offset = ULON_LOC + (loc * LATLON_ELEM_SIZE);
ok = Mcread (file, (off_t) offset, (size_t) LATLON_ELEM_SIZE, (void *)&tmp);
(void) M0swbyt4 (&tmp, 1);
stn->uplon = tmp;
/* station elevation */
offset = ELE_LOC + (loc * ELE_ELEM_SIZE);
ok = Mcread (file, (off_t) offset, (size_t) ELE_ELEM_SIZE, (void *)&tmp);
(void) M0swbyt4 (&tmp, 1);
stn->ele = tmp;
/* station upper elevation */
offset = UELE_LOC + (loc * ELE_ELEM_SIZE);
ok = Mcread (file, (off_t) offset, (size_t) ELE_ELEM_SIZE, (void *)&tmp);
(void) M0swbyt4 (&tmp, 1);
stn->upele = tmp;
/* station country */
offset = CO_LOC + (loc * CO_ELEM_SIZE);
ok = Mcread (file, (off_t) offset, (size_t) CO_ELEM_SIZE, (void *)ctmp);
if (ctmp) stn->country = strdup (ctmp);
/* station state */
offset = ST_LOC + (loc * ST_ELEM_SIZE);
ok = Mcread (file, (off_t) offset, (size_t) ST_ELEM_SIZE, (void *)ctmp);
if (ctmp) stn->state = strdup (ctmp);
/* station datatypes */
{
int bytes;
int n_types;
int *types;
int types_offset;
int types_idx;
int *t;
/* read the number of types for this station */
offset = NTYPE_LOC + (loc * NTYPE_ELEM_SIZE);
ok = Mcread (file, (off_t) offset, (size_t) NTYPE_ELEM_SIZE, (void
*)&n_types);
(void) M0swbyt4 (&n_types, 1);
if (n_types != 0)
{
/* read the offset to the types for this station */
offset = TYPE_OFF_LOC + (loc * TYPE_OFF_ELEM_SIZE);
ok = Mcread (file, (off_t) offset, (size_t) TYPE_OFF_ELEM_SIZE,
(void *)&types_offset);
(void) M0swbyt4 (&types_offset, 1);
/* now read the types for this station */
/* the types are a list of numbers that index into the array
* of strings which names the datatypes */
bytes = n_types * sizeof (int);
types = (int *)malloc (bytes);
if (types == (int *)NULL) return (STATION *)NULL;
ok = Mcread (file, (off_t) types_offset, (size_t) bytes, types);
(void) M0swbyt4 (types, n_types);
stn->typenames = calloc (n_types * sizeof (char *), sizeof (char
*));
stn->n_datatypes = n_types;
t = types;
for (types_idx = 0 ; types_idx < n_types ; types_idx++)
{
stn->typenames[types_idx] = type_names[*t];
t++;
}
free (types);
}
}
/* station description */
offset = NAME_LOC + (loc * NAME_ELEM_SIZE);
ok = Mcread (file, (off_t) offset, (size_t) NAME_ELEM_SIZE, (void *)ctmp);
if (ctmp) stn->description = strdup (ctmp);
return stn;
}
static int
idn_ok (STATION_QRY *q_info, STATION *stn, int idx)
{
if (q_info->idn[idx] == 0) return 1;
if (q_info->idn[idx] == stn->idn) return 1;
return 0;
}
static int
validdate_ok (STATION_QRY *q_info, STATION *stn)
{
/* both query beginning and end date are before the station was active */
if (q_info->valid.bdate < stn->valid.bdate &&
q_info->valid.edate < stn->valid.bdate) return 0;
/* both query beginning and end date are after the station was active */
if (q_info->valid.bdate > stn->valid.edate &&
q_info->valid.edate > stn->valid.edate) return 0;
/*
* otherwise the requested date fits somewhere in the time the station
* was active
*/
return 1;
}
static int
latlon_ok (STATION_QRY *q_info, STATION *stn)
{
static int domain = 0;
static int last_lone = MCMISSING4;
static int last_lonw = MCMISSING4;
int lonw;
int lone;
if (q_info->minlat != MCMISSING4 || q_info->maxlat != MCMISSING4)
{
if (q_info->minlat != MCMISSING4 && stn->lat < q_info->minlat)
{
return 0;
}
if (q_info->maxlat != MCMISSING4 && stn->lat > q_info->maxlat)
{
return 0;
}
}
/* do we need to check lon bounds */
if (q_info->maxlon == MCMISSING4 &&
q_info->minlon == MCMISSING4) return 1;
lonw = q_info->maxlon;
lone = q_info->minlon;
if (lone == MCMISSING4) lone = -1800000;
if (lonw == MCMISSING4) lonw = 1800000;
/* now determine what type of range the longitude
* boundaries exist for. this is very important
* because this information is used to
* determine if a station is within the
* defined box.
*
* ---western hemi---0---eastern hemi---180---western hemi---0---
* | | |
* #--domain=1 --# | | |
* | | |
* #--domain=1 --# | |
* | | |
* | #-- domain=1 --# | |
* | | |
* | #-- domain=2 --# |
* | | |
* | #---------domain=3 --------#
* | | |
* #-------- domain=4 --------# |
* | | |
*/
if (!domain || lone != last_lone || lonw != last_lonw)
{
if (lonw > lone) domain = 1;
else if (lonw < 0 && lonw < lone && lone >= 0) domain = 2;
else if (lonw < 0 && lonw < lone && lone < 0) domain = 3;
else if (lonw >= 0 && lonw < lone && lone > 0) domain = 4;
}
switch(domain)
{
case 1:
if (lonw >= stn->lon && stn->lon >= lone) return 1;
break;
case 2:
if (lonw <= stn->lon && stn->lon >= lone) return 1;
break;
case 3:
if (stn->lon >= 0 ||
(lonw >= stn->lon || stn->lon >= lone)) return 1;
break;
case 4:
if (stn->lon <= 0 ||
(lonw >= stn->lon || stn->lon >= lone)) return 1;
break;
default: return 0;
}
#if 0
if (q_info->minlon != MCMISSING4 || q_info->maxlon != MCMISSING4)
{
if (q_info->minlon != MCMISSING4 && stn->lon < q_info->minlon)
{
return 0;
}
if (q_info->maxlon != MCMISSING4 && stn->lon > q_info->maxlon)
{
return 0;
}
}
#endif
return 0;
}
static int
id_ok (STATION_QRY *q_info, STATION *stn, int idx)
{
/* id not requested */
if (!q_info->id[idx]) return 1;
/* id requested, but no id for station */
if (!stn->id) return 0;
if (strcmp (q_info->id[idx], stn->id) == 0) return 1;
return 0;
}
static int
userid_ok (STATION_QRY *q_info, STATION *stn, int idx)
{
/* user id not requested */
if (!q_info->userid[idx]) return 1;
/* id requested, but no id for station */
if (!stn->userid) return 0;
if (strcmp (q_info->userid[idx], stn->userid) == 0) return 1;
return 0;
}
static int
country_ok (STATION_QRY *q_info, STATION *stn)
{
/* country not requested */
if (!q_info->country) return 1;
/* country requested, but no country for station */
if (!stn->country) return 0;
if (strcmp (q_info->country, stn->country) == 0) return 1;
return 0;
}
static int
state_ok (STATION_QRY *q_info, STATION *stn)
{
/* state not requested */
if (!q_info->state) return 1;
/* state requested, but no state for station */
if (!stn->state) return 0;
if (strcmp (q_info->state, stn->state) == 0) return 1;
return 0;
}
static int
name_ok (STATION_QRY *q_info, STATION *stn)
{
char *s1;
char *s2;
int match = 0;
/* name not requested */
if (!q_info->match) return 1;
/* match string requested, but no state for station */
if (!stn->description) return 0;
/* duplicate strings and convert to common case */
s1 = strdup (stn->description);
s2 = strdup (q_info->match);
if (s1 && s2)
{
Mcupcase (s1);
Mcupcase (s2);
if (strstr (s1, s2)) match = 1;
free (s1);
free (s2);
}
if (match) return 1;
return 0;
}
static int
datatype_ok (STATION_QRY *q_info, STATION *stn)
{
int i;
int j;
/* datatype not requested */
if (!q_info->n_datatypes) return TRUE;
for (i = 0 ; i < q_info->n_datatypes ; i++)
{
for (j = 0 ; j < stn->n_datatypes ; j++)
{
if (strcmp (q_info->typenames[i], stn->typenames[j]) == 0)
{
return TRUE;
}
}
}
return FALSE;
}
/*
*$ Name:
*$ ReadAsciiStation - Parse the station from a line of a user definition
*$ file
*$
*$ Interface:
*$ #include "mcidas.h"
*$ #include "stations.h"
*$
*$ static STATION *
*$ ReadAsciiStation(char *buf)
*$
*$ Input:
*$ buf - buffer containing text of station definition
*$
*$ Input and Output:
*$ none
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ 0 - error (failed to parse buffer or memory allocation error)
*$ <>0 - pointer to station parsed from buffer
*$
*$
*$ Remarks:
*$
*$ Categories:
*$ system
*$ utility
*/
static STATION *
ReadAsciiStation (char *buf)
{
int handle;
int num_stn_types;
int num_stn_comments;
int j;
int ok;
char *ctmp;
char *p;
STATION *stn;
/*
* remove any line feeds and any tab characters, otherwise the McIDAS
* arg parser pukes
*/
p = buf + strlen (buf);
while (p > buf)
{
if (*p == '\n')
{
*p = '\0';
}
if (*p == '\t')
{
*p = ' ';
}
p--;
}
/* use the McIDAS arg parser to parse the line */
# ifdef DEBUG_STATION
Mcdprintf ("User Defined: %s\n", buf);
# endif
handle = Mcargparse (buf, (McArgSyntax *)NULL, (int *)NULL);
if (handle < 0)
{
return (STATION *)NULL;
}
/* if the station doesn't have any identification, return */
if (Mcargnum (handle, "ID") < 1 &&
Mcargnum (handle, "IDN") < 1 &&
Mcargnum (handle, "ARGOS") < 1)
{
Mceprintf ("Error in station file:\n");
Mceprintf (" station doesn't have an ID, IDN, or ARGOS "
"identification\n");
Mcargfree (handle);
return (STATION *)NULL;
}
/* allocate a new station structure */
stn = NewStation ();
if (stn == (STATION *)NULL) return stn;
/* station IDN */
ok = Mcargint (handle, "IDN", 1, 0, 0, 999999, &stn->idn,
(const char **)NULL);
/* station ID */
ok = Mcargstr (handle, "ID", 1, (char *)NULL, (const char **)&ctmp);
if (ctmp) stn->id = strdup (ctmp);
/* station USERID (if provided) replaces ID */
ok = Mcargstr (handle, "USE.RID", 1, (char *)NULL,
(const char **)&ctmp);
if (ctmp)
{
stn->userid = strdup (ctmp);
}
/* station lat/lon */
ok = Mcargill (handle, "LAT.LON", 1, MCMISSING4, 999, -999, &stn->lat,
(const char **)NULL);
ok = Mcargill (handle, "LAT.LON", 2, MCMISSING4, 999, -999, &stn->lon,
(const char **)NULL);
/* station lat/lon */
ok = Mcargill (handle, "ULAT.LON", 1, MCMISSING4, 999, -999,
&stn->uplat, (const char **)NULL);
ok = Mcargill (handle, "ULAT.LON", 2, MCMISSING4, 999, -999,
&stn->uplon, (const char **)NULL);
/* country of station */
ok = Mcargstr (handle, "CO", 1, (char *)NULL, (const char **)&ctmp);
if (ctmp) stn->country = strdup (ctmp);
/* state of station */
ok = Mcargstr (handle, "ST", 1, (char *)NULL, (const char **)&ctmp);
if (ctmp) stn->state = strdup (ctmp);
/* station name */
ok = Mcargstr (handle, "NAME", 1, (char *)NULL, (const char **)&ctmp);
if (ctmp) stn->description = strdup (ctmp);
/* station ELE */
ok = Mcargint (handle, "ELE", 1, 0, 0, MCMISSING4, &stn->ele,
(const char **)NULL);
/* station UELE */
ok = Mcargint (handle, "UELE", 1, 0, 0, MCMISSING4, &stn->upele,
(const char **)NULL);
/* beginning valid date */
ok = Mcargiyd (handle, "VAL.ID", 1, BOTIME, EOTIME, BOTIME,
&(stn->valid.bdate), (const char **)NULL);
/* ending valid date */
ok = Mcargiyd (handle, "VAL.ID", 2, EOTIME, EOTIME, EOTIME,
&(stn->valid.edate), (const char **)NULL);
/* station types */
num_stn_types = Mcargnum (handle, "DATA.TYPE");
if (num_stn_types > 0)
{
stn->n_datatypes = num_stn_types;
stn->typenames = (char **)malloc (sizeof (char **) *
stn->n_datatypes);
if (stn->typenames == (char **)NULL) return (STATION *)NULL;
}
for (j=0; j<num_stn_types; j++)
{
int i_loc;
Mcargstr (handle, "DATA.TYPE", j+1, (char *)NULL,
(const char **)&ctmp);
i_loc = AddTypename (ctmp, &user_type_names, &num_user_types);
if (i_loc < 0)
{
Mcargfree (handle);
return (STATION *)NULL;
}
stn->typenames[j] = user_type_names[i_loc];
}
/* station comments */
num_stn_comments = Mcargnum (handle, "COM.MENTS");
if (num_stn_comments > 0)
{
stn->n_comments = num_stn_comments;
stn->comments = (char **)malloc (sizeof (char **) *
stn->n_comments);
if (stn->comments == (char **)NULL) return (STATION *)NULL;
}
for (j=0; j<num_stn_comments; j++)
{
Mcargstr (handle, "COM.MENTS", j+1, (char *)NULL,
(const char **)&ctmp);
stn->comments[j] = strdup (ctmp);
}
/* station priority */
ok = Mcargint (handle, "PRI.ORITY", 1, MINPRIORITY, MINPRIORITY,
MAXPRIORITY, &(stn->priority), (const char **)NULL);
/* WSFO zone number stations resides */
ok = Mcargint (handle, "ZON.E", 1, 0, 999, -999, &(stn->WFO_zone),
(const char **)NULL);
/* station is in a zone of this WSFO */
ok = Mcargstr (handle, "WSFO", 1, (char *)NULL, (const char **)&ctmp);
if (ctmp) stn->WSFO_office = strdup (ctmp);
Mcargfree (handle);
return stn;
}
/*
* Add the typename to a type list
*
* Returns
* -1 memory allocation error
* >= 0 index in the names array that the typename is located
*/
static int
AddTypename (char *t_name, char ***names, int *num)
{
int i;
char **nms;
int n;
nms = *names;
n = *num;
for (i = 0 ; i < n ; i++)
{
if (strcmp (t_name, nms[i]) == 0) return i;
}
n++;
nms = realloc (nms, sizeof (char *) * n);
if (nms == (char **)0) return -1;
nms[n-1] = strdup (t_name);
*names = nms;
*num = n;
return (n - 1);
}
/*
*$ Name:
*$ NewStation - allocate and initialize a new station structure
*$
*$ Interface:
*$ #include "mcidas.h"
*$ #include "stations.h"
*$
*$ STATION *
*$ NewStation(void)
*$
*$ Input:
*$ none
*$
*$ Input and Output:
*$ none
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ 0 - error (failed to parse buffer or memory allocation error)
*$ <>0 - pointer to freshly allocated station
*$
*$
*$ Remarks:
*$
*$ Station structure should be freed by calling the function
*$ FreeStation ().
*$
*$ Categories:
*$ system
*$ utility
*/
STATION *
NewStation (void)
{
STATION *stn;
stn = (STATION *) malloc (sizeof (STATION));
if (stn == (STATION *)NULL) return (STATION *)NULL;
memset (stn, 0, sizeof (STATION));
stn->lat = MCMISSING4;
stn->lon = MCMISSING4;
stn->ele = MCMISSING4;
stn->uplat = MCMISSING4;
stn->uplon = MCMISSING4;
stn->upele = MCMISSING4;
stn->priority = 10;
stn->valid.bdate = BOTIME;
stn->valid.edate = EOTIME;
return stn;
}
/*
*$ Name:
*$ FreeStation - frees a station and all allocated elements
*$
*$ Interface:
*$ #include "mcidas.h"
*$ #include "stations.h"
*$
*$ void
*$ FreeStation(STATION *stn)
*$
*$ Input:
*$ stn - pointer to station to free
*$
*$ Input and Output:
*$ none
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ 0 - error (failed to parse buffer or memory allocation error)
*$ <>0 - pointer to freshly allocated station
*$
*$
*$ Remarks:
*$
*$ Frees memory for a station created by calling NewStation(). All
*$ dynamically allocated fields of the structure are also freed (station
*$ ID, datatype names, etc).
*$
*$ Categories:
*$ system
*$ utility
*/
void
FreeStation (STATION *stn)
{
int i;
/* free all allocated strings */
if (stn->id) free (stn->id);
if (stn->description) free (stn->description);
if (stn->state) free (stn->state);
if (stn->country) free (stn->country);
if (stn->county) free (stn->county);
if (stn->WSFO_office) free (stn->WSFO_office);
if (stn->continent) free (stn->continent);
/* free the comment strings */
for (i = 0 ; i < stn->n_comments ; i++)
{
if (stn->comments[i]) free (stn->comments[i]);
}
if (stn->comments) free (stn->comments);
/* now free the station structure */
free (stn);
}
#ifdef IDINFO
Fint
idinfo_ (const char *id, Fint *idn, Fint *f5or6, Fint *ewflg, Fint *llwflg,
Fint *lat, Fint *lon, Fint *state, Fint *country, Fint *ele,
FsLen id_len)
{
STATION_QRY query;
STATION *stn;
int num_stn;
int handle;
memset ((void *)&query, 0, sizeof (STATION_QRY));
query.minlat = MCMISSING4;
query.maxlat = MCMISSING4;
query.minlon = MCMISSING4;
query.maxlon = MCMISSING4;
if (id_len == 0 && idn == 0) return 0;
if (id_len > 0 && id)
{
query.id = fsalloc (id, id_len);
*idn = 0;
}
else
{
query.idn = *idn;
memset (id, ' ', 8);
}
handle = McSTNOpenQuery (query);
if (handle < 0) return 0;
num_stn = McSTNGetNumStations (handle);
if (num_stn < 1) return 0;
stn = McSTNGetNextStation (handle);
if (stn == (STATION *)0) return 0;
*lat = 0;
*lon = 0;
*ele = 0;
memset (state, ' ', sizeof (Fint));
memset (country, ' ', sizeof (Fint));
if (stn->country) strcpy ((char *)country, stn->country);
if (stn->state) strcpy ((char *)state, stn->state);
if (*llwflg)
{
Freal f_tmp;
f_tmp = flalo_ ((Fint *)&stn->lat);
*lat = f_tmp * 10000;
f_tmp = flalo_ ((Fint *)&stn->lon);
*lon = f_tmp * 10000;
}
else
{
*lat = stn->lat;
*lon = stn->lon;
}
if (*ewflg == -1)
{
*lat *= -1;
*lon *= -1;
}
*ele = stn->ele;
McSTNCloseQuery (handle);
return 1;
}
#endif
/*
*$ Name:
*$ mcstnopenquery - Opens a query to the station database
*$
*$ Interface:
*$ include 'stations.inc'
*$
*$ integer function
*$ mcstnopenquery()
*$
*$ Input:
*$ none
*$
*$ Input and Output:
*$ none
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ >-1 - handle to successful query
*$ -1 - maximum number of queries reached
*$ -2 - query failed
*$
*$ Remarks:
*$ This function opens a query to the station database. Before calling
*$ this function, the query common block must be filled with information
*$ describing the station(s) you are looking for. Upon successful
*$ completion, a handle to the query is returned. The query common block
*$ is defined in the Fortran include file stations.inc.
*$
*$ Call mcstnclosequery to close this query after all stations have been
*$ retrieved. This frees memory allocated for the query and releases this
*$ handle so it can be used again.
*$
*$ No more than 255 queries can be active simultaneously.
*$
*$ Categories:
*$ system
*$ utility
*$
*$ Filename:
*$ stnqry.c
*/
Fint
mcstnopenquery_ (void)
{
int ok;
STATION_QRY query;
ok = McSTNSetQueryDefaults (&query);
if (ok != 0) return -1;
query.id = (char **)malloc (sizeof (char *));
if (query.id == (char **)NULL)
{
return -10;
}
query.id[0] = fsalloc (fstnqry_.q_id, F_IDLEN);
if (query.id[0] == (char *)NULL)
{
return -10;
}
query.n_id = 1;
if (!query.id[0] || query.id[0][0] == '\0')
{
free (query.id[0]);
free (query.id);
query.id = (char **)NULL;
query.n_id = 0;
}
query.userid = (char **)malloc (sizeof (char *));
query.userid[0] = fsalloc (fstnqry_.q_userid, F_IDLEN);
if (query.userid[0] == (char *)NULL)
{
return -10;
}
query.n_userid = 1;
if (!query.userid[0] || query.userid[0][0] == '\0')
{
free (query.userid[0]);
free (query.userid);
query.userid = (char **)NULL;
query.n_userid = 0;
}
if (fstnqry_.q_idn)
{
query.idn = (int *)malloc (sizeof (int));
query.idn[0] = fstnqry_.q_idn;
query.n_idn = 1;
}
query.match = fsalloc (fstnqry_.q_match, F_NAMELEN);
if (query.match == (char *)NULL)
{
return -10;
}
if (query.match && query.match[0] == '\0')
{
free (query.match);
query.match = (char *)NULL;
}
query.minlat = fstnqry_.q_minlat;
query.maxlat = fstnqry_.q_maxlat;
query.minlon = fstnqry_.q_minlon;
query.maxlon = fstnqry_.q_maxlon;
query.valid.bdate = fstnqry_.q_mindate;
query.valid.edate = fstnqry_.q_maxdate;
query.state = fsalloc (fstnqry_.q_state, F_STATELEN);
if (query.state == (char *)NULL)
{
return -10;
}
if (query.state && query.state[0] == '\0')
{
free (query.state);
query.state = (char *)NULL;
}
query.country = fsalloc (fstnqry_.q_country, F_COUNTRYLEN);
if (query.country == (char *)NULL)
{
return -10;
}
if (query.country && query.country[0] == '\0')
{
free (query.country);
query.country = (char *)NULL;
}
query.county = fsalloc (fstnqry_.q_county, F_COUNTYLEN);
if (query.county == (char *)NULL)
{
return -10;
}
if (query.county && query.county[0] == '\0')
{
free (query.county);
query.county = (char *)NULL;
}
query.priority = fstnqry_.q_priority;
query.n_datatypes = fstnqry_.q_n_datatypes;
if (query.n_datatypes > 0)
{
query.typenames = Mcfstoarr ((char *)fstnqry_.q_typenames,
query.n_datatypes,
F_TYPELEN);
if (query.typenames == (char **)NULL)
{
return -11;
}
}
ok = McSTNOpenQuery (&query);
/* free all the C allocated strings */
if (query.id) free (query.id);
if (query.match) free (query.match);
if (query.state) free (query.state);
if (query.country) free (query.country);
if (query.county) free (query.county);
if (query.typenames) Mcfreearr (query.typenames, query.n_datatypes);
/* return the results */
return ((Fint)ok);
}
/*
*$ Name:
*$ mcstngetnextstation - Return the next station matching a query
*$
*$ Interface:
*$ include 'stations.inc'
*$
*$ integer function
*$ mcstngetnextstation(int handle)
*$
*$ Input:
*$ handle - handle to the query opened with mcstnopenquery.
*$
*$ Input and Output:
*$ none
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ 0 - sucess; next station returned
*$ -1 - invalid handle
*$ -2 - no more stations to be returned
*$ -3 - failed converting typenames or comments to Fortran (memory
*$ allocation error)
*$
*$ Remarks:
*$ The query must first be opened by calling mcstnopenquery.
*$
*$ This function returns the station by filling the common block FSTN.
*$ After successfully calling this function the variables of this common
*$ contain all the information for the station.
*$
*$ Continue calling this function to retrieve all stations that match the
*$ query. mcstngetnumstations will give you the number of stations matching
*$ a particular query.
*$
*$ Categories:
*$ system
*$ utility
*/
Fint
mcstngetnextstation_ (Fint *f_handle)
{
int handle;
int ok;
STATION *stn;
handle = *f_handle;
/* verify we received a valid handle */
if (handle < 0 || handle >= MAXQUERIES)
{
return -1;
}
/* Get the information for the next station */
stn = McSTNGetNextStation (handle);
if (stn == (STATION *)NULL)
{
return -2;
}
/* initialize the return strings to blanks */
memset (fstn_.s_id, ' ', F_IDLEN);
memset (fstn_.s_userid, ' ', F_IDLEN);
memset (fstn_.s_desc, ' ', F_NAMELEN);
memset (fstn_.s_state, ' ', F_STATELEN);
memset (fstn_.s_country, ' ', F_COUNTRYLEN);
memset (fstn_.s_county, ' ', F_COUNTYLEN);
memset (fstn_.s_wsfo_office,' ', F_WSFOLEN);
memset (fstn_.s_continent, ' ', F_CONTLEN);
memset (fstn_.s_typenames, ' ', F_MAXTYPES * F_TYPELEN);
memset (fstn_.s_comments, ' ', F_MAXCOMMENTS * F_COMMENTLEN);
/* copy the C strings to the Fortran strings */
if (stn->id) Mcstrtofs (fstn_.s_id, stn->id, F_IDLEN);
if (stn->userid) Mcstrtofs (fstn_.s_userid, stn->userid,
F_IDLEN);
if (stn->description) Mcstrtofs (fstn_.s_desc, stn->description,
F_NAMELEN);
if (stn->country) Mcstrtofs (fstn_.s_country,stn->country,
F_COUNTRYLEN);
if (stn->county) Mcstrtofs (fstn_.s_county, stn->county,
F_COUNTYLEN);
if (stn->state) Mcstrtofs (fstn_.s_state, stn->state,
F_STATELEN);
if (stn->WSFO_office) Mcstrtofs (fstn_.s_wsfo_office,
stn->WSFO_office, F_WSFOLEN);
if (stn->continent) Mcstrtofs (fstn_.s_continent, stn->continent,
F_CONTLEN);
if (stn->n_datatypes > 0)
{
ok = Mcarrtofs ((const char * const *) stn->typenames,
stn->n_datatypes,
F_MAXTYPES,
F_TYPELEN,
(char *)fstn_.s_typenames);
if (ok == -9999) return -3;
}
fstn_.s_n_datatypes = stn->n_datatypes;
if (stn->n_comments > 0)
{
ok = Mcarrtofs ((const char * const *) stn->comments,
stn->n_comments,
F_MAXCOMMENTS,
F_COMMENTLEN,
(char *)fstn_.s_comments);
if (ok == -9999) return -3;
}
fstn_.s_n_comments = stn->n_comments;
/* copy the binary data */
fstn_.s_idn = stn->idn;
fstn_.s_argos = stn->ARGOS;
fstn_.s_lat = stn->lat;
fstn_.s_lon = stn->lon;
fstn_.s_ele = stn->ele;
fstn_.s_uplat = stn->uplat;
fstn_.s_uplon = stn->uplon;
fstn_.s_upele = stn->upele;
fstn_.s_bdate = stn->valid.bdate;
fstn_.s_edate = stn->valid.edate;
fstn_.s_wfo_zone = stn->WFO_zone;
fstn_.s_gmt_offset = stn->GMT_offset;
fstn_.s_classification = stn->classification;
fstn_.s_priority = stn->priority;
return 0;
}
/*
*$ Name:
*$ LoadCoreHeaders - load the headers from the core file
*$
*$ Interface:
*$ #include "mcidas.h"
*$ #include "stations.h"
*$
*$ static int
*$ LoadCoreHeaders(void)
*$
*$ Input:
*$ none
*$
*$ Input and Output:
*$ none
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ 0 - success
*$ -1 - memory allocation error
*$ -2 - error reading header
*$ -3 - error reading sizes header
*$ -4 - error reading data offsets header
*$ -5 - error reading index header
*$ -6 - error reading datatypes
*$
*$ Remarks:
*$
*$ Categories:
*$ system
*$ utility
*/
static int
LoadCoreHeaders ()
{
int ok;
int last_byte;
int i;
char *ctmp = 0;
HEADER = malloc (sizeof (STNHEADER));
OFFSETS = malloc (sizeof (STNDATAOFFSET));
SIZES = malloc (sizeof (STNSIZES));
INDEX = malloc (sizeof (STNINDEXHEADER));
if (HEADER == (STNHEADER *)NULL ||
OFFSETS == (STNDATAOFFSET *)NULL ||
SIZES == (STNSIZES *)NULL ||
INDEX == (STNINDEXHEADER *)NULL) return -1;
# ifdef DEBUG_STATION
Mcdprintf ("LoadCoreHeaders:\n");
# endif
/* read the header block */
ok = Mcread (core_file, (off_t) 0, sizeof (STNHEADER), (void *)HEADER);
if (ok < 0) return -2;
M0swbyt4 (HEADER, sizeof (STNHEADER) / 4);
/* read the sizes block */
ok = Mcread (core_file, (off_t) HEADER->sizes_blk, sizeof (STNSIZES), (void
*)SIZES);
if (ok < 0) return -3;
M0swbyt4 (SIZES, sizeof (STNSIZES) / 4);
/* read the data offsets block */
ok = Mcread (core_file, (off_t) HEADER->data_offset_blk,
sizeof (STNDATAOFFSET), (void *)OFFSETS);
if (ok < 0) return -4;
M0swbyt4 (OFFSETS, sizeof (STNDATAOFFSET) / 4);
/* read the index header block */
ok = Mcread (core_file, (off_t) HEADER->index_info_blk, sizeof
(STNINDEXHEADER),
(void *)INDEX);
if (ok < 0) return -5;
M0swbyt4 (INDEX, sizeof (STNINDEXHEADER) / 4);
# ifdef DEBUG_STATION
Mcdprintf ("LoadCoreHeaders: reading %d datatypes\n", HEADER->n_types);
# endif
/* allocate temporary storage */
ctmp = calloc (SIZES->typename * sizeof (char) + 1, sizeof (char));
/* starting location to read from */
last_byte = HEADER->types_blk;
/* read the datatypes and save a copy of them */
num_types = 0;
for (i = 0 ; i < HEADER->n_types ; i++)
{
ok = Mcread (core_file, (off_t) last_byte, (size_t) SIZES->typename,
(void *)ctmp);
if (ok < 0) return -6;
AddTypename (ctmp, &type_names, &num_types);
last_byte += SIZES->typename;
}
/* free temporary storage */
if (ctmp) free (ctmp);
return 0;
}
/*
*$ Name:
*$ LoadTypesIndex - load the datatypes index from the core file
*$
*$ Interface:
*$ #include "mcidas.h"
*$ #include "stations.h"
*$
*$ static int
*$ LoadTypesIndex(STNTYPESINDEX **t_index)
*$
*$ Input:
*$ none
*$
*$ Input and Output:
*$ t_index - pointer to the datatypes index
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ 0 - success
*$ -1 - memory allocation error
*$ -2 - index header missing
*$ -3 - no datatypes in file, thus no index
*$
*$ Remarks:
*$
*$ t_index is dynamically allocated by this function.
*$
*$ Categories:
*$ system
*$ utility
*/
static int
LoadTypesIndex (STNTYPESINDEX **t_index)
{
STNTYPESINDEX *typesidx;
int *num_list;
int **stn_list;
int n_types;
unsigned n_bytes;
int last_byte;
int i;
typesidx = malloc (sizeof (STNTYPESINDEX));
if (typesidx == (STNTYPESINDEX *)NULL) return -1;
if (HEADER->n_types < 1) return -3;
n_types = HEADER->n_types;
# if DEBUG_STATION
Mcdprintf ("LoadTypesIndex: n_types = %d\n", n_types);
# endif
if (INDEX->type_index_offset == MCMISSING) return -2;
# ifdef DEBUG_STATION
Mcdprintf ("LoadTypesIndex: mallocing num_list\n");
# endif
num_list = (int *)malloc (n_types * sizeof (int));
if (num_list == (int *)NULL) return -1;
Mcread (core_file, (off_t) INDEX->type_index_offset, (size_t) (n_types *
sizeof (int)),
(void *)num_list);
M0swbyt4 (num_list, n_types);
# ifdef DEBUG_STATION
Mcdprintf ("LoadTypesIndex: mallocing stn_list pointers\n");
# endif
stn_list = (int **)malloc (n_types * sizeof (int *));
if (stn_list == (int **)NULL) return -1;
last_byte = INDEX->type_index_offset + n_types * sizeof (int);
for (i = 0 ; i < n_types ; i++)
{
# ifdef DEBUG_STATION
Mcdprintf ("LoadTypesIndex: %d stations for type %d\n",
num_list[i], i);
# endif
/* if we have stations for this type, load the index for that type */
if (num_list[i] > 0)
{
n_bytes = num_list[i] * sizeof (int);
# ifdef DEBUG_STATION
Mcdprintf ("LoadTypesIndex: mallocing stn_list[%d] pointers\n",
i);
# endif
stn_list[i] = (int *)malloc (n_bytes);
if (stn_list[i] == (int *)NULL) return -1;
Mcread (core_file, (off_t) last_byte, (size_t) n_bytes, (void
*)stn_list[i]);
M0swbyt4 (stn_list[i], n_bytes / 4);
last_byte += n_bytes;
}
}
typesidx->n_list = num_list;
typesidx->stn_list = stn_list;
*t_index = typesidx;
return 0;
}
/*
*$ Name:
*$ McSTNQueryAddID - Adds this character ID to list of ID's in query
*$
*$ Interface:
*$ #include "mcidas.h"
*$ #include "stations.h"
*$
*$ int
*$ McSTNQueryAddID(STATION_QRY *query, char *id)
*$
*$ Input:
*$ id - ID of the station to add to the query id list
*$
*$ Input and Output:
*$ query - query structure
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ 0 - OK
*$ -1 - memory allocation error
*$
*$ Remarks:
*$ Memory for the list of pointers to the strings is reallocated each
*$ time a new id is added. Also, new memory for id string is allocated.
*$ It is up to the caller to free this memory.
*$
*$ Categories:
*$ system
*$ utility
*$
*$ Filename:
*$ stnqry.c
*/
int
McSTNQueryAddID (STATION_QRY *query, char *id)
{
int n_id;
if (id == (char *)NULL) return -2;
n_id = query->n_id;
if (n_id == 0) query->id = 0;
query->id = (char **)realloc (query->id, (n_id + 1) * sizeof (char *));
if (query->id == (char **)NULL) return -1;
query->id[n_id] = (char *)strdup (id);
if (query->id[n_id] == (char *)NULL) return -1;
query->n_id++;
return 0;
}
/*
*$ Name:
*$ McSTNQueryAddIDN - Adds this block number to list of IDN's in query
*$
*$ Interface:
*$ #include "mcidas.h"
*$ #include "stations.h"
*$
*$ int
*$ McSTNQueryAddIDN(STATION_QRY *query, int idn)
*$
*$ Input:
*$ idn - IDN (Block number) of the station to add to the query id list
*$
*$ Input and Output:
*$ query - query structure
*$
*$ Output:
*$ none
*$
*$ Return values:
*$ 0 - OK
*$ -1 - memory allocation error
*$
*$ Remarks:
*$ Memory for the list of wmo block number is reallocated each
*$ time a new block number is added.
*$ It is up to the caller to free this memory.
*$
*$ Categories:
*$ system
*$ utility
*$
*$ Filename:
*$ stnqry.c
*/
int
McSTNQueryAddIDN (STATION_QRY *query, int idn)
{
int n_idn;
n_idn = query->n_idn;
if (n_idn == 0) query->idn = 0;
query->idn = (int *)realloc (query->idn, (n_idn + 1) * sizeof (int));
if (query->idn == (int *)NULL) return -1;
query->idn[n_idn] = idn;
query->n_idn++;
return 0;
}
void
print_station (STATION *s)
{
#ifdef DEBUG_STATION
#endif
}
void
print_query (STATION_QRY *q)
{
#ifdef DEBUG_STATION
int i;
Mcprintf ("STATION_QRY\n");
Mcprintf ("-----------\n");
if (q->n_id)
{
Mcprintf (" id: ");
for (i = 0 ; i < q->n_id ; i++)
{
if (q->id) Mcprintf ("\"%s\",", q->id[i]);
}
}
Mcprintf ("\n");
if (q->n_idn)
{
Mcprintf (" idn:");
for (i = 0 ; i < q->n_idn ; i++)
{
Mcprintf (" %d", q->idn[i]);
}
Mcprintf ("\n");
}
Mcprintf (" state: ");
if (q->state) Mcprintf ("\"%s\"", q->state);
Mcprintf ("\n");
Mcprintf (" country: ");
if (q->country) Mcprintf ("\"%s\"", q->country);
Mcprintf ("\n");
Mcprintf (" county: ");
if (q->county) Mcprintf ("\"%s\"", q->county);
Mcprintf ("\n");
Mcprintf (" match: ");
if (q->match) Mcprintf ("\"%s\"", q->match);
Mcprintf ("\n");
Mcprintf (" minlat: %d\n", q->minlat);
Mcprintf (" maxlat: %d\n", q->maxlat);
Mcprintf (" minlon: %d\n", q->minlon);
Mcprintf (" maxlon: %d\n", q->maxlon);
Mcprintf (" valid.bdate: %d\n", q->valid.bdate);
Mcprintf (" valid.edate: %d\n", q->valid.edate);
Mcprintf (" number of datatypes: %d\n", q->n_datatypes);
for (i = 0 ; i < q->n_datatypes ; i++)
{
Mcprintf (" %s\n", q->typenames[i]);
}
#endif
}
--------------------------- stnqry.c -----------------------------------------
-------------------------- stations.h ----------------------------------------
/*
* Copyright(c) 2000, Space Science and Engineering Center, UW-Madison
* Refer to "McIDAS Software Acquisition and Distribution Policies"
* in the file mcidas/data/license.txt
*/
/**** $Id: stations.h,v 1.6 2000/03/28 21:06:06 chadj Tst $ ****/
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#define BOTIME 1970001 /* beginning of time */
#define EOTIME 2100001 /* end of time */
#define MINPRIORITY 0 /* minimum priority */
#define MAXPRIORITY 0 /* maximum priority */
typedef struct _DATE {
int bdate; /* beginning date */
int edate; /* ending date */
} DATE;
/* The definition of a station */
typedef struct _STATION {
char *id; /* character ID of station */
char *userid; /* user defined character ID */
int idn; /* WMO block number of station */
char *description; /* verbal description (name) station */
int ARGOS; /* ARGOS ID of station */
int lat; /* latitude of station (hhmmss) */
int lon; /* longitude of station (hhmmss) */
int ele; /* elevation of station (m) */
int uplat; /* 2nd latitude of station (hhmmss) */
int uplon; /* 2nd longitude of station (hhmmss) */
int upele; /* 2nd elevation of station (m) */
DATE valid; /* valid dates for this station */
char *state; /* PO of station for this station */
char *country; /* PO of country for this station */
char *county; /* name of county of station */
int WFO_zone; /* WFO_zone number of station */
char *WSFO_office; /* ID of WSFO office of station */
char *continent; /* name of continent station resides */
int GMT_offset; /* offset from GMT for this station */
int n_datatypes; /* number datatypes of this station */
char **typenames; /* name of datatypes of this station */
int n_comments; /* number comments of this station */
char **comments; /* comments of this station */
unsigned long classification; /* classification of this station */
int priority; /* plotting priority of this station */
} STATION;
/* The definition of a query */
typedef struct _STATION_QRY {
char **id; /* character ID */
int n_id; /* number of character IDs */
char **userid; /* user defined character ID */
int n_userid; /* nubmer of user IDs */
int *idn; /* WMO block number */
int n_idn; /* number of WMO block numbers */
char *match; /* string to match description */
int minlat; /* minimum lattitude (hhmmss) */
int maxlat; /* maximum lattitude (hhmmss) */
int minlon; /* minimum longitude (hhhmmss) */
int maxlon; /* maximum longitude (hhhmmss) */
DATE valid; /* valid dates */
char *state; /* PO of state */
char *country; /* PO of country */
char *county; /* name of county */
int n_datatypes; /* number of data types */
char **typenames; /* list of data type names */
int priority; /* priority number */
} STATION_QRY;
/*
* Define our Fortran structs. These are the structures filled by the
* Fortran jacket routines which are written in C. The common blocks for these
* structures are defined in stations.inc. The structures themselves are
* instantiated as a static global in stnqry.c. To get at the variables in these
* structures a Fortran program must include stations.inc and then access the
* fields in each of the structs below as variables in the program. Fields
* from the F_STATION struct are prepended with "s_", and fields from the
* F_STATION_QRY struct are prepended with "q_". (station vs. query fields)
*
* Because Fortran requires us to specify fixed lengths for characters, we need
* to set some constants
*/
#define F_IDLEN 12
#define F_COMLEN 80
#define F_TYPELEN 16
#define F_NAMELEN 80
#define F_MAXTYPES 64
#define F_MAXCOMMENTS 24
#define F_COMMENTLEN 80
#define F_STATELEN 4
#define F_COUNTRYLEN 4
#define F_COUNTYLEN 36
#define F_WSFOLEN 12
#define F_CONTLEN 24
typedef struct _F_STATION {
char s_id[F_IDLEN];
char s_userid[F_IDLEN];
Fint s_idn;
char s_desc[F_NAMELEN];
Fint s_argos;
Fint s_lat;
Fint s_lon;
Fint s_ele;
Fint s_uplat;
Fint s_uplon;
Fint s_upele;
Fint s_bdate;
Fint s_edate;
char s_state[F_STATELEN];
char s_country[F_COUNTRYLEN];
char s_county[F_COUNTYLEN];
Fint s_wfo_zone;
char s_wsfo_office[F_WSFOLEN];
char s_continent[F_CONTLEN];
Fint s_gmt_offset;
Fint s_n_datatypes;
char s_typenames[F_MAXTYPES][F_TYPELEN];
Fint s_n_comments;
char s_comments[F_MAXCOMMENTS][F_COMMENTLEN];
Fint s_classification;
Fint s_priority;
} F_STATION;
typedef struct _F_STATION_QRY {
char q_id[F_IDLEN];
char q_userid[F_IDLEN];
Fint q_idn;
char q_match[F_NAMELEN];
Fint q_minlat;
Fint q_maxlat;
Fint q_minlon;
Fint q_maxlon;
Fint q_mindate;
Fint q_maxdate;
char q_state[F_STATELEN];
char q_country[F_COUNTRYLEN];
char q_county[F_COUNTYLEN];
Fint q_n_datatypes;
char q_typenames[F_MAXTYPES][F_TYPELEN];
Fint q_priority;
} F_STATION_QRY;
typedef struct _STNTYPESINDEX {
int *n_list;
int **stn_list;
} STNTYPESINDEX;
/* structures into the binary file */
/* <<<<< UPC mod 20000710 - change long to Fint4 as binary file values
are all 4-byte quantities >>>>> */
typedef Fint4 OFFSET;
typedef struct _STNHEADER {
int version;
int n_stations;
int n_types;
OFFSET types_blk;
OFFSET sizes_blk;
OFFSET data_offset_blk;
OFFSET index_info_blk;
} STNHEADER;
typedef struct _STNTYPES {
int n_types;
char **names;
} STNTYPESBLK;
typedef struct _STNSIZES {
int id;
int idn;
int argos;
int lat;
int lon;
int ele;
int uplat;
int uplon;
int upele;
int state;
int country;
int county;
int typename;
int description;
int date;
int comment;
} STNSIZES;
typedef struct _STNDATAOFFSET {
OFFSET id;
OFFSET idn;
OFFSET argos;
OFFSET lat;
OFFSET lon;
OFFSET ele;
OFFSET uplat;
OFFSET uplon;
OFFSET upele;
OFFSET state;
OFFSET country;
OFFSET county;
OFFSET description;
OFFSET valid_date;
OFFSET types;
OFFSET n_types;
OFFSET comments;
OFFSET n_comments;
} STNDATAOFFSET;
typedef struct _STNINDEXHEADER {
OFFSET type_index_offset;
} STNINDEXHEADER;
/* user callable prototypes */
int M0STNSetCoreFile (const char *file);
int M0STNSetSiteFile (const char *file);
int M0STNSetUserFile (const char *file);
int McSTNGetDatatypes (char ***names, int *num);
int McSTNOpenQuery (STATION_QRY *q_info);
int McSTNGetNumStations (int handle);
STATION * McSTNGetNextStation (int handle);
int McSTNCloseQuery (int handle);
int McSTNSetQueryDefaults (STATION_QRY *query);
int McSTNQueryAddID (STATION_QRY *query, char *id);
int McSTNQueryAddIDN (STATION_QRY *query, int idn);
Fint mcstnopenquery_ (void);
Fint mcstnsetquerydefaults_ (void);
Fint mcstnclosequery_ (Fint *handle);
Fint mcstngetnextstation_ (Fint *handle);
Fint mcstngetnumstations_ (Fint *handle);
Fint idinfo_ (const char *id, Fint *idn, Fint *f5or6,
Fint *ewflg, Fint *llwflg, Fint *lat,
Fint *lon, Fint *state, Fint *country,
Fint *ele, FsLen id_len);
-------------------------- stations.h ----------------------------------------
Tom