/* * $Id: inner.c,v 1.12 1996/06/13 12:30:23 jgofs Exp jgofs $ * Currently locked by $Locker: jgofs $ (not locked if blank) * (Time in GMT, EST=GMT-5:00 * $Log: inner.c,v $ * Revision 1.12 1996/06/13 12:30:23 jgofs * For some reason, can't rely upon PATH_INFO environment variable * to determine what level you're at in inner.c. Instead, have to * look at calling sequence of ioreadrec_ and iocommout_ to * determine what comments are valid. Put in boolean flags to * mark this. Also, changed comment from being arrays of * static character arrays into dynamically allocated arrays. * * Revision 1.11 1996/06/12 16:42:41 jgofs * Changed io, now all variables are stored internally as strings. * Has made all html links seem to work. Also, was using incorrect * netcdf varid when asking for level 1 values. Duhhh... * Only thing that doesn't seem to work is comments thru the web. * * Revision 1.10 1996/06/12 13:42:07 jgofs * Now handles some of the html queries correctly. Problem was * that some of the arguments passed into ioopen_ thru "s" * aren't necessarily all valid variable names. Some might be * projections. Have realized that level 1 comments cannot be * grabbed until we enter level 1. Html queries on depth * still don't work. * * Revision 1.9 1996/06/12 11:43:07 jgofs * Now all comments are forced to be null terminated. Still * unsure as to why html stuff is weird. Has something to do * with outer:test subroutine, though. * * Revision 1.8 1996/06/11 13:17:01 jgofs * Valid variables were not being marked correctly as so. * Only things not working are comments in html and certain * QUERY_STRINGs, such as mooring, depth, etc. Weird... * * Revision 1.7 1996/06/10 12:19:53 jgofs * Not sure exactly why ncattget wasn't working for min and max * values before. All I did to fix it was to delete the offending * line and retype it in. Perhaps there was a control character * embedded in there? Actually, it was just the min attribute that * was causing problems... * * Revision 1.6 1996/06/03 13:25:04 jgofs * Can retrieve units attribute ( level 1 comment ) * but cannot seem to get min and max extents... * * Revision 1.5 1996/06/03 12:51:26 jgofs * something weird, need to recheck out 1.4 * * Revision 1.4 1996/05/31 14:24:51 jgofs * Level 0 and level 1 comments almost done. Only thing left * is to get the unit measurements for the particular variable. * * Revision 1.3 1996/05/30 16:53:41 jgofs * The command line * gom2 /usr/users/jgofs/data/gom_moor/hourly-vane.hdr lat lon * * produces good level 0 output. Need to get level 1 comments, * level 1 ioreadrec implemented. * * Revision 1.2 1996/05/30 13:43:22 jgofs * Actually runs with arguments * /usr/users/jgofs/data/gom_moor/hourly-vane.hdr lat lon * * Time to implement variable reads. * * Revision 1.1 1996/05/29 20:24:42 jgofs * Initial revision * * */ /* * If this code looks bad in your editor, maybe you should * look at it in vi with these settings... * These come from the .exrc file used in the original * source code directory that this file was written in. set nu set autoindent set tabstop=4 set shiftwidth=4 set showmatch map b :w :!make * */ #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #include #include #include #include #include "netcdf.h" /* * Local prototypes not defined in outer.c */ void setup_level_zero_comments ( ); void setup_level_one_comments ( ); void setup_variables ( int *nparams, char *param_list[] ); /* * Local structure defs. */ #include "gom_object_def.h"; #define MAX_LINE_LENGTH MAX_NC_NAME #define JGOFS_SUCCESS 1 #define JGOFS_FAILURE 0 /* * GLOBAL VARIABLES * ================ */ /* * This is the jgofs object. */ static Gom_Obj gom_obj; /* * Listing of level 0, some level 1 variable names. */ char *level_0_varnames[8] = { "mooring", "g_start_date", "g_stop_date", "lat", "lon", "depth", "j_start_date", "j_stop_date" }; char *level_1_varnames[2] = { "time", "time2" }; /* * Placeholder for path of header file. */ char pathname[MAX_LINE_LENGTH]; /* * EXTERNAL VARIABLES * ================== */ /* * This setting disables error messages and fatal errors, * allows us to recover gracefully. */ extern int ncopts; /* * ioopen_ * * Open the data set at the topmost level. * * Parameters * s: parameter array, first element has file name. It is CRUCIAL that * this array contain ALL of the variables that we want to project. * The default is NO variables, so one can't just invoke the method * on the header file and expect to see data... * nparams: points to number of parameters in s * total: total number of variables * * Return value: ID number of the highest level, NOT the * number of levels. */ int ioopen_ ( char *s[], int *nparams, int *ntotal ) { Gom_Obj *obj = &gom_obj; /* * need a character buffer for various things */ char buffer[500]; /* * Used to get the pathname. */ char *tok; /* * We want neither fatal errors nor error messages * from netcdf functions. */ ncopts = 0; /* * Need to grab pathname off of header filename. * This is necessary in order to find the netcdf * files later. */ strcpy ( pathname, s[0] ); if ((tok = strrchr ( pathname, '/' )) != NULL ) *(tok+1) = '\0'; else pathname[0] = '\0'; /* * Open the header file. */ if ( (gom_obj.header_fp = fopen ( s[0], "r" )) == NULL ) { fprintf ( stderr, "Could not open %s\n", s[0] ); exit ( EXIT_FAILURE ); } setup_level_zero_comments(); gom_obj.level_0_comments_valid = TRUE; setup_variables ( nparams, s ); /* * Read one more line and we'll be properly positioned. */ fgets ( buffer, MAX_LINE_LENGTH, gom_obj.header_fp ); /* * Last thing to do is to zero out the first paramter * and set return parameters. */ *ntotal = gom_obj.num0v + gom_obj.num1v; s[0][0] = '\0'; /* * There are two levels, but it is zero based, so return 1. */ return 1; } /* * iocommout * * Extracts the next comment and puts it in the string str. * * Parameters * str: will contain the comment. * * Return value: 1 if successful, 0 if not */ int iocommout_ ( char *str ) { int *index = &(gom_obj.current_comment); /* * If at level 0, just output level 0 comments. */ if ( gom_obj.level_0_comments_valid ) { if ( gom_obj.current_comment < gom_obj.num_level0_comments ) { strcpy ( str, gom_obj.comment[(*index)++] ); return ( JGOFS_SUCCESS ); } else return ( JGOFS_FAILURE ); } /* * If at level 1, output level 0 AND level 1 comments. */ else { if ( gom_obj.current_comment < gom_obj.num_comments ) { strcpy ( str, gom_obj.comment[(*index)++] ); return ( JGOFS_SUCCESS ); } else return ( JGOFS_FAILURE ); } } /* * ioname_ * * Returns the name of the v(n)th variable. Must be null terminated. * * Parameters * *vn: integer id for a particular jgofs variable * s: where the name is placed */ void ioname_ ( int *vn, char *s ) { sprintf ( s, "%s\0", gom_obj.var[*vn].name ); } /* * iovarlevel_ * * Provides the hierarchical structure of the variable indicated by *vn. * As far as I can tell, there are only 2 levels to a netcdf * file, and the first ones are always the dimensions, which * would be level 0. * * Parameters * *vn: integer id for a particular jgofs variable * * Return value: the level of the indicated jgofs variable */ int iovarlevel_ ( int *vn ) { return ( gom_obj.var[*vn].level ); } /* * ioattrout_ * * Returns the next attribute associated with a particular variable. * * Parameters * *vn: integer id for a particular jgofs variable * *str: string containing the attribute * * Return value: 1 for a successful attribute retrieval, 0 for failure. */ int ioattrout_ ( int *vn, char *str ) { return ( 0 ); } /* * iovalreal_ * * Returns the real number value of the variable whose index is * passed in. * * Parameters * *vn: integer id for a particular jgofs variable * *f: points to real value cast of indicated jgofs variable * */ void iovalreal_ ( int *vn, float *f ) { sscanf ( gom_obj.var[*vn].value, "%f", f ); } /* * iovalstr_ * * Returns character string equivalent of a variable. * * Parameters * *vn: integer id for a particular jgofs variable * *str: string containing the value, null terminated. * */ void iovalstr_ ( int *vn, char *str ) { Gom_Var *var = &gom_obj.var[*vn]; strcpy ( str, gom_obj.var[*vn].value ); } /* * ioreadrec_ * * Actually does the reading of records from the data set. * * Parameters * *level: Integer indicating jgofs level to read at. * * Return value: 1 for a successful read, 0 for failure. * */ int ioreadrec_ ( int *level ) { /* * Need a buffer for reads. */ char buffer[MAX_LINE_LENGTH]; /* * Need buffer for level 0 netcdf filename */ char current_netcdf_filename[MAX_LINE_LENGTH]; /* * Multidimensional index of the variable to be read. */ static long int record_index[4] = {0, 0, 0, 0}; /* * Jgofs id variables. */ int jg_id, /* loop variable */ netcdf_varid, time_id, time2_id; /* For variables "time" and "time2" */ int status; /* Result of netcdf operation. */ long int time1_val, time2_val; double time_val; /* Special values for netcdf time variables. */ int i; float datum; /* * Can't think of any level 1 variables that * aren't floats. This may have to be changed, * though. */ /* * Level 0 read */ if ( *level == 0 ) { if ( fgets ( buffer, MAX_LINE_LENGTH, gom_obj.header_fp ) == NULL ) return JGOFS_FAILURE; /* * first reset all values to null */ for ( i = 0; i < gom_obj.num0v; ++i ) memset ( gom_obj.var[i].value, '\0', strlen(gom_obj.var[i].value) ); sscanf ( buffer, "%s %s %s %s %s %s %s %s %s\n", current_netcdf_filename, gom_obj.var[jg_gregorian_start_date_id].value, gom_obj.var[jg_gregorian_stop_date_id].value, gom_obj.var[jg_julian_start_date_id].value, gom_obj.var[jg_julian_stop_date_id].value, gom_obj.var[jg_mooring_id].value, gom_obj.var[jg_lat_id].value, gom_obj.var[jg_lon_id].value, gom_obj.var[jg_depth_id].value ); /* * Contruct full pathname of current netcdf file. */ strcpy ( gom_obj.ncfilename, pathname ); strcat ( gom_obj.ncfilename, current_netcdf_filename ); /* * Open the netcdf file for subsequent level 1 reads. */ gom_obj.ncid = ncopen ( gom_obj.ncfilename, NC_NOWRITE ); setup_level_one_comments (); /* * ioreadrec was successful */ return JGOFS_SUCCESS; } /* * Level 1 read. */ gom_obj.level_0_comments_valid = FALSE; gom_obj.level_1_comments_valid = TRUE; if ( *level == 1 ) { /* * first reset all values to null */ for ( i = gom_obj.num0v; i < gom_obj.num_vars; ++i ) memset ( gom_obj.var[i].value, '\0', strlen(gom_obj.var[i].value) ); /* * Getting the time information is not general. The time * information is split between the "time" and "time2" * variables. Want to read them both in and combine. * In the combining, we also want to subtract off the * julian day of Jan 1, 1970. */ time_id = ncvarid ( gom_obj.ncid, "time" ); time2_id = ncvarid ( gom_obj.ncid, "time2" ); status = ncvarget1 ( gom_obj.ncid, time_id, record_index, (void *)&time1_val ); status = ncvarget1 ( gom_obj.ncid, time2_id, record_index, (void *)&time2_val ); time_val = (double)time1_val + (double)time2_val/8.64e7 - 2415021.0; sprintf ( gom_obj.var[jg_time_id].value, "%lf", time_val ); /* * Now proceed with the rest of the level 1 variables. */ for ( jg_id = jg_time_id+1; jg_id < gom_obj.num_vars; ++jg_id ) { netcdf_varid = ncvarid ( gom_obj.ncid, gom_obj.var[jg_id].name ); status = ncvarget1 ( gom_obj.ncid, netcdf_varid, record_index, (void *)&datum ); sprintf ( gom_obj.var[jg_id].value, "%f\0", datum ); } /* * If status == -1, then we were unable to retrieve data at * level 1. So we must be done with this level. Get ready * to go back to level 0. */ if ( status == -1 ) { record_index[0] = 0; ncclose ( gom_obj.ncid ); return JGOFS_FAILURE; } else { record_index[0]++; return JGOFS_SUCCESS; } return (JGOFS_FAILURE); } /* * If we're here, must have tried a level 2 read. No such thing... */ return ( JGOFS_FAILURE ); } /* * ioclose_ * * Closes any open files. Yeah right, like anyone cares. */ void ioclose_ () { ncclose ( gom_obj.ncid ); } /* * setup_level_zero_comments * * This helper routine gets all level 0 comments for the object. * These comments are found in the header file. */ void setup_level_zero_comments ( ) { /* * helps dbx to debug */ Gom_Obj *obj = &gom_obj; /* * need a character buffer for various things */ char buffer[MAX_LINE_LENGTH]; /* * Loop variables, indices into arrays. */ int i, last_char_index, comm_index; fgets ( buffer, MAX_LINE_LENGTH, gom_obj.header_fp ); comm_index = 0; gom_obj.num_level0_comments = 0; gom_obj.num_level1_comments = 0; while ( strncmp ( buffer, "File", 4 ) ) { buffer[strlen(buffer)-1] = '\0'; gom_obj.comment[comm_index] = malloc ( (strlen(buffer)*2) * sizeof(char)); strcpy ( gom_obj.comment[comm_index++], buffer+2 ); memset ( (void *)buffer, '\0', sizeof(buffer) ); fgets ( buffer, MAX_LINE_LENGTH, gom_obj.header_fp ); } gom_obj.num_level0_comments = comm_index; gom_obj.num_comments = comm_index; /* * Last thing is to make sure that all comments are null * terminated and have no newline characters. Do this by * looking at last character in each comment. If it's a * newline, replace it with null char. Otherwise put * null char in after last char. */ for ( i = 0; i < gom_obj.num_level0_comments; ++i ) { last_char_index = strlen ( gom_obj.comment[i] ) - 1; if ( gom_obj.comment[i][last_char_index] == '\n' ) gom_obj.comment[i][last_char_index] = '\0'; else gom_obj.comment[i][last_char_index+1] = '\0'; } } /* * setup_level_one_comments * * This helper routine gets all level 1 comments for the object. */ void setup_level_one_comments ( ) { /* * helps dbx to debug */ Gom_Obj *obj = &gom_obj; /* * need a character buffer for various things */ char buffer[MAX_LINE_LENGTH]; /* * Loop variables, indices into arrays. */ int i, last_char_index, comm_index = gom_obj.num_level0_comments; /* * Used to read in different netcdf comment types. */ int byte_val; char str_val[MAX_LINE_LENGTH]; int short_val; long int long_val; float float_val; double double_val; /* * jgofs and netcdf variable id numbers */ int jg_varid, netcdf_varid; /* * Return values from netcdf operations. */ int status, status_min, status_max, num_global_atts, attribute_length; float min_val, max_val; char attribute_name[MAX_LINE_LENGTH]; nc_type data_type; /* * Get the number of global attributes * which make up some of the level 1 comments. */ status = ncinquire ( gom_obj.ncid, (int *)NULL, (int *)NULL, &num_global_atts, (int *)NULL ); for ( i = 0; i < num_global_atts; ++i ) { /* * Get name of attribute */ status = ncattname ( gom_obj.ncid, NC_GLOBAL, i, attribute_name ); if ( status == -1 ) { fprintf ( stderr, "get_comments: ncattname failed\n" ); exit ( EXIT_FAILURE ); } /* * Get data type and length. */ status = ncattinq ( gom_obj.ncid, NC_GLOBAL, attribute_name, &data_type, &attribute_length ); if ( status == -1 ) { fprintf ( stderr, "get_comments: ncattinq failed\n" ); exit ( EXIT_FAILURE ); } gom_obj.comment[comm_index] = malloc ( MAX_LINE_LENGTH * sizeof(char)); /* * Now get the actual attribute ( level 1 comment ). */ switch ( data_type ) { case NC_BYTE: status = ncattget ( gom_obj.ncid, NC_GLOBAL, attribute_name, (void *)&byte_val ); if ( status == -1 ) { fprintf ( stderr, "get_comments: ncattget failed" ); exit ( EXIT_FAILURE ); } sprintf ( gom_obj.comment[comm_index++], "%s = %#X", attribute_name, byte_val ); break; /* * character case is slightly different. Must end with * a null char, otherwise it looks weird. */ case NC_CHAR: status = ncattget ( gom_obj.ncid, NC_GLOBAL, attribute_name, (void *)str_val ); if ( status == -1 ) { fprintf ( stderr, "get_comments: ncattget failed" ); exit ( EXIT_FAILURE ); } str_val[strlen(str_val)] = '\0'; sprintf ( gom_obj.comment[comm_index++], "%s = %s", attribute_name, str_val ); break; case NC_SHORT: status = ncattget ( gom_obj.ncid, NC_GLOBAL, attribute_name, (void *)&short_val ); if ( status == -1 ) { fprintf ( stderr, "get_comments: ncattget failed" ); exit ( EXIT_FAILURE ); } sprintf ( gom_obj.comment[comm_index++], "%s = %i", attribute_name, short_val ); break; case NC_LONG: status = ncattget ( gom_obj.ncid, NC_GLOBAL, attribute_name, (void *)&long_val ); if ( status == -1 ) { fprintf ( stderr, "get_comments: ncattget failed" ); exit ( EXIT_FAILURE ); } sprintf ( gom_obj.comment[comm_index++], "%s = %li", attribute_name, long_val ); break; case NC_FLOAT: status = ncattget ( gom_obj.ncid, NC_GLOBAL, attribute_name, (void *)&float_val ); if ( status == -1 ) { fprintf ( stderr, "get_comments: ncattget failed" ); exit ( EXIT_FAILURE ); } sprintf ( gom_obj.comment[comm_index++], "%s = %f", attribute_name, float_val ); break; case NC_DOUBLE: status = ncattget ( gom_obj.ncid, NC_GLOBAL, attribute_name, (void *)&double_val ); if ( status == -1 ) { fprintf ( stderr, "get_comments: ncattget failed" ); exit ( EXIT_FAILURE ); } sprintf ( gom_obj.comment[comm_index++], "%s = %lf", attribute_name, double_val ); break; default: fprintf ( stderr, "Unknown netcdf type encountered in get_comments\n" ); exit ( EXIT_FAILURE ); } } /* * Now get the particular comments. * This means that we want units of measurement for all * level 1 variables, and extents for all level 1 variables * except for time. * */ for ( jg_varid = jg_time_id; jg_varid < gom_obj.num_vars; ++jg_varid ) { /* * Get the name of the variable. */ netcdf_varid = ncvarid ( gom_obj.ncid, gom_obj.var[jg_varid].name ); if ( netcdf_varid == -1 ) { fprintf ( stderr, "get_comments: ncvarid failed\n" ); exit ( EXIT_FAILURE ); } /* * get the units attribute */ memset ( (void *)buffer, '\0', sizeof(buffer) ); status = ncattget ( gom_obj.ncid, netcdf_varid, "units", (void *)buffer ); if ( status == -1 ) { fprintf ( stderr, "get_comments:ncattget failed\n" ); exit ( EXIT_FAILURE ); } else { gom_obj.comment[comm_index] = malloc ( MAX_LINE_LENGTH * sizeof(char)); sprintf ( gom_obj.comment[comm_index++], "%s units of measurement: %s\0", gom_obj.var[jg_varid].name, buffer ); } /* * get the measurement extents */ status_min = ncattinq ( gom_obj.ncid, netcdf_varid, "minimum", &data_type, &attribute_length ); status_max = ncattinq ( gom_obj.ncid, netcdf_varid, "maximum", &data_type, &attribute_length ); if ( (status_min != -1) && (status_max != -1) ) { status = ncattget ( gom_obj.ncid, netcdf_varid, "maximum", (void *)&max_val ); if (status == -1 ) { fprintf ( stderr, "get_comments: ncattget max failed\n" ); exit ( EXIT_FAILURE ); } status = ncattget ( gom_obj.ncid, netcdf_varid, "minimum", (void *)&min_val ); if (status == -1 ) { fprintf ( stderr, "get_comments: ncattget min failed\n" ); exit ( EXIT_FAILURE ); } else { gom_obj.comment[comm_index] = malloc ( MAX_LINE_LENGTH * sizeof(char)); sprintf ( gom_obj.comment[comm_index++], "%s range: [%f, %f]\0", gom_obj.var[jg_varid].name, min_val, max_val ); } } } /* * Now finalize the comment numbers. */ gom_obj.num_comments = comm_index; gom_obj.num_level1_comments = gom_obj.num_comments - gom_obj.num_level0_comments; gom_obj.current_comment = 0; /* * Last thing is to make sure that all comments are null * terminated and have no newline characters. Do this by * looking at last character in each comment. If it's a * newline, replace it with null char. Otherwise put * null char in after last char. */ for ( i = 0; i < gom_obj.num_comments; ++i ) { last_char_index = strlen ( gom_obj.comment[i] ) - 1; if ( gom_obj.comment[i][last_char_index] == '\n' ) gom_obj.comment[i][last_char_index] = '\0'; else gom_obj.comment[i][last_char_index+1] = '\0'; } } /* * */ void setup_variables ( int *nparams, char *arg_list[] ) { /* * need a character buffer for various things */ char buffer[MAX_LINE_LENGTH]; /* * Netcdf file to grab global comments from. */ char netcdf_filename[MAX_LINE_LENGTH]; char full_pathname[MAX_LINE_LENGTH]; int ncid; /* * Need to peek ahead in header file to grab the first * netcdf file. Therefore, need to keep track of * original position in header file. */ int orig_pos; /* * Pointer to a jgofs variable in object. */ Gom_Var *var; /* * Indices, loop varibles. */ int i, j, index; /* * Used to determine whether or not something in the * argument list is a valid variable or not. If not, * that doesn't necessarily imply an error... */ int keep_it, varid; /* * Define the level 0 variables for all objects, even if * they are not necessarily present... * These particular variables are present in the header * files, and must be at least defined. Not necessary * to use them during testing... */ gom_obj.num0v = 8; var = gom_obj.var; for ( i = 0; i < gom_obj.num0v; ++i ) { strcpy ( var[i].name, level_0_varnames[i] ); var[i].name[ strlen(level_0_varnames[i]) ] = '\0'; var[i].level = 0; /* * Determine whether or not the variable is valid or not. * If it is, it is one of the parameters in s. */ var[i].valid = 0; for ( j = 1; j < (*nparams); ++j ) if ( !strcmp ( var[i].name, arg_list[j] ) ) var[i].valid = 1; } gom_obj.var[jg_mooring_id].data_type = NC_LONG; gom_obj.var[jg_gregorian_start_date_id].data_type = NC_SHORT; gom_obj.var[jg_gregorian_stop_date_id].data_type = NC_SHORT; gom_obj.var[jg_lat_id].data_type = NC_FLOAT; gom_obj.var[jg_lon_id].data_type = NC_FLOAT; gom_obj.var[jg_depth_id].data_type = NC_FLOAT; gom_obj.var[jg_julian_start_date_id].data_type = NC_DOUBLE; gom_obj.var[jg_julian_stop_date_id].data_type = NC_DOUBLE; /* * Now go thru the paramter list, looking for any * level 1 variables. * * First thing to do is peek ahead at the first netcdf * file in the header file. Need to do this in order * to compare variable names in the arg_list to * existing variable names in the netcdf files. The * assumption is that if a variable name is not present * in the first netcdf file, it won't be present in * any of the other netcdf files. */ orig_pos = ftell ( gom_obj.header_fp ); rewind ( gom_obj.header_fp ); fgets ( buffer, MAX_LINE_LENGTH, gom_obj.header_fp ); while ( strncmp ( buffer, "File", 4 ) ) fgets ( buffer, MAX_LINE_LENGTH, gom_obj.header_fp ); fgets ( buffer, MAX_LINE_LENGTH, gom_obj.header_fp ); fgets ( buffer, MAX_LINE_LENGTH, gom_obj.header_fp ); sscanf ( buffer, "%s", netcdf_filename ); fseek ( gom_obj.header_fp, orig_pos, SEEK_SET ); /* * Construct full pathname. */ strcpy ( full_pathname, pathname ); strcat ( full_pathname, netcdf_filename ); ncid = ncopen ( full_pathname, NC_NOWRITE ); gom_obj.num1v = 0; index = gom_obj.num0v; var = gom_obj.var; for ( j = 1; j < *nparams; ++j ) { /* * make sure it's not a level 0 variable already */ keep_it = TRUE; for ( i = 0; i < gom_obj.num0v; ++i ) { if ( !strcmp( var[i].name, arg_list[j] ) ) keep_it = FALSE; } /* * Now make sure the variable name exits in the * first netcdf file. */ if ( keep_it ) { varid = ncvarid ( ncid, arg_list[j] ); if ( varid == -1 ) keep_it = FALSE; } if ( keep_it ) { strcpy ( var[index].name, arg_list[j] ); var[index].name[strlen(arg_list[j])] = '\0'; var[index].level = 1; var[index].data_type = NC_FLOAT; var[index].valid = TRUE; index++; } } ncclose ( ncid ); gom_obj.num1v = index - gom_obj.num0v; gom_obj.var[jg_time_id].data_type = NC_DOUBLE; gom_obj.num_vars = gom_obj.num0v + gom_obj.num1v; }