/*
 *	$Id: gmt_nan_init.c,v 1.7 2004/05/18 17:29:09 pwessel Exp $
 *
 *	Copyright (c) 1991-2004 by P. Wessel and W. H. F. Smith
 *	See COPYING file for copying and redistribution conditions.
 *
 *	This program is free software; you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License as published by
 *	the Free Software Foundation; version 2 of the License.
 *
 *	This program is distributed in the hope that it will be useful,
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *	GNU General Public License for more details.
 *
 *	Contact info: gmt.soest.hawaii.edu
 *--------------------------------------------------------------------*/
/* gmt_nan_init reads the netcdf file GMT_nan.cdf which contains both
 * single and double precision representations of a non-signaling (quiet)
 * NaN and generates the GMT include file gmt_nan.h
 *
 * This program must be run after netcdf has been installed and before
 * GMT is made since GMT requires the gmt_nan.h file which is machine-
 * dependent.
 *
 * Author:	Paul Wessel & Walter H. F. Smith
 * Date:	30-APR-1998
 * Update:	18-OCT-1999 PW: Added case for no IEEE
 * Version:	3.3.6
 */
 
#include <stdio.h>
#include <stdlib.h>
#include "netcdf.h"

int check_nc_status (int status);

main (int argc, char **argv)
{
	int cdfid;		/* NetCDF file id */
	int f_nan_id;		/* NetCDF variable id for the single-precision NaN */
	int d_nan_id;		/* NetCDF variable id for the double-precision NaN */
	size_t start = 0;	/* Dummy index to first value in array of length 1 */
	unsigned int *i_f_nan;	/* Integer pointer to memory location of f_nan */ 
	unsigned int *i_d_nan;	/* Integer pointer to memory location of d_nan */
	float f_nan;		/* Single-precision NaN */
	double d_nan;		/* Double-precision NaN */
	FILE *fp;		/* File pointer to gmt_nan.h */
	
	/* Open the GMT_nan.cdf file distributed with GMT */

	check_nc_status (nc_open ("GMT_nan.cdf", NC_NOWRITE, &cdfid));

	/* Obtain variable ids */

        check_nc_status (nc_inq_varid (cdfid, "GMT_float_quiet_NaN",  &f_nan_id));
        check_nc_status (nc_inq_varid (cdfid, "GMT_double_quiet_NaN", &d_nan_id));

	/* Read the values of the two NaNs */

        check_nc_status (nc_get_var1_float  (cdfid, f_nan_id, &start, &f_nan));
        check_nc_status (nc_get_var1_double (cdfid, d_nan_id, &start, &d_nan));

	/* Close the netcdf file */

        check_nc_status (nc_close (cdfid));

	/* Set integer pointer to point to the memory locations with the NaNs */

	i_f_nan = (unsigned int *)&f_nan;
	i_d_nan = (unsigned int *)&d_nan;

	/* Report the bit-patterns (in hex notation) to the screen */

#ifdef NO_IEEE
	fprintf (stderr, "gmt_nan_init: No IEEE hardware support - use proxies\n");
	fprintf (stderr, "gmt_nan_init: GMT Float  NaN = %.12lg\n", FLT_MAX);
	fprintf (stderr, "gmt_nan_init: GMT Double NaN = %.12lg\n", DBL_MAX);
#else
	fprintf (stderr, "gmt_nan_init: GMT Float  NaN = 0x%x\n", *i_f_nan);
	fprintf (stderr, "gmt_nan_init: GMT Double NaN = 0x%x, 0x%x\n", i_d_nan[0], i_d_nan[1]);
#endif

	/* Write gmt_nan.h file */

	if ((fp = fopen ("gmt_nan.h", "w")) == NULL) {
		fprintf (stderr, "gmt_nan_init: Could not create gmt_nan.h\n");
		exit (EXIT_FAILURE);
	}

	fprintf (fp, "/*--------------------------------------------------------------------\n");
	fprintf (fp, " *   The GMT-system:	gmt_nan.h	[Automatically Generated]\n *\n");
	fprintf (fp, " *   Copyright (c) 1991-2004 by P. Wessel and W. H. F. Smith\n");
	fprintf (fp, " *   See COPYING file for copying and redistribution conditions.\n *\n");
	fprintf (fp, " *   This program is free software; you can redistribute it and/or modify\n");
	fprintf (fp, " *   it under the terms of the GNU General Public License as published by\n");
	fprintf (fp, " *   the Free Software Foundation; version 2 of the License.\n *\n");
	fprintf (fp, " *   This program is distributed in the hope that it will be useful,\n");
	fprintf (fp, " *   but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
	fprintf (fp, " *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
	fprintf (fp, " *   GNU General Public License for more details.\n *\n");
	fprintf (fp, " *   Contact info: gmt.soest.hawaii.edu\n");
	fprintf (fp, " *--------------------------------------------------------------------*/\n");
	fprintf (fp, "/*\n * Machine-dependent macros for generation of NaNs on this system\n");
	fprintf (fp, " * This file was created by the program gmt_nan_init.c\n */\n\n");
	fprintf (fp, "#ifndef _GMT_NAN_H\n");
	fprintf (fp, "#define _GMT_NAN_H\n");
	fprintf (fp, "#ifdef NO_IEEE\n");
	fprintf (fp, "#define GMT_make_fnan(x) (x = FLT_MAX)\n");
	fprintf (fp, "#else\n");
	fprintf (fp, "#define GMT_make_fnan(x) (((unsigned int *) &x)[0] = 0x%x)\n", *i_f_nan);
	fprintf (fp, "#endif\n");
	fprintf (fp, "#ifdef NO_IEEE\n");
	fprintf (fp, "#define GMT_make_dnan(x) (x = DBL_MAX)\n");
	fprintf (fp, "#else\n");
	fprintf (fp, "#define GMT_make_dnan(x) (((unsigned int *) &x)[0] = 0x%x, ((unsigned int *) &x)[1] = 0x%x)\n\n", i_d_nan[0], i_d_nan[1]);
	fprintf (fp, "#endif\n");
	fprintf (fp, "/* Conditionally define the last resort (poor man's isnan)\n   in case they are not supplied in gmt_math.h */\n\n");
	fprintf (fp, "#ifndef GMT_is_fnan\n");
	fprintf (fp, "#define GMT_is_fnan(x) ((x) != (x))\n");
	fprintf (fp, "#endif\n");
	fprintf (fp, "#ifndef GMT_is_dnan\n");
	fprintf (fp, "#define GMT_is_dnan(x) ((x) != (x))\n");
	fprintf (fp, "#endif\n");
	fprintf (fp, "\n#endif /* _GMT_NAN_H */\n");

	fclose (fp);

	fprintf (stderr, "gmt_nan_init: gmt_nan.h successfully created!\n");

	exit (EXIT_SUCCESS);
}

int check_nc_status (int status)
{
	if (status != NC_NOERR) {
		fprintf (stderr, "gmt_nan_init: %s\n", nc_strerror(status));
		return (-1);
	}
	
	return 0;
}
