/*--------------------------------------------------------------------
 *	$Id: mgd77manage.c,v 1.60 2006/04/10 05:47:30 pwessel Exp $
 *
 * mgd77manage is used to (1) remove data columns from mgd77+ files
 * or (2) add a new data column to mgd77+ files.  Data can be added
 * from data tables, created from reference field formulas, or by
 * sampling grids along track.  Data from tables may be numbers or
 * text strings.
 *
 *    Copyright (c) 2005-2006 by P. Wessel
 *    See README file for copying and redistribution conditions.
 *--------------------------------------------------------------------*/
/*
 *
 * Author:	Paul Wessel
 * Date:	18-OCT-2005
 * Version:	1.0
 *
 */
 
#include "mgd77.h"

#define N_PAR		6
#define COL_SCALE	0
#define COL_OFFSET	1
#define IMG_SPACING	2
#define IMG_SCALE	3
#define IMG_MODE	4
#define COL_TYPE	5

#define ADD_IGRF	2
#define ADD_CARTER	3
#define ADD_GRAV	4

#define N_E77_MODES	6
#define E77_HEADER	0
#define E77_TREND	1
#define E77_NAV		2
#define E77_VALUES	3
#define E77_SLOPES	4
#define E77_GRID	5

#define set_bit(k) (1 << (k))

int main (int argc, char **argv)
{
	int i, j, k = 0, ii, jj, n = 0, argno, n_cruises = 0, n_paths = 0, ij, mx = 0, my, pos, column, result;
	int width, n_delete = 0, GF_version = MGD77_NOT_SET, n_expected_fields, n_fields, n_sampled = 0;
	int kind = GMT_IS_FLOAT, dims[2], set, var_id, n_dims = 0, dist_flag = 2, n_bad, e77_mode[N_E77_MODES];
	
	size_t n_alloc = GMT_CHUNK, start[2] = {0, 0}, count[2] = {0, 0};
	
	time_t now;
	
	nc_type c_nc_type;
	
	BOOLEAN got_c = FALSE, got_a = FALSE, got_d = FALSE, got_g = FALSE, got_i = FALSE, got_n = FALSE, got_t = FALSE;
	BOOLEAN error = FALSE, bilinear = FALSE, replace = FALSE, delete = FALSE, interpolate = FALSE, transform;
	BOOLEAN strings = FALSE, track_decode, got_grid, got_table, two_cols = FALSE, constant, ok_to_read = TRUE, got_e = FALSE;
	
	char line[BUFSIZ], file[BUFSIZ], *d_list = CNULL, p[BUFSIZ], history[BUFSIZ], c_size = 0, **list;
	char c_abbrev[GMT_TEXT_LEN], c_units[GMT_TEXT_LEN], c_name[MGD77_COL_NAME_LEN], c_comment[MGD77_COL_COMMENT_LEN];
	char no_char = '9', not_given[GMT_TEXT_LEN], word[BUFSIZ], **tmp_string = VNULL, *text = VNULL, d_unit[2];
	signed char LEN = 0, OLDLEN = 0;
	
	short int *i2;
	
	float *f = VNULL;

	double threshold = 1.0, i_dx = 0, i_dy = 0, x, y, match_value, single_val, dist_scale = 1.0;
	double parameters[N_PAR], *xtmp, *coldnt = VNULL, *colvalue = VNULL, *in ,limits[2];

	struct MGD77_CONTROL In;
	struct MGD77_DATASET *D;
	struct GRD_HEADER grd;
	struct GMT_EDGEINFO edgeinfo;
	struct GMT_BCR bcr;
	struct GMT_gcal cal;
	struct MGD77_CARTER Carter;
	
	FILE *fp, *fp_err;

	int decode_A_options (int mode, char *line, char *file, double parameters[]);
	int decode_I_options (char *line, char *abbrev, char *name, char *units, char *size, char *comment, double parameters[]);
	int skip_if_missing (char *name, char *file, struct MGD77_CONTROL *F, struct MGD77_DATASET *D);
	int got_default_answer (char *line, char *answer);

	argc = GMT_begin (argc, argv);		/* Initialize GMT Machinery */
	
	GMT_boundcond_init (&edgeinfo);
	parameters[COL_SCALE]   = 1.0;	/* Output column scaling */
	parameters[COL_OFFSET]  = 0.0;	/* Output column offset */
	parameters[IMG_SPACING] = 0.0;	/* IMG data minute spacing */
	parameters[IMG_SCALE]   = 1.0;	/* IMG data scaling */
	parameters[IMG_MODE]    = 0.0;	/* IMG data mode */
	parameters[COL_TYPE]    = 0;	/* netCDF type */
	GMT_pad[0] = GMT_pad[1] = GMT_pad[2] = GMT_pad[3] = 2;
	d_unit[0] = d_unit[1] = '\0';
	memset ((void *)e77_mode, 0, (size_t)(N_E77_MODES * sizeof (int)));
	/* Default e77_mode will apply header and fix corrections if prefix is Y and set all data bits */
	
	MGD77_Init (&In, TRUE);			/* Initialize MGD77 Machinery */

	for (i = 1; !error && i < argc; i++) {	/* Process input options */
		k = 0;
		if (argv[i][0] == '-') {
			switch(argv[i][1]) {
			
				case 'V':
				case '\0':
					error += GMT_parse_common_options (argv[i], NULL, NULL, NULL, NULL);
					break;
					
				case 'A':	/* Adding a new column */
					k = 2;
					if (argv[i][k] == '+') {
						replace = TRUE;
						k++;
					}
					switch (argv[i][k]) {
						case 'a':	/* Plain column data file of exact same # of records */
							got_a = TRUE;
							error += decode_A_options (0, &argv[i][k+1], file, parameters);
							break;
						case 'c':	/* Add reference field or correction term */
							got_c = TRUE;
							error += decode_A_options (0, &argv[i][k+1], file, parameters);
							break;
						case 'D':	/* dist,val data file - interpolate to get values at all records */
							interpolate = TRUE;
						case 'd':	/* dist,val data file - only update records with matching distances */
							got_d = TRUE;
							error += decode_A_options (0, &argv[i][k+1], file, parameters);
							break;
						case 'e':	/* Plain E77 error flag file from mgd77sniffer */
							got_e = TRUE;
							while (argv[i][++k]) {
								switch (argv[i][k]) {
									case 'h':	/* Ignore all header recommendations regardless of Y/N prefix */
										e77_mode[E77_HEADER] = -1;
										break;
									case 'H':	/* Apply all header recommendations regardless of Y/N prefix */
										e77_mode[E77_HEADER] = +1;
										break;
									case 'f':	/* Ignore all systematic trend recommendations regardless of Y/N prefix */
										e77_mode[E77_TREND] = -1;
										break;
									case 'F':	/* Apply all systematic trend recommendations regardless of Y/N prefix */
										e77_mode[E77_TREND] = +1;
										break;
									case 'n':	/* Ignore all NAV flags */
										e77_mode[E77_NAV] = -1;
										break;
									case 'v':	/* Ignore all VALUE flags */
										e77_mode[E77_VALUES] = -1;
										break;
									case 's':	/* Ignore all SLOPE flags */
										e77_mode[E77_SLOPES] = -1;
										break;
									case 'g':	/* Ignore all GRID flags */
										e77_mode[E77_GRID] = -1;
										break;
									default:
										fprintf (stderr, "%s: ERROR: -A[+]e modifiers must be combination of H|h,F|f,nvsg\n", GMT_program);
										break;
								}
							}
							break;
						case 'g':	/* Sample along track from this GMT grid file */
							got_g = TRUE;
							error += decode_A_options (0, &argv[i][k+1], file, parameters);
							break;
						case 'i':	/* Sample along track from this *.img grid file */
							got_i = TRUE;
							error += decode_A_options (1, &argv[i][k+1], file, parameters);
							break;
						case 'n':	/* recno,val data file - only update records with matching rec number */
							got_n = TRUE;
							error += decode_A_options (0, &argv[i][k+1], file, parameters);
							break;
						case 'T':	/* abstime,val data file - interpolate to get values at all records */
							interpolate = TRUE;
						case 't':	/* abstime,val data file - only update records with matching times */
							got_t = TRUE;
							kind = GMT_IS_ABSTIME;
							error += decode_A_options (0, &argv[i][k+1], file, parameters);
							break;
						default:
							fprintf (stderr, "%s: ERROR: -A modifier must be a|c|d|D|e|g|i|n|t|T\n", GMT_program);
							error++;
							break;
					}
					break;

				case 'C':	/* Distance calcuation method */
					if (argv[i][2] == 'f') dist_flag = 1;
					if (argv[i][2] == 'g') dist_flag = 2;
					if (argv[i][2] == 'e') dist_flag = 3;
					if (dist_flag < 1 || dist_flag > 3) {
						fprintf(stderr, "%s: ERROR -C: Flag must be f, g, or e\n", GMT_program);
						error++;
					}
					break;
				case 'D':	/* Columns to delete */
					d_list = &argv[i][2];
					delete = TRUE;
					
				case 'E':	/* character to generate no-string value */
					no_char = argv[i][2];
					break;

				case 'I':	/* Column attribute information */
					error += decode_I_options (&argv[i][2], c_abbrev, c_name, c_units, &c_size, c_comment, parameters);
					break;
					
				case 'N':	/* Set distance units */
					d_unit[0] = argv[i][2];	d_unit[1] = 0;
					if (!strchr ("ekmn", (int)d_unit[0])) {
						fprintf(stderr, "%s: ERROR -N: Unit must be e, k, m, or n\n", GMT_program);
						error++;
					}
					break;
					
				case 'Q':	/* bilinear interpolation parameters */
					bilinear = TRUE;
					threshold = (argv[i][2]) ? atof (&argv[i][2]) : 1.0;
					break;

				default:		/* Options not recognized */
					error = TRUE;
					break;
			}
		}
		else
			n_cruises++;
	}
	
	/* Check that the options selected are mutually consistent */
	
	if (GMT_give_synopsis_and_exit || argc == 1) {	/* Display usage */
		fprintf(stderr,"mgd77manage %s - Manage the content of MGD77+ files\n\n", MGD77_VERSION);
		fprintf(stderr,"usage: mgd77manage <cruise(s)> [-A[+]a|c|d|D|e|g|i|n|t|T<info>] [-Cf|g|e] [-Dname1,name2,...]\n");
		fprintf(stderr,"\t[-E<no_char>] [-I<abbrev>/<name>/<units>/<size>/<scale>/<offset>/\"comment\"]\n");
		fprintf(stderr,"\t[-Ne|k|m|n[+|-]] [-Q[<value>]] [-V] [%s]\n\n", GMT_bi_OPT);
         
		if (GMT_give_synopsis_and_exit) exit (EXIT_FAILURE);
              
		fprintf (stderr, "\t<cruises> is one or more MGD77+ legnames, e.g., 01010083.\n");
		fprintf (stderr, "\n\tOPTIONS:\n\n");
		fprintf (stderr, "\t-A Append a new data column to the given files.  The code letters are:\n");
		fprintf (stderr, "\t   +: Optional.  Will overwrite an existing column with same name with new data.\n");
		fprintf (stderr, "\t   [Default will refuse if an existing column has the same abbreviation as the new data].\n");
		fprintf (stderr, "\t   a: Give filename with a new column to add.  We expect a single-coloumn file\n");
		fprintf (stderr, "\t      with the same number of records as the MGD77 file.  Only one cruise can be set.\n");
		fprintf (stderr, "\t      If filename is - we read from stdin.\n");
		fprintf (stderr, "\t   c: Create a new column to be calculated from existing columns.  Add code:\n");
		fprintf (stderr, "\t        m = IGRF total field, c = Carter correction, g = IGF (\"normal gravity\")\n");
		fprintf (stderr, "\t        For g, optionally append 1-4 to select the gravity formula to use:\n");
		fprintf (stderr, "\t        1 = Heiskanen 1924, 2 = International 1930, 3 = IGF1967, 4 = IGF1980.\n");
		fprintf (stderr, "\t        [Default uses formula specified in the MGD77 header, or 4 if not valid]\n");
		fprintf (stderr, "\t   d: Give filename with (dist [see -N], data) for a new column.  We expect a two-coloumn file\n");
		fprintf (stderr, "\t      with distances (in km) in first column and data values in 2nd.  Only one cruise can be set.\n");
		fprintf (stderr, "\t      If filename is - we read from stdin.  Only records with mathcing distance will have data assigned.\n");
		fprintf (stderr, "\t   D: Same as d but we interpolate between the dist,data pairs to fill in all data records.\n");
		fprintf (stderr, "\t   e: Ingest MGD77 error/correction information (e77) produced by mgd77sniffer.  We will look\n");
		fprintf (stderr, "\t      for the <cruise>.e77 file in the current directory or in MGD77_HOME/E77 [%s/E77]\n", In.MGD77_HOME);
		fprintf (stderr, "\t      By default we will apply recommended header (h) and systematic fixes (f) and set all data bit flags.\n");
		fprintf (stderr, "\t      Append a combination of these flags to change the default accordingly:\n");
		fprintf (stderr, "\t        h = Ignore all header recommendations\n");
		fprintf (stderr, "\t        H = Apply all header recommendations regardless of Y/N prefix\n");
		fprintf (stderr, "\t        f = Ignore all systematic fixes recommendations\n");
		fprintf (stderr, "\t        F = Apply all ystematic fixes recommendations regardless of Y/N prefix\n");
		fprintf (stderr, "\t        n = Ignore data record bitflags pertaining to navigation (time, lon, lat).\n");
		fprintf (stderr, "\t        v = Ignore data record bitflags pertaining to data values.\n");
		fprintf (stderr, "\t        s = Ignore data record bitflags pertaining to data slopes (gradients).\n");
		fprintf (stderr, "\t        g = Ignore data record bitflags pertaining to offsets relative to grids.\n");
		fprintf (stderr, "\t   g: Sample a GMT grid along track. (also see -Q).\n");
		fprintf (stderr, "\t      Append filename of the GMT grid.\n");
		fprintf (stderr, "\t   i: Sample a Sandwell/Smith *.img Mercator grid along track (also see -Q).\n");
		fprintf (stderr, "\t      Append /scale/mode/filename to set the grid's scale, mode, and filename:\n");
		fprintf (stderr, "\t      Give scale (0.1 or 1) to multiply after read, and set mode as follows:\n");
		fprintf (stderr, "\t        0 = img file w/ no constraint code, interpolate to get data at track.\n");
                fprintf (stderr, "\t        1 = img file w/ constraints coded, interpolate to get data at track.\n");
                fprintf (stderr, "\t        2 = img file w/ constraints coded, gets data only at constrained points, NaN elsewhere.\n");
                fprintf (stderr, "\t        3 = img file w/ constraints coded, gets 1 at constraints, 0 elsewhere.\n");
                fprintf (stderr, "\t        For mode 2|3 you may want to consider the -Q<value> setting.\n");
		fprintf (stderr, "\t   n: Give filename with (rec_no, data) for a new column.  We expect a two-coloumn file\n");
		fprintf (stderr, "\t      with record numbers (0 means 1st row) in first column and data values in 2nd.  Only one cruise can be set.\n");
		fprintf (stderr, "\t      If filename is - we read from stdin.  Only records with matching record numbers will have data assigned.\n");
		fprintf (stderr, "\t   t: Give filename with (abstime, data) for a new column.  We expect a two-coloumn file\n");
		fprintf (stderr, "\t      with dateTclock strings in first column and data values in 2nd.  Only one cruise can be set.\n");
		fprintf (stderr, "\t      If filename is - we read from stdin.  Only records with matching times will have data assigned.\n");
		fprintf (stderr, "\t   T: Same as t but we interpolate between the time, data pairs to fill in all data records.\n");
		fprintf (stderr, "\t-C Append code for distance calculation procedure (when -Ad|D is set):\n");
		fprintf (stderr, "\t     f Flat Earth\n");
		fprintf (stderr, "\t     g Great circle [Default]\n");
		fprintf (stderr, "\t     e Ellipsoidal (geodesic) using current GMT ellipsoid\n");
		fprintf (stderr, "\t-D Delete the columns listed from all the cruise data files.\n");
		fprintf (stderr, "\t   The columns are removed before any data are added.  It is not a substitute for -A+.\n");
		fprintf (stderr, "\t   However, sometimes the shape of new data demands the old to be deleted first (you will be told)\n");
		fprintf (stderr, "\t-E Give character used to fill empty/missing string columns [9]\n");
		fprintf (stderr, "\t-I In addition to the file information above, you must also specify column information:\n");
		fprintf (stderr, "\t      abbrev:  Short, abbreviated word, like satfaa (%d char max)\n", MGD77_COL_ABBREV_LEN);
		fprintf (stderr, "\t      name:    Descriptive name, like \"Geosat/ERS-1 Free-air gravity\" (%d char max)\n", MGD77_COL_NAME_LEN);
		fprintf (stderr, "\t      units:   Units for the column (e.g., mGal, gamma, km) (%d char max)\n", MGD77_COL_NAME_LEN);
		fprintf (stderr, "\t      size:    Either t(ext), b(yte), s(hort), f(loat), i(nt), or d(ouble)\n");
		fprintf (stderr, "\t      scale:   Multiply data by this scale before writing to mgd77+ file\n");
		fprintf (stderr, "\t      offset:  Add after scaling before writing to mgd77+ file\n");
		fprintf (stderr, "\t      comment: Any text (in double quotes) for information about column (%d char max)\n", MGD77_COL_COMMENT_LEN);
		fprintf (stderr, "\t      -I is ignored by -Ae\n");
		fprintf (stderr, "\t   Note for text: Interpolation is not allowed, and \"not-a-string\" is created from -E.\n");
		fprintf (stderr, "\t-N Append your choice for distance unit (if -Ad|D are set). Choose among:\n");
		fprintf (stderr, "\t   (e) meter, (k) km, (m) miles, or (n) nautical miles [Default is -Nk]\n");
		fprintf (stderr, "\t    See -C for selecting distance calculation procedure.\n");
		fprintf (stderr, "\t-Q Quick mode, use bilinear rather than bicubic interpolation (requires -Ag|i).\n");
		fprintf (stderr, "\t   Optionally, append <value> in the 0 <= value <= 1 range.\n");
		fprintf (stderr, "\t   [Default = 1 requires all 4 nearest nodes to be non-NaN.], <value> = 0.5\n");
		fprintf (stderr, "\t   will interpolate about 1/2 way from a non-NaN to a NaN node, while\n");
		fprintf (stderr, "\t   0.1 will go about 90%% of the way, etc.\n");
		fprintf (stderr, "\t   -Q0 means only consider the nearest node (no interpolation).\n");
		GMT_explain_option ('V');
		GMT_explain_option ('i');
		exit(EXIT_FAILURE);
	}

	got_table = (got_a || got_d || got_e || got_n || got_t);	/* Got a table to read */
	got_grid = (got_g || got_i);					/* Got a grid to read */
	c_nc_type = irint (parameters[COL_TYPE]);			/* NC data type */
	strings = (c_nc_type == NC_CHAR);				/* TRUE if our new column contains strings */
	
	n_paths = MGD77_Path_Expand (&In, argv, argc, &list);	/* Get list of requested IDs */

	if (n_paths == 0) {
		fprintf(stderr, "%s: ERROR: No cruises given\n", GMT_program);
		exit (EXIT_FAILURE);
	}

	if ((got_table + got_grid) > 1) {
		fprintf (stderr, "%s: ERROR: You must select one, and only one, of the -A options.\n", GMT_program);
		exit (EXIT_FAILURE);
	}
	if ((interpolate + strings) > 1) {
		fprintf (stderr, "%s: ERROR: Cannot interpolate column if data are strings\n", GMT_program);
		exit (EXIT_FAILURE);
	}
	if (got_table && got_c) {
		fprintf (stderr, "%s: ERROR: Only one -A option can be specified\n", GMT_program);
		exit (EXIT_FAILURE);
	}
	if (got_table && n_paths != 1) {
		fprintf (stderr, "%s: ERROR: With -Aa|d|D|n|t|T you can only select one cruise at the time.\n", GMT_program);
		exit (EXIT_FAILURE);
	}
	if (!got_grid && bilinear) {
		fprintf (stderr, "%s: ERROR -Q:  Requires -Ag|i.\n", GMT_program);
		exit (EXIT_FAILURE);
	}
	if (bilinear && (threshold < 0.0 || threshold > 1.0)) {
		fprintf (stderr, "%s: ERROR -Q:  threshold must be in [0,1] range\n", GMT_program);
		exit (EXIT_FAILURE);
	}
	if (!delete) {
		if (strlen (c_abbrev) > MGD77_COL_ABBREV_LEN) {
			fprintf(stderr, "%s: ERROR: Column abbreviation too long - %d characters is maximum!\n", GMT_program, MGD77_COL_ABBREV_LEN);
			exit (EXIT_FAILURE);
		}
		if (strlen (c_name) > MGD77_COL_NAME_LEN) {
			fprintf(stderr, "%s: ERROR: Column name too long - %d characters is maximum!\n", GMT_program, MGD77_COL_NAME_LEN);
			exit (EXIT_FAILURE);
		}
		if (strlen (c_comment) > MGD77_COL_COMMENT_LEN) {
			fprintf(stderr, "%s: ERROR: Column comment too long - %d characters is maximum!\n", GMT_program, MGD77_COL_COMMENT_LEN);
			exit (EXIT_FAILURE);
		}
	}
	MGD77_Set_Unit (d_unit, &dist_scale, -1);	/* Gets scale which multiplies meters to chosen distance unit */

	memset ((void *)not_given, (int)no_char, GMT_TEXT_LEN);	/* Text representing "no text value" */
	not_given[GMT_TEXT_LEN-1] = '\0';
	fp_err = (In.verbose_dest == 1) ? GMT_stdout : stderr;
	
	if (got_c) {	/* Calculate values to be stored */
		int version = MGD77_NOT_SET;
		/* "file" is here either m, c, or g[1-4] */
		if (file[0] == 'm' && file[1] == '\0') {
			got_c = ADD_IGRF;
		}
		else if (file[0] == 'c' && file[1] == '\0') {
			got_c = ADD_CARTER;
			MGD77_carter_init (&Carter);	/* Initialize Carter machinery */
		}
		else if (file[0] == 'g' && (file[1] == '\0' || ((version = (file[1] - '0')) >= MGD77_IGF_HEISKANEN && version <= MGD77_IGF_1980)) ) {
			got_c = ADD_GRAV;
			GF_version = version;
		}
		else {
			fprintf(stderr, "%s: ERROR: -Ac expects m, c, or g[1-4]\n", GMT_program);
			exit (EXIT_FAILURE);
		}
	}
	else if (got_g) {	/* Read regular GMT grid */

		if (GMT_read_grd_info (file, &grd)) {
			fprintf (stderr, "%s: Error opening file %s\n", GMT_program, file);
			exit (EXIT_FAILURE);
		}
		if (fabs (grd.x_max - grd.x_min - 360.0) < GMT_CONV_LIMIT) GMT_boundcond_parse (&edgeinfo, "g");
	
		GMT_boundcond_param_prep (&grd, &edgeinfo);
	
		/* Initialize bcr structure with 2 rows/cols boundaries:  */

		GMT_bcr_init (&grd, GMT_pad, bilinear, threshold, &bcr);
		
		mx = grd.nx + GMT_pad[0] + GMT_pad[2];	my = grd.ny + GMT_pad[1] + GMT_pad[3];

		f = (float *) GMT_memory (VNULL, (size_t)(mx * my), sizeof (float), GMT_program);

		if (GMT_read_grd (file, &grd, f, 0.0, 0.0, 0.0, 0.0, GMT_pad, FALSE)) {
			fprintf (stderr, "%s: Error reading file %s\n", GMT_program, file);
			exit (EXIT_FAILURE);
		}
		interpolate = (threshold > 0.0);
	}
	else if (got_i) {	/* Read Sandwell/Smith IMG file */
		struct STAT buf;
		int min;
		if (STAT (file, &buf)) {	/* Inquiry about file failed somehow */
			fprintf (stderr, "%s: Unable to stat file %s\n", GMT_program, file);
			exit (EXIT_FAILURE);
		}
		if (buf.st_size == (21600*12672*2))
			min = 1;
		else if (buf.st_size == (10800*6336*2))
			min = 2;
		else {
			fprintf (stderr, "%s: img file %s does not seem to have 1 or 2 minute grid spacing.\n", GMT_program, file);
			exit (EXIT_FAILURE);
		}
		parameters[IMG_SPACING] = (double)min;
		if ((fp = GMT_fopen (file, "rb")) == NULL) {
			fprintf (stderr, "%s: Error opening img file %s\n", GMT_program, file);
			exit (EXIT_FAILURE);
		}
		GMT_grd_init (&grd, argc, argv, FALSE);
		/* Select plain Mercator on a sphere with -Jm1 -R0/360/-72.006/+72.006 */
		gmtdefs.ellipsoid = GMT_N_ELLIPSOIDS - 1;
		project_info.units_pr_degree = TRUE;
		project_info.m_got_parallel = FALSE;
		project_info.pars[0] = 1.0;
		project_info.projection = GMT_MERCATOR;
		
		GMT_map_setup (0.0, 360.0, GMT_IMG_MINLAT, GMT_IMG_MAXLAT);
		
		GMT_geo_to_xy (project_info.w, project_info.s, &grd.x_min, &grd.y_min);
		GMT_geo_to_xy (project_info.e, project_info.n, &grd.x_max, &grd.y_max);
		grd.x_inc = grd.y_inc = parameters[IMG_SPACING] / 60.0;
		grd.nx = irint (grd.x_max / grd.x_inc);
		grd.ny = irint (grd.y_max / grd.y_inc);
		if ((grd.nx * min) != 21600) {
			fprintf (stderr, "%s: img file %s has %d x-nodes but expected %d\n", GMT_program, file, grd.nx, 21600/min);
			exit (EXIT_FAILURE);
		}
		if ((grd.ny * min) != 12672) {
			fprintf (stderr, "%s: img file %s has %d y-nodes but expected %d\n", GMT_program, file, grd.ny, 12672/min);
			exit (EXIT_FAILURE);
		}
		grd.node_offset = 1;	/* These are pixel grids */
		grd.xy_off = 0.5;
		
		if (fabs (grd.x_max - grd.x_min - 360.0) < GMT_CONV_LIMIT) GMT_boundcond_parse (&edgeinfo, "g");
	
		GMT_boundcond_param_prep (&grd, &edgeinfo);
	
		/* Initialize bcr structure with 2 row/col boundaries:  */

		GMT_bcr_init (&grd, GMT_pad, bilinear, threshold, &bcr);
		
		mx = grd.nx + GMT_pad[0] + GMT_pad[2];	my = grd.ny + GMT_pad[1] + GMT_pad[3];
		track_decode = irint (parameters[IMG_MODE]);
		interpolate = (threshold > 0.0);

		f = (float *) GMT_memory (VNULL, (size_t)(mx * my), sizeof (float), GMT_program);
		i2 = (short int *) GMT_memory (VNULL, (size_t)(grd.nx), sizeof (short int), GMT_program);
		for (j = 0; j < grd.ny; j++) {	/* Read all the rows, offset by 2 boundary rows and cols */
			ij = (j + GMT_pad[3]) * mx + GMT_pad[0];
			fread ((void *)i2, sizeof (short int), grd.nx, fp);
			for (i = 0; i < grd.nx; i++) {	/* Process this row's values */
				switch (track_decode) {
					case 0:	/* No encoded track flags, do nothing */
						break;
					case 1:	/* Remove the track flag on odd (constrained) points */
						if (i2[i]%2) i2[i]--;
						break;
					case 2:	/* Remove the track flag on odd (constrained) points and set unconstrained to NaN */
						i2[i] = (i2[i]%2) ? i2[i] - 1 : SHRT_MIN;
						break;
					case 3:	/* Set odd (constrained) points to 1 and set unconstrained to 0 */
						i2[i] %= 2;
						break;
				}
				f[ij+i] = (float)((track_decode == 3) ? i2[i] : (i2[i] * parameters[IMG_SCALE]));
			}
		}
		GMT_free ((void *)i2);
		GMT_fclose (fp);
	}
	else if (got_table) {	/* Got a one- or two-column table to read */
		if (file[0] == '-') {   /* Just read from standard input */
			fp = GMT_stdin;
#ifdef SET_IO_MODE
			GMT_setmode (GMT_IN);
#endif
		}
		else {
			if ((fp = GMT_fopen (file, GMT_io.r_mode)) == NULL) {
				fprintf (stderr, "%s: Cannot open file %s\n", GMT_program, file);
				exit (EXIT_FAILURE);
			}
		}

		/* Skip any header records */
		if (GMT_io.io_header[GMT_IN]) for (i = 0; i < GMT_io.n_header_recs; i++) GMT_fgets (line, BUFSIZ, fp);

		n = 0;
		n_alloc = GMT_CHUNK;
		n_expected_fields = (GMT_io.ncol[GMT_IN]) ? GMT_io.ncol[GMT_IN] : BUFSIZ;
		colvalue = (double *) GMT_memory (VNULL, (size_t)n_alloc, sizeof (double), GMT_program);
		two_cols = (got_d || got_n || got_t);
		if (two_cols) {	/* Got an abscissae column as well (dnt: d = dist, n = rec number, t = time) */
			coldnt = (double *) GMT_memory (VNULL, (size_t)n_alloc, sizeof (double), GMT_program);
			GMT_io.in_col_type[0] = kind;
		}
		if (strings && !two_cols) {	/* Must read strings directly from file since GMT_input would barf */
			ok_to_read = FALSE;
			tmp_string = (char **) GMT_memory (VNULL, n_alloc, sizeof (char *), GMT_program);
			while (fgets (word, BUFSIZ, fp)) {
				if (word[0] == '#') continue;
				width = strlen (word);
				tmp_string[n] = (char *) GMT_memory (VNULL, (size_t)(width+1), sizeof (char), GMT_program);
				strcpy (tmp_string[n], word);
				if (width > LEN) LEN = width;
				n++;
			}
		}
		else if (strings) {		/* Pretend to read one column and get the text string form the text record */
			tmp_string = (char **) GMT_memory (VNULL, n_alloc, sizeof (char *), GMT_program);
			n_expected_fields = 1;
		}
		
		if (ok_to_read) n_fields = GMT_input (fp, &n_expected_fields, &in);

		while (ok_to_read && ! (GMT_io.status & GMT_IO_EOF)) {	/* Not yet EOF */

			while ((GMT_io.status & GMT_IO_SEGMENT_HEADER) && !(GMT_io.status & GMT_IO_EOF)) {
				n_fields = GMT_input (fp, &n_expected_fields, &in);
			}
			if ((GMT_io.status & GMT_IO_EOF)) continue;	/* At EOF */

			if (GMT_io.status & GMT_IO_MISMATCH) {
				fprintf (stderr, "%s: Mismatch between actual (%d) and expected (%d) fields near line %d\n", GMT_program, n_fields, n_expected_fields, n);
				exit (EXIT_FAILURE);
			}

			if (strings) {	/* number in col1, string in col2 */
				coldnt[n]   = in[0];
				sscanf (GMT_io.current_record, "%*s %s", word);
				tmp_string[n] = (char *) GMT_memory (VNULL, (size_t)(strlen(word)+1), sizeof (char), GMT_program);
				strcpy (tmp_string[n], word);
			}
			else if (two_cols) {
				coldnt[n]   = in[0];
				colvalue[n] = in[1];
			}
			else
				colvalue[n] = in[0];
			n++;
			if (n == (int)n_alloc) {
				n_alloc += GMT_CHUNK;
				if (strings)
					tmp_string = (char **) GMT_memory ((void *)tmp_string, n_alloc, sizeof (char *), GMT_program);
				else
					colvalue = (double *) GMT_memory ((void *)colvalue, (size_t)n_alloc, sizeof (double), GMT_program);
				if (two_cols) coldnt = (double *) GMT_memory ((void *)coldnt, (size_t)n_alloc, sizeof (double), GMT_program);
			}

			n_fields = GMT_input (fp, &n_expected_fields, &in);
		}
		if (fp != GMT_stdin) GMT_fclose (fp);
		if (!strings) colvalue = (double *) GMT_memory ((void *)colvalue, (size_t)n, sizeof (double), GMT_program);
		if (two_cols) coldnt = (double *) GMT_memory ((void *)coldnt, (size_t)n, sizeof (double), GMT_program);
	}
	
	if (got_grid) {	/* Set inverse spacing */
		i_dx = 1.0 / grd.x_inc;
		i_dy = 1.0 / grd.y_inc;
	}

	MGD77_Ignore_Format (MGD77_FORMAT_ANY);	/* Reset to all formats OK, then ... */
	MGD77_Ignore_Format (MGD77_FORMAT_M77);	/* disallow ASCII MGD77 files */
	MGD77_Ignore_Format (MGD77_FORMAT_TBL);	/* and ASCI tables */
	
	In.format = MGD77_FORMAT_CDF;	/* Only file type allowed as input */
	
	for (argno = 0; argno < n_paths; argno++) {		/* Process each ID */
	
		if (MGD77_Open_File (list[argno], &In, MGD77_READ_MODE)) continue;
				
		if (gmtdefs.verbose) fprintf (stderr, "%s: Now processing cruise %s\n", GMT_program, list[argno]);
		
		D = MGD77_Create_Dataset ();
		In.n_out_columns = 0;

		if (MGD77_Read_File (list[argno], &In, D)) {
			fprintf (stderr, "%s: Error reading data set for cruise %s\n", GMT_program, list[argno]);
			exit (EXIT_FAILURE);
		}

		/* Start reading data from file */
	
		column = MGD77_Get_Column (c_abbrev, &In);
		set    = MGD77_Get_Set (c_abbrev);
		if (column != MGD77_NOT_SET) {	/* A column with same abbreviation is already present in the file */
			if (set == MGD77_M77_SET) {
				fprintf (stderr, "%s: column %s is part of the standard MGD77 set and cannot be removed!\n", GMT_program, c_abbrev);
				exit (EXIT_FAILURE);
			}
			if (!replace) {
				fprintf (stderr, "%s: A columned named %s is already present in %s.  use -A+ to overwrite [default is to skip]\n", GMT_program, c_abbrev, list[argno]);
				MGD77_Free (D);	/* Free memory already allocated by MGD77_Read_File for this aborted effort */
				continue;
			}
		}

		if (delete) {	/* Must create a new file with everything except the fields to be deleted */
			int id, c;
			char oldfile[BUFSIZ];
			
			if (column != MGD77_NOT_SET) {	/* Get info about this existing column to see if it is compatible with new data */
				n_dims = (D->H.info[In.order[column].set].col[In.order[column].item].constant) ? 0 : 1;
				if (D->H.info[In.order[column].set].col[In.order[column].item].text) n_dims++;
			}
			
			pos = n_delete = 0;
			(void) time (&now);
			sprintf (history, "%s %s removed columns", ctime(&now), In.user);
			while ((GMT_strtok (d_list, ",", &pos, p))) {	/* For each named column */
				k = MGD77_Get_Column (p, &In);
				if (k == MGD77_NOT_SET) {
					fprintf (stderr, "%s: No column named %s in %s - cannot delete it. \n", GMT_program, p, list[argno]);
					continue;
				}
				c = In.order[k].set;
				id = In.order[k].item;
				D->H.info[c].col[id].abbrev[0] = D->H.info[c].col[id].name[0] = D->H.info[c].col[id].units[0] = D->H.info[c].col[id].comment[0] = '\0';
				D->H.info[c].col[id].pos = D->H.info[c].col[id].var_id = MGD77_NOT_SET;
				D->H.info[c].bit_pattern = 0;
				D->H.info[c].col[id].present = FALSE;
				D->H.info[c].n_col--;
				D->H.n_fields--;
				D->n_fields--;
				In.n_out_columns--;
				for (i = k; i < In.n_out_columns; i++) {	/* Move remaining columns over */
					D->values[i] = D->values[i+1];
					strcpy (In.desired_column[i], In.desired_column[i+1]);
					In.order[i].set = In.order[i+1].set;
					In.order[i].item = In.order[i+1].item;
				}
				strcat (history, " ");
				strcat (history, p);
				n_delete++;
			}
			
			/* Rename the old file for now */
			
			sprintf (oldfile, "%s.old", In.path);
			if (rename (In.path, oldfile)) {
				fprintf (stderr, "%s: Unable to rename %s to %s\n", GMT_program, In.path, oldfile);
				exit (EXIT_FAILURE);
			}
			
			/* Update header history */

			k = strlen (history);
			for (i = 0; i < k; i++) if (history[i] == '\n') history[i] = ' ';	/* Remove the \n returned by ctime() */
			history[k++] = '\n';	history[k] = '\0';				/* Add LF at end of line */
			k += strlen (D->H.history);
			D->H.history = (char *)GMT_memory ((void *)D->H.history, k, sizeof (char), GMT_program);
			strcat (D->H.history, history);		/* MGD77_Write_FILE_cdf will use this to create the history attribute, thus preserving earlier history */

			if (MGD77_Write_File (In.path, &In, D)) {	/* Create the new, slimmer file */
				fprintf (stderr, "%s: Error writing slimmer version of %s\n", GMT_program, list[argno]);
				exit (EXIT_FAILURE);
			}

			/* Now we can safely remove the old file */
			
			if (remove (oldfile)) {
				fprintf (stderr, "%s: Error removing the old version of %s\n", GMT_program, list[argno]);
				exit (EXIT_FAILURE);
			}
			
			MGD77_Free (D);
			if (column == MGD77_NOT_SET) continue;	/* Nothing more to do for this file */
			
			/* Now reread header etc since things have changed in the file */
			
			In.n_out_columns = 0;
			D = MGD77_Create_Dataset ();
			if (MGD77_Read_File (list[argno], &In, D)) {
				fprintf (stderr, "%s: Error reading data set for cruise %s\n", GMT_program, list[argno]);
				exit (EXIT_FAILURE);
			}
		}
		
		if (got_c == ADD_IGRF) {	/* Append IGRF column */
			int ix, iy, it;
			double n_days, date, *xvar, *yvar, *tvar, IGRF[7];
			
			if ((ix = skip_if_missing ("lon",  list[argno], &In, D)) == MGD77_NOT_SET) continue;
			if ((iy = skip_if_missing ("lat",  list[argno], &In, D)) == MGD77_NOT_SET) continue;
			if ((it = skip_if_missing ("time", list[argno], &In, D)) == MGD77_NOT_SET) continue;

			xvar = (double *)D->values[ix];
			yvar = (double *)D->values[iy];
			tvar = (double *)D->values[it];
			colvalue = (double *)GMT_memory (VNULL, D->H.n_records, sizeof (double), GMT_program);
			
			for (i = n_sampled = 0; i < D->H.n_records; i++) {
				GMT_gcal_from_dt (tvar[i], &cal);			/* No adjust for TZ; this is GMT UTC time */
				n_days = (GMT_is_gleap (cal.year)) ? 366.0 : 365.0;	/* Number of days in this year */
				/* Get date as decimal year */
				date = cal.year + cal.day_y / n_days + (cal.hour * GMT_HR2SEC_I + cal.min * GMT_MIN2SEC_I + cal.sec) * GMT_SEC2DAY;
				colvalue[i] = (MGD77_igrf10syn (0, date, 1, 0.0, xvar[i], yvar[i], IGRF)) ? GMT_d_NaN : IGRF[MGD77_IGRF_F];
				n_sampled++;
			}
			if (gmtdefs.verbose) fprintf (stderr, "%s: Estimated IGRF at %d locations out of %d for cruise %s\n", GMT_program, n_sampled, D->H.n_records, list[argno]);
		}
		else if (got_c == ADD_GRAV) {	/* Append IGF column */
			int ix, iy;
			double *xvar, *yvar;
			
			if ((ix = skip_if_missing ("lon", list[argno], &In, D)) == MGD77_NOT_SET) continue;
			if ((iy = skip_if_missing ("lat", list[argno], &In, D)) == MGD77_NOT_SET) continue;

			if (GF_version == MGD77_NOT_SET) {
				GF_version = D->H.mgd77->Gravity_Theoretical_Formula_Code - '0';
				if (GF_version < MGD77_IGF_HEISKANEN || GF_version > MGD77_IGF_1980) {
					fprintf (stderr, "%s: Invalid Gravity Theoretical Formula Code (%c) - default to %d\n", GMT_program, D->H.mgd77->Gravity_Theoretical_Formula_Code, MGD77_IGF_1980);
					GF_version = MGD77_IGF_1980;
				}
			}
			xvar = (double *)D->values[ix];
			yvar = (double *)D->values[iy];
			colvalue = (double *)GMT_memory (VNULL, D->H.n_records, sizeof (double), GMT_program);
			
			for (i = 0; i < D->H.n_records; i++) colvalue[i] = MGD77_Theoretical_Gravity (xvar[i], yvar[i], GF_version);
			if (gmtdefs.verbose) fprintf (stderr, "%s: Estimated IGRF at %d locations out of %d for cruise %s\n", GMT_program, D->H.n_records, D->H.n_records, list[argno]);
		}
		else if (got_c == ADD_CARTER) {	/* Append Carter correction column */
			int ix, iy, it;
			double *xvar, *yvar, *tvar;
			
			if ((ix = skip_if_missing ("lon", list[argno], &In, D)) == MGD77_NOT_SET) continue;
			if ((iy = skip_if_missing ("lat", list[argno], &In, D)) == MGD77_NOT_SET) continue;
			if ((it = skip_if_missing ("twt", list[argno], &In, D)) == MGD77_NOT_SET) continue;

			xvar = (double *)D->values[ix];
			yvar = (double *)D->values[iy];
			tvar = (double *)D->values[it];
			colvalue = (double *)GMT_memory (VNULL, D->H.n_records, sizeof (double), GMT_program);
			
			for (i = 0; i < D->H.n_records; i++) colvalue[i] = MGD77_carter_correction (xvar[i], yvar[i], 1000.0 * tvar[i], &Carter);
			if (gmtdefs.verbose) fprintf (stderr, "%s: Estimated IGRF at %d locations out of %d for cruise %s\n", GMT_program, D->H.n_records, D->H.n_records, list[argno]);
		}
		else if (got_grid) {	/* Sample grid along track (or Mercator-projected) track */
			int ix, iy;
			double *xvar, *yvar;
			
			if ((ix = skip_if_missing ("lon", list[argno], &In, D)) == MGD77_NOT_SET) continue;
			if ((iy = skip_if_missing ("lat", list[argno], &In, D)) == MGD77_NOT_SET) continue;

			xvar = (double *)D->values[ix];
			yvar = (double *)D->values[iy];
			colvalue = (double *)GMT_memory (VNULL, D->H.n_records, sizeof (double), GMT_program);
			
			for (i = n_sampled = 0; i < D->H.n_records; i++) {
				colvalue[i] = GMT_d_NaN;	/* In case we are outside grid */
	
				/* If point is outside grd area, shift it using periodicity or skip if not periodic. */

				if (got_i)	/* Mercator IMG grid */
					GMT_geo_to_xy (xvar[i], yvar[i], &x, &y);
				else {		/* Regular geographic grd */
					x = xvar[i];
					y = yvar[i];
				}
				if (y < grd.y_min || y > grd.y_max) continue;

				while ( (x < grd.x_min) && (edgeinfo.nxp > 0) ) x += (grd.x_inc * edgeinfo.nxp);
				if (x < grd.x_min) continue;

				while ( (x > grd.x_max) && (edgeinfo.nxp > 0) ) x -= (grd.x_inc * edgeinfo.nxp);
				if (x > grd.x_max) continue;

				if (interpolate) {	/* IMG has been corrected, and GRD is good to go */
					colvalue[i] = GMT_get_bcr_z (&grd, x, y, f, &edgeinfo, &bcr);
				}
				else {	/* Take IMG nearest node and do special stuff (values already set during read) */
					ii = GMT_x_to_i (x, grd.x_min, grd.x_inc, grd.xy_off, grd.nx);
					jj = GMT_y_to_j (y, grd.y_min, grd.y_inc, grd.xy_off, grd.ny);
					colvalue[i] = f[(jj+GMT_pad[3])*mx+ii+GMT_pad[0]];
				}
				n_sampled++;
			}
			if (gmtdefs.verbose) fprintf (stderr, "%s: Sampled grid at %d locations out of %d for cruise %s\n", GMT_program, n_sampled, D->H.n_records, list[argno]);
		}
		else if (got_a) {	/* Just got a single column to paste in, assuming the row numbers match */
			if (n != D->H.n_records) {
				fprintf (stderr, "%s: Extra column data records (%d) do not match # of cruise records (%d) for %s\n", GMT_program, n, D->H.n_records, list[argno]);
				exit (EXIT_FAILURE);
			}
			if (gmtdefs.verbose) fprintf (stderr, "%s: Appended column data for all %d records for cruise %s\n", GMT_program, D->H.n_records, list[argno]);
		}
		else if (got_d || got_n || got_t) {	/* Got either (time,data) or (dist,data) */
			int ix, iy, it;
			double *x = VNULL, *y = VNULL, *d = VNULL;
			colvalue = (double *) GMT_memory ((void *)colvalue, (size_t)D->H.n_records, sizeof (double), GMT_program);
			if (got_d) {	/* Must create distances in user's units */
				if ((ix = skip_if_missing ("lon", list[argno], &In, D)) == MGD77_NOT_SET) continue;
				if ((iy = skip_if_missing ("lat", list[argno], &In, D)) == MGD77_NOT_SET) continue;
				x = (double *)D->values[ix];
				y = (double *)D->values[iy];
				d = GMT_distances (x, y, D->H.n_records, dist_scale, dist_flag);
				x = d;
			}
			else if (got_t) {	/* Time */
				if ((it = skip_if_missing ("time", list[argno], &In, D)) == MGD77_NOT_SET) continue;
				x = (double *)D->values[it];
			}
			if (interpolate) {	/* Using given table to interpolate the values at all mgd77 records */
				y = (double *) GMT_memory (VNULL, (size_t)D->H.n_records, sizeof (double), GMT_program);
				result = GMT_intpol (coldnt, colvalue, n, D->H.n_records, x, y, gmtdefs.interpolant);
				if (result != 0) {
					fprintf (stderr, "%s: Error from GMT_intpol near row %d!\n", GMT_program, result+1);
					exit (EXIT_FAILURE);
				}
				memcpy ((void *)colvalue, (void *)y, (size_t)(D->H.n_records * sizeof (double)));
				GMT_free ((void *)y);
			}
			else if (strings && n < D->H.n_records) {	/* Only update the exact matching records */
				text = (char *) GMT_memory (VNULL, D->H.n_records * LEN, sizeof (char), GMT_program);
				for (i = j = n_sampled = 0; i < D->H.n_records && j < n; i++) {
					match_value = (got_n) ? i : x[i];
					strncpy (&text[i*LEN], not_given, (int)LEN);	/* In case we have no data at this time */
					while (coldnt[j] < match_value && j < n) j++;
					if (coldnt[j] == match_value) {
						strncpy (&text[i*LEN], tmp_string[j], (int)LEN);
						n_sampled++;
					}
				}
				GMT_free ((void *)tmp_string);
				if (gmtdefs.verbose) fprintf (stderr, "%s: Appended column data for %d locations out of %d for cruise %s\n", GMT_program, n_sampled, D->H.n_records, list[argno]);
			}
			else if (strings) {	/* One to one match */
				text = (char *) GMT_memory (VNULL, D->H.n_records * LEN, sizeof (char), GMT_program);
				for (i = 0; i < n; i++) strncpy (&text[i*LEN], tmp_string[i], (int)LEN);
				GMT_free ((void *)tmp_string);
				if (gmtdefs.verbose) fprintf (stderr, "%s: Appended column data for %d locations out of %d for cruise %s\n", GMT_program, n_sampled, D->H.n_records, list[argno]);
			}
			else {	/* Only update the exact matching records */
				y = (double *) GMT_memory (VNULL, (size_t)D->H.n_records, sizeof (double), GMT_program);
				for (i = j = n_sampled = 0; i < D->H.n_records && j < n; i++) {
					match_value = (got_n) ? i : x[i];
					y[i] = GMT_d_NaN;	/* In case we have no data at this time */
					while (coldnt[j] < match_value && j < n) j++;
					if (coldnt[j] == match_value) {	/* Found our guy */
						y[i] = colvalue[j];
						n_sampled++;
					}
				}
				memcpy ((void *)colvalue, (void *)y, (size_t)(D->H.n_records * sizeof (double)));
				if (gmtdefs.verbose) fprintf (stderr, "%s: Appended column data for %d locations out of %d for cruise %s\n", GMT_program, n_sampled, D->H.n_records, list[argno]);
				GMT_free ((void *)y);
			}
			if (got_d) GMT_free ((void *)d);
		}
		else if (got_e)
		{
			/* Read any header scale/offset factors to be set.
			 * Decode error flags to give bit flag, store in colvalue
			 */
			FILE *fp_e;
			char ID[16], date[16], field[GMT_TEXT_LEN], efile[BUFSIZ], timestamp[GMT_TEXT_LEN], answer[BUFSIZ], code[BUFSIZ], YorN, kind;
			int n_recs, type, number, item, it, rec, id, var_id, key, n_flags, from, to, day, month, year, e_error = 0;
			unsigned int *flags, pattern;
			BOOLEAN has_time;
			struct MGD77_HEADER_PARAMS *P;
			double rec_time, value, *tvar = VNULL;
			
			sprintf (efile, "%s.e77", list[argno]);
			if ((fp_e = GMT_fopen (efile, "r")) == NULL) {	/* Not in current directory, try MGD77_HOME/E77 */
				sprintf (efile, "%s%cE77%c%s.e77", In.MGD77_HOME, DIR_DELIM, DIR_DELIM, list[argno]);
				if ((fp_e = GMT_fopen (efile, "r")) == NULL) {	/* Not here either */
					fprintf(stderr, "%s: ERROR: The file %s.e77 could not be found in current directory or in MGD77_HOME/E77 - skipped\n", GMT_program, list[argno]);
					MGD77_Free (D);	/* Free memory allocated by MGD77_Read_File for this aborted effort */
					continue;
				}
			
			}
			P = D->H.mgd77;
			if (!fgets (line, BUFSIZ, fp_e)) {
				fprintf(stderr, "%s: ERROR: Could not read record #1 from %s.e77 - aborting\n", GMT_program, list[argno]);
				e_error++;
			}
			sscanf (&line[1], "%*s %s %*s %*s %*s %*s %*s %s %*s %d", ID, date, &n_recs);
			if (strcmp (In.NGDC_id, ID)) {
				fprintf(stderr, "%s: ERROR: E77 Conflict %s : ID = %s versus %s - aborting\n", GMT_program, efile, ID, In.NGDC_id);
				e_error++;
			}
			/* Make sure the File creation dates from the data file and the E77 match */
			day = atoi (&date[6]);
			date[6] = 0;
			month = atoi (&date[4]);
			date[4] = 0;
			year = atoi (date);
			
			if (!(year == atoi (P->File_Creation_Year) && month == atoi (P->File_Creation_Month) && day == atoi (P->File_Creation_Day))) {
				fprintf(stderr, "%s: ERROR: E77 Conflict %s: File Creation Date: %s versus %s%s%s - aborting\n", GMT_program, efile, date,
					P->File_Creation_Year, P->File_Creation_Month, P->File_Creation_Day);
				e_error++;
			}
			if (n_recs != D->H.n_records) {
				fprintf(stderr, "%s: ERROR: E77 Conflict %s: n_recs = %d versus %d = aborting\n", GMT_program, efile, n_recs, D->H.n_records);
				e_error++;
			}
			if (e_error) {
				fprintf(stderr, "%s: ERROR: The file %s has too many errors - skipped\n", GMT_program, efile);
				MGD77_Free (D);	/* Free memory allocated by MGD77_Read_File for this aborted effort */
				continue;
			}
			
			flags = (unsigned int *)GMT_memory (VNULL, D->H.n_records, sizeof (unsigned int), GMT_program);
			n_flags = 0;

			MGD77_nc_status (nc_open (In.path, NC_WRITE, &In.nc_id));	/* Open the file */
			MGD77_nc_status (nc_redef (In.nc_id));				/* Enter define mode */

			while (fgets (line, BUFSIZ, fp_e) && strncmp (line, "# Errata: Data", 14)) {	/* Read until we get to data record section */
				if (line[0] == '#') continue;	/* Skip comments */
				GMT_chop (line);	/* Rid the world of CR/LF */
				sscanf (line, "%c-%[^-]-%c-%d-%d", &YorN, field, &kind, &number, &item);
				if (YorN == 'I') {	/* Information message */
					fprintf (stderr, "%s: %s\n", list[argno], line);
					continue;
				}
				type = (field[0] == 'H') ? 0 : 1;
				if (e77_mode[type] == -1) continue;
				if (e77_mode[type] == 0 && YorN == 'N') continue;
				if (!got_default_answer (line, answer)) continue;
				
				/* Here we must do something */
				
				if (type == 0) {	/* Header meta data fixes */
					switch (number) {
						case 1:	/* Header Sequence 01 */
							switch (item) {
								case 1:	/* Invalid Record Type */
									P->Record_Type = answer[0];
									break;
								case 2:	/* Survey Identifier missing */
									strcpy (P->Survey_Identifier, answer);
									break;
								case 3:	/* Invalid Format Acronym */
									strcpy (P->Format_Acronym, answer);
									break;
								case 4:	/* Invalid Data Center File Number */
									strcpy (P->Format_Acronym, answer);
									break;
								case 5:	/* Invalid Parameter Survey Code */
								case 6:
								case 7:
								case 8:
								case 9:
									P->Paramaters_Surveyed_Code[item-5] = answer[0];
									break;
								case 10:	/* Invalid File Creation Year */
									strcpy (P->File_Creation_Year, answer);
									break;
								case 11:	/* Invalid File Creation Month */
									strcpy (P->File_Creation_Month, answer);
									break;
								case 12:	/* Invalid File Creation Day */
									strcpy (P->File_Creation_Day, answer);
									break;
								default:
									fprintf (stderr, "%s: Warning: Sequence number %d, Item %d is not supported - skipped\n", GMT_program, number, item);
									break;
							}
							break;
						case 2:	/* Header Sequence 02 */
							switch (item) {
								case 3:	/* Invalid Platform Type Code */
									P->Platform_Type_Code = answer[0];
									break;
								default:
									fprintf (stderr, "%s: Warning: Sequence number %d, Item %d is not supported - skipped\n", GMT_program, number, item);
									break;
							}
							break;
						case 4:	/* Header Sequence 04 */
							switch (item) {
								case 1:	/* Invalid Survey Departure Year */
									strcpy (P->Survey_Departure_Year, answer);
									break;
								case 2:	/* Invalid Survey Departure Month */
									strcpy (P->Survey_Departure_Month, answer);
									break;
								case 3:	/* Invalid Survey Departure Day */
									strcpy (P->Survey_Departure_Day, answer);
									break;
								case 4:	/* Invalid Arrival Departure Year */
									strcpy (P->Survey_Arrival_Year, answer);
									break;
								case 5:	/* Invalid Arrival Departure Month */
									strcpy (P->Survey_Arrival_Month, answer);
									break;
								case 6:	/* Invalid Arrival Departure Day */
									strcpy (P->Survey_Arrival_Day, answer);
									break;
								default:
									fprintf (stderr, "%s: Warning: Sequence number %d, Item %d is not supported - skipped\n", GMT_program, number, item);
									break;
							}
							break;
						case 10:	/* Header Sequence 10 */
							switch (item) {
								case 1:	/* Invalid Format Type */
									P->Format_Type = answer[0];
									break;
								case 2:	/* Invalid Format Description */
									strcpy (P->Format_Description, answer);
									break;
								default:
									fprintf (stderr, "%s: Warning: Sequence number %d, Item %d is not supported - skipped\n", GMT_program, number, item);
									break;
							}
							break;
						case 11:	/* Header Sequence 11 */
							switch (item) {
								case 2:	/* Invalid Topmost Latitude */
									strcpy (P->Topmost_Latitude, answer);
									break;
								case 3:	/* Invalid Bottommost Latitude */
									strcpy (P->Bottommost_Latitude, answer);
									break;
								case 5:	/* Invalid Leftmost Latitude */
									strcpy (P->Leftmost_Longitude, answer);
									break;
								case 6:	/* Invalid Rightmost Latitude */
									strcpy (P->Rightmost_Longitude, answer);
									break;
								default:
									fprintf (stderr, "%s: Warning: Sequence number %d, Item %d is not supported - skipped\n", GMT_program, number, item);
									break;
							}
							break;
						case 12:	/* Header Sequence 12 */
							switch (item) {
								case 1:	/* Invalid Bathymetry Digitizing Rate */
									strcpy (P->Bathymetry_Digitizing_Rate, answer);
									break;
								case 3:	/* Invalid Bathymetry Assumed Sound Velocity */
									strcpy (P->Bathymetry_Assumed_Sound_Velocity, answer);
									break;
								case 4:	/* Invalid Bathymetry Datum Code */
									strcpy (P->Bathymetry_Datum_Code, answer);
									break;
								default:
									fprintf (stderr, "%s: Warning: Sequence number %d, Item %d is not supported - skipped\n", GMT_program, number, item);
									break;
							}
							break;
						case 13:	/* Header Sequence 13 */
							switch (item) {
								case 1:	/* Invalid Magnetics Digitizing Rate */
									strcpy (P->Magnetics_Digitizing_Rate, answer);
									break;
								case 2:	/* Invalid Magnetics Digitizing Rate */
									strcpy (P->Magnetics_Sampling_Rate, answer);
									break;
								case 3:	/* Invalid Magnetics Sensor Tow Distance */
									strcpy (P->Magnetics_Sensor_Tow_Distance, answer);
									break;
								case 4:	/* Invalid Magnetics Sensor Depth */
									strcpy (P->Magnetics_Sensor_Depth, answer);
									break;
								case 5:	/* Invalid Magnetics Sensor Separation */
									strcpy (P->Magnetics_Sensor_Separation, answer);
									break;
								case 6:	/* Invalid Magnetics Reference Field */
									strcpy (P->Magnetics_Ref_Field, answer);
									break;
								case 8:	/* Invalid Magnetics Reference Field Code */
									strcpy (P->Magnetics_Ref_Field_Code, answer);
									break;
								case 9:	/* Invalid IGRF Code */
									strcpy (P->Magnetics_Ref_Field_Code, answer);
									break;
									break;
								default:
									fprintf (stderr, "%s: Warning: Sequence number %d, Item %d is not supported - skipped\n", GMT_program, number, item);
									break;
							}
							break;
						case 14:	/* Header Sequence 14 */
							switch (item) {
								case 1:	/* Invalid Gravity Digitizing Rate */
									strcpy (P->Gravity_Digitizing_Rate, answer);
									break;
								case 2:	/* Invalid Gravity Sampling Rate */
									strcpy (P->Gravity_Sampling_Rate, answer);
									break;
								case 3:	/* Invalid Gravity Theoretical Formula Code */
									P->Gravity_Theoretical_Formula_Code = answer[0];
									break;
								case 4:	/* Invalid Gravity Reference System Code */
									P->Gravity_Reference_System_Code = answer[0];
									break;
								default:
									fprintf (stderr, "%s: Warning: Sequence number %d, Item %d is not supported - skipped\n", GMT_program, number, item);
									break;
							}
							break;
						case 15:	/* Header Sequence 15 */
							switch (item) {
								case 1:	/* Invalid Gravity Departure Base Station Value */
									strcpy (P->Gravity_Departure_Base_Station, answer);
									break;
								case 3:	/* Invalid Gravity Arrival Base Station Value */
									strcpy (P->Gravity_Arrival_Base_Station, answer);
									break;
								default:
									fprintf (stderr, "%s: Warning: Sequence number %d, Item %d is not supported - skipped\n", GMT_program, number, item);
									break;
							}
							break;
						case 16:	/* Header Sequence 16 */
							switch (item) {
								case 1:	/* Invalid Number of Ten Degree Identifiers */
									strcpy (P->Number_of_Ten_Degree_Identifiers, answer);
									break;
								case 2:	/* Invalid Number of Ten Degree Identifiers */
									strcpy (P->Number_of_Ten_Degree_Identifiers, answer);
									break;
								default:
									fprintf (stderr, "%s: Warning: Sequence number %d, Item %d is not supported - skipped\n", GMT_program, number, item);
									break;
							}
							break;
						default:
							fprintf (stderr, "%s: Warning: Sequence number %d is outside range - skipped\n", GMT_program, number);
							break;
					}
				}
				else {			/* Systematic fixes */
					if ((id = MGD77_Get_Column (field, &In)) == MGD77_NOT_SET) {
						fprintf (stderr, "%s: Warning: Correction found for %s which is not in this cruise?\n", GMT_program, field);
					}
					else {
						k = MGD77_Info_from_Abbrev (field, &(D->H), &set, &item);
						value = atof (answer);
						switch (number) {
							case 01:	/* Correction scale factor */
								if (D->H.info[set].col[id].corr_factor == 1.0) {	/* Must add a new attribute to the file */
									D->H.info[set].col[id].corr_factor = value;
									MGD77_nc_status (nc_put_att_double (In.nc_id, D->H.info[set].col[id].var_id, "corr_factor", NC_DOUBLE, 1, &D->H.info[set].col[id].corr_factor));
								}
								break;
							case 02:	/* Correction offset */
								if (D->H.info[set].col[id].corr_offset == 0.0) {	/* Must add a new attribute to the file */
									D->H.info[set].col[id].corr_offset = value;
									MGD77_nc_status (nc_put_att_double (In.nc_id, D->H.info[set].col[id].var_id, "corr_offset", NC_DOUBLE, 1, &D->H.info[set].col[id].corr_offset));
								}
								break;
							case 05:	/* Range of bad values - set flags to BAD  */
								sscanf (answer, "%d-%d", &from, &to);
								if (from < 1 || from > D->H.n_records || to < 1 || to > D->H.n_records || to < from) {
									fprintf (stderr, "%s: Error: Record range %s is invalid.  Correction skipped\n", GMT_program, answer);
									break;
								}
								pattern = set_bit (id);
 								for (rec = from-1; rec < to; rec++, n_flags++) flags[rec] |= pattern;	/* -1 to get C indeces */
								break;
							default:
								break;
						}
					}
				}
			}
			/* Now start on data record section */
			has_time = TRUE;
			if ((it = skip_if_missing ("time", list[argno], &In, D)) == MGD77_NOT_SET)
				has_time = FALSE;
			else
				tvar = (double *)D->values[it];
			while (fgets (line, BUFSIZ, fp_e)) {	/* Read until EOF */
				sscanf (line, "%s %d %s", timestamp, &rec, code);
				rec--;	/* E77 starts with rec = 1 for first data record */
				if (has_time) {
					if (GMT_verify_expectations (GMT_IS_ABSTIME, GMT_scanf (timestamp, GMT_IS_ABSTIME, &rec_time), timestamp)) {
						fprintf (stderr, "%s: ERROR: E77 time stamp (%s) in wrong format? - skipped\n", GMT_program, timestamp);
						continue;
					}
					if (fabs (tvar[rec] - rec_time) > 0.05) {	/* 0.06 is finest resolution in MGD77 file */
						fprintf (stderr, "%s: ERROR: E77 time stamp and record number do not match record time - skipped\n", GMT_program);
						continue;
					}
				}
				pos = 0;
				item = -1;	/* So we increment to 0 inside the loop */
				while (GMT_strtok (code, "-", &pos, p)) {
					item++;
					if (e77_mode[item+2]) continue;	/* Ignore this sort of code */
					if (p[0] == '0') continue;
					for (k = 0; k < (int)strlen(p); k++) {	/* Loop over one or more codes */
					
						if (item == 0) {	/* NAV */
							switch (p[k]) {
								case 'A':	/* Time out of range */
									flags[rec] |= set_bit(0);
									n_flags++;
									break;
								case 'B':
									fprintf (stderr, "%s: Decreasing time %s - Source Institution need to sort records\n", list[argno], timestamp);
									break;
								case 'C':	/* Excessive speed - flag time, lon, lat */
									flags[rec] |= set_bit(0);
									flags[rec] |= set_bit(4);
									flags[rec] |= set_bit(3);
									n_flags++;
									break;
								case 'D':	/* On land */ 
									flags[rec] |= set_bit(4);
									flags[rec] |= set_bit(3);
									n_flags++;
									break;
								case 'E':	/* Undefined lat */
									flags[rec] |= set_bit(3);
									n_flags++;
									break;
								case 'F':	/* Undefined lon */
									flags[rec] |= set_bit(4);
									n_flags++;
									break;
								default:
									fprintf (stderr, "%s: Unrecognized NAV code %c - skipped\n", list[argno], p[k]);
									break;
							}
						}
						else if (p[k] < 'A' || p[k] > 'X') {
							fprintf (stderr, "%s: Unrecognized error field %c - skipped\n", list[argno], p[k]);
						}
						else {			/* EO, RANGE, SLOPE, or GRID */
							if (p[k] >= 'A' && p[k] <= 'X')	{ /* Valid codes */
								if (p[k] > 'G')
 									key = p[k] - 'A' - 4;	/* H (lat) = 3, J (ptc) = 5, etc (only expect J-X though) */
								else if (p[k] < 'C')
									key = p[k] - 'A' + 1;	/* A (rectype) = 1, B (TZ) = 2 */
								else
  									key = 0;	/* C-G (yyyy,mm,dd,hh,mi) all map to time 0 */
								flags[rec] |= set_bit(key);
								n_flags++;
							}
							else {
								fprintf (stderr, "%s: Unrecognized error field %c - skipped\n", list[argno], p[k]);
							}
						}
					}		
				}
			}
			GMT_fclose (fp_e);

			/* Update history */

			(void) time (&now);
			sprintf (history, "%s MGD77_flags added by %s", ctime(&now), In.user);
			k = strlen (history);
			for (i = 0; i < k; i++) if (history[i] == '\n') history[i] = ' ';	/* Remove the \n returned by ctime() */
			history[k++] = '\n';	history[k] = '\0';				/* Add LF at end of line */
			k += strlen (D->H.history);
			D->H.history = (char *)GMT_memory ((void *)D->H.history, k, sizeof (char), GMT_program);
			strcat (D->H.history, history);
			MGD77_nc_status (nc_put_att_text (In.nc_id, NC_GLOBAL, "history", strlen (D->H.history), D->H.history));
		
			if (n_flags) {	/* Add flags to netCDF file */
				if (!D->flags[0]) {	/* We need to define the flags for the first time */
					dims[0] = In.nc_recid;
					MGD77_nc_status (nc_def_var (In.nc_id, "MGD77_flags", NC_INT, 1, dims, &var_id));	/* Define an array variable */
					memset ((void *)answer, 0, BUFSIZ);	/* No default answer */
					strcpy (answer, "MGD77 flags (ON = Bad, OFF = Good) derived from E77 errata");
					MGD77_nc_status (nc_put_att_text   (In.nc_id, var_id, "comment", strlen (answer), answer));
					D->flags[0] = flags;
				}
				else {	/* Merge the existing flags with the new ones */
					for (i = 0; i < D->H.n_records; i++) D->flags[0][i] |= flags[i];
				}
				MGD77_nc_status (nc_enddef (In.nc_id));	/* End define mode. */
				start[0] = 0;
				count[0] = D->H.n_records;
				MGD77_nc_status (nc_put_vara_int (In.nc_id, var_id, start, count, (int *)D->flags[0]));
			}
			else
				MGD77_nc_status (nc_enddef (In.nc_id));	/* End define mode. */
			
			MGD77_Free (D);
			MGD77_Close_File (&In);
			continue;	/* Nothing more to do for this file */
		}
		
		/* Specify the information for the extra column. */
		
		constant = (LEN == 0) ? MGD77_dbl_are_constant (colvalue, D->H.n_records, limits) : MGD77_txt_are_constant (text, D->H.n_records, (int)LEN);	/* Do we need to store 1 or n values? */

		if (column != MGD77_NOT_SET) {	/* Is it possible just to replace the existing column? */
			error = 0;
			if (LEN) {
				if (OLDLEN != LEN) {
					fprintf (stderr, "%s: Revised text column %s differs in width (%d) from the old values (%d.\n", GMT_program, c_abbrev, (int)LEN, (int)OLDLEN);
					error = TRUE;
				}
				if (constant && n_dims == 2) {
					fprintf (stderr, "%s: Revised text column %s is constant whereas old values were in an array\n", GMT_program, c_abbrev);
					error = TRUE;
				}
				if (!constant && n_dims == 1) {
					fprintf (stderr, "%s: Revised text column %s is an array whereas old values is a constant\n", GMT_program, c_abbrev);
					error = TRUE;
				}
			}
			else {
				if (constant && n_dims == 1) {
					fprintf (stderr, "%s: Revised data column %s is constant whereas old values were in an array\n", GMT_program, c_abbrev);
					error = TRUE;
				}
				if (!constant && n_dims == 0) {
					fprintf (stderr, "%s: Revised data column %s is an array whereas old values is a constant\n", GMT_program, c_abbrev);
					error = TRUE;
				}
			}
			if (error) {
				fprintf (stderr, "%s: You must use -D to delete the old information before adding the new information\n", GMT_program);
				continue;
			}
		}
		
		/* OK, here we may either replace an exiting column or add a new one */
		
		if (MGD77_Open_File (list[argno], &In, MGD77_WRITE_MODE)) return (-1);	/* Only creates the full path to the new file */
	
		MGD77_nc_status (nc_open (In.path, NC_WRITE, &In.nc_id));	/* Open the file */
		MGD77_nc_status (nc_redef (In.nc_id));				/* Enter define mode */
		
		dims[0] = In.nc_recid;	dims[1] = LEN;
		start[0] = start[1] = 0;
		count[0] = D->H.n_records;	count[1] = LEN;
		
		if (column == MGD77_NOT_SET) {	/*Adding a new column */
			if (constant) {	/* Simply store one value */
				if (LEN)	/* Text variable */
					MGD77_nc_status (nc_def_var (In.nc_id, c_abbrev, c_nc_type, 1, &dims[1], &var_id));	/* Define a single text variable */
				else
					MGD77_nc_status (nc_def_var (In.nc_id, c_abbrev, c_nc_type, 0, NULL, &var_id));		/* Define a single variable */
			}
			else {	/* Must store array */
				if (LEN)	/* Text variable */
					MGD77_nc_status (nc_def_var (In.nc_id, c_abbrev, c_nc_type, 2, dims, &var_id));		/* Define a 2-D text variable */
				else
					MGD77_nc_status (nc_def_var (In.nc_id, c_abbrev, c_nc_type, 1, dims, &var_id));		/* Define a number array variable */
			}
		}
		else	/* Reuse, get id */
			MGD77_nc_status (nc_inq_varid (In.nc_id, c_abbrev, &var_id));
		
		if (c_name[0]) MGD77_nc_status (nc_put_att_text   (In.nc_id, var_id, "long_name", strlen (c_name), c_name));
		if (c_units[0]) MGD77_nc_status (nc_put_att_text   (In.nc_id, var_id, "units", strlen (c_units), c_units));
		MGD77_nc_status (nc_put_att_double   (In.nc_id, var_id, "actual_range", NC_DOUBLE, 2, limits));
		if (c_comment[0]) MGD77_nc_status (nc_put_att_text   (In.nc_id, var_id, "comment", strlen (c_comment), c_comment));
		MGD77_nc_status (nc_put_att_double (In.nc_id, var_id, "_FillValue", c_nc_type, 1, &MGD77_NaN_val[c_nc_type]));
		MGD77_nc_status (nc_put_att_double (In.nc_id, var_id, "missing_value", c_nc_type, 1, &MGD77_NaN_val[c_nc_type]));
		if (parameters[COL_SCALE]  != 1.0) MGD77_nc_status (nc_put_att_double (In.nc_id, var_id, "scale_factor", NC_DOUBLE, 1, &parameters[COL_SCALE]));
		if (parameters[COL_OFFSET] != 0.0) MGD77_nc_status (nc_put_att_double (In.nc_id, var_id, "add_offset",   NC_DOUBLE, 1, &parameters[COL_OFFSET]));
					
		/* Update history */

		(void) time (&now);
		sprintf (history, "%s Column %s added by %s", ctime(&now), c_abbrev, In.user);
		k = strlen (history);
		for (i = 0; i < k; i++) if (history[i] == '\n') history[i] = ' ';	/* Remove the \n returned by ctime() */
		history[k++] = '\n';	history[k] = '\0';				/* Add LF at end of line */
		k += strlen (D->H.history);
		D->H.history = (char *)GMT_memory ((void *)D->H.history, k, sizeof (char), GMT_program);
		strcat (D->H.history, history);
		MGD77_nc_status (nc_put_att_text (In.nc_id, NC_GLOBAL, "history", strlen (D->H.history), D->H.history));
		
		MGD77_nc_status (nc_enddef (In.nc_id));	/* End define mode.  Now we can write/update data */

		transform = (! (parameters[COL_SCALE] == 1.0 && parameters[COL_OFFSET] == 0.0));	/* TRUE if we must transform before writing */
		n_bad = 0;
		if (constant) {	/* Simply store one value */
			if (LEN)
				MGD77_nc_status (nc_put_vara_schar (In.nc_id, var_id, start, &count[1], (signed char *)text));	/* Just write one text string */
			else {
				n_bad = MGD77_do_scale_offset_before_write (&single_val, colvalue, 1, parameters[COL_SCALE], parameters[COL_OFFSET], c_nc_type);
				MGD77_nc_status (nc_put_var1_double (In.nc_id, var_id, start, &single_val));
			}
		}
		else {	/* Must store array */
			if (LEN)
				MGD77_nc_status (nc_put_vara_schar (In.nc_id, var_id, start, count, (signed char *)text));
			else if (transform) {
				xtmp = (double *) GMT_memory (VNULL, count[0], sizeof (double), GMT_program);
				n_bad = MGD77_do_scale_offset_before_write (xtmp, colvalue, D->H.n_records, parameters[COL_SCALE], parameters[COL_OFFSET], c_nc_type);
				MGD77_nc_status (nc_put_vara_double (In.nc_id, var_id, start, count, xtmp));
				GMT_free ((void *)xtmp);
			}
			else 
				MGD77_nc_status (nc_put_vara_double (In.nc_id, var_id, start, count, colvalue));
		}
		if (n_bad) {	/* Report what we found */
			if (In.verbose_level | 1) fprintf (fp_err, "%s: %s [%s] had %d values outside valid range <%g,%g> for the chosen type (set to NaN = %g)\n",
				GMT_program, In.NGDC_id, c_abbrev, n_bad, MGD77_Low_val[c_nc_type], MGD77_High_val[c_nc_type], MGD77_NaN_val[c_nc_type]);
		}
		
		if (got_e) {
			/* Loop over scale/offset terms and add to netCDF file */
		}
		
		MGD77_Close_File (&In);
		MGD77_Free (D);
	}
	
	if (got_g || got_i) GMT_free ((void *)f);
	if (got_table) GMT_free ((void *)colvalue);
	if (two_cols) GMT_free ((void *)coldnt);
	
	if (gmtdefs.verbose) {
		if (delete)
			fprintf (stderr, "%s: Removed %d data columns from %d MGD77 files\n", GMT_program, n_delete, n_cruises);
		else
			fprintf (stderr, "%s: Sampled data for %d MGD77 files\n", GMT_program, n_cruises);
	}
	
	exit (EXIT_SUCCESS);
}

/* Help functions to decode the -A and -I options */

int decode_A_options (int mode, char *line, char *file, double parameters[])
{
	int error = 0, n;
	char txt_a[GMT_TEXT_LEN], txt_b[GMT_TEXT_LEN];
	
	if (mode == 1) {	/* For *.img files since we need to know data scale and grid mode : fname/scl/mode */
		/* -A[+]i<spacing>/<scale>/<mode>/<filename> */
		n = sscanf (line, "%[^/]/%[^/]/%s", txt_a, txt_b, file);
		if (n != 3) error = 1;
		parameters[IMG_SCALE]   = atof (txt_a);
		parameters[IMG_MODE]    = atof (txt_b);
	}
	else {	/* GMT grid or fable: No data scale and mode to worry about */
		/* -A[+]a|c|d|D|e|g|n|t|T<filename> */
		strcpy (file, line);
	}
	
	return (error);
}

int decode_I_options (char *line, char *abbrev, char *name, char *units, char *size, char *comment, double parameters[])
{	/* -I<abbrev>/<name>/<units>/<size>/<scale>/<offset>/\"comment\" */
	int i = 0, k, pos = 0, error;
	char p[BUFSIZ];
	
	while (i < 7 && GMT_strtok (line, "/", &pos, p)) {	/* Process the 7 items */
		switch (i) {
			case 0:
				strcpy (abbrev, p);
				/* Check abbrev for COARDS compliance */
				for (k = error = 0; abbrev[k]; k++) {
					if (isalpha ((int)abbrev[k])) continue;
					if (isdigit ((int)abbrev[k]) && k > 0) continue;
					if (abbrev[k] == '_' && k > 0) continue;
					error++;
				}
				if (error) {
					fprintf (stderr, "%s: Abbreviation name should only contain letters, digits, and underscores\n", GMT_program);
					return (TRUE);
				}
				break;
			case 1:
				strcpy (name, p);
				break;
			case 2:
				strcpy (units, p);
				break;
			case 3:
				*size = p[0];
				break;
			case 4:
				parameters[COL_SCALE]  = atof (p);
				break;
			case 5:
				parameters[COL_OFFSET]  = atof (p);
				break;
			case 6:
				strcpy (comment, p);
				break;
		}
		i++;
	}
	
	switch (*size) {	/* Given size, set the NC type */
		case 'b':
			parameters[COL_TYPE] = NC_BYTE;
			break;
		case 'd':
			parameters[COL_TYPE] = NC_DOUBLE;
			break;
		case 'f':
			parameters[COL_TYPE] = NC_FLOAT;
			break;
		case 'i':
			parameters[COL_TYPE] = NC_INT;
			break;
		case 's':
			parameters[COL_TYPE] = NC_SHORT;
			break;
		case 't':
			parameters[COL_TYPE] = NC_CHAR;
			break;
		default:
			fprintf (stderr, "%s: Unknown data type flag %c\n", GMT_program, *size);
			parameters[COL_TYPE] = MGD77_NOT_SET;
			break;
	}
	return ((irint (parameters[COL_TYPE]) == MGD77_NOT_SET) || (i != 7));
}

int skip_if_missing (char *name, char *file, struct MGD77_CONTROL *F, struct MGD77_DATASET *D)
{	/* Used when a needed column is not present and we must free memory and goto next file */
	int id;

	if ((id = MGD77_Get_Column (name, F)) == MGD77_NOT_SET) {
		fprintf (stderr, "%s: Cruise %s is missing column %s which is required for selected operation - skipping\n", GMT_program, file, name);
		MGD77_Free (D);	/* Free memory already allocated by MGD77_Read_File for this aborted effort */
	}
	return (id);
}

int got_default_answer (char *line, char *answer)
{
	int i, k, len;
	
	len = strlen(line) - 1;
	memset ((void *)answer, 0, BUFSIZ);	/* No default answer */
	if (line[len] == ']') {	/* Got a default answer for this item */
		for (k = i = len; i && line[i] != '['; i--);
		strncpy (answer, &line[i+1], k - i - 1);
	}
	return (answer[0] != '\0');
}
