/* defgb.h								*/
/*	Supplies constants to defgb package.				*/
/*	Generally, constants are created from user-supplied compiler	*/
/*   -D values and defaults defined somewhere in this file		*/
/*	Some constants are checked for permissible values		*/
/*	Note that "compile-time initialization" can also be done in	*/
/*   the code modules.  Further, run-time initialization can take place	*/
/*   before the system "starts running".  Besides the obvious data	*/
/*   declaration statements, check the init* modules in ioopen_routines	*/

#define DEFGBH_VERSION "defgb.h  version 5.6a  5 Jun 2013"
/*  5 Jun 13.		WJS						*/
/*	Increase MAXREC from 10000 (observed problem w/big dataset)	*/
/*    & tie it loosely to INBUFSIZE					*/
/*		[Begin 5.6a]						*/
/*  5 Jun 13.		WJS						*/
/*	coordinatedmissingdata opt file					*/
/*  3 Jun 13.		WJS						*/
/*	identifymissingdata opt file					*/
/*		[Begin 5.6]						*/
/* 15 Feb 13.		WJS						*/
/*	Fix typo (only 4 mos after making it - got a lot of use in 	*/
/*    those 4 mos, I guess)						*/
/* 18 Oct 12.		WJS						*/
/*	Parametrize output time variable size a bit more		*/
/*		[Begin 5.5c]						*/
/*  8 Oct 12.		WJS						*/
/*	ISO8601 output time stuff					*/
/*		[Begin 5.5b]						*/
/* 18 Apr 10.		WJS						*/
/*	Comment says "max len 26" but code had 24.  Believe comment	*/
/*    (even if it's wrong! (didn't check))				*/
/*  9 Dec 09.		WJS						*/
/*	generated data opt file stuff					*/
/*    v 5.5 actually didn't have anything in it, but got		*/
/*    included in defgb 4.3h, a "temporizing" release			*/
/*		[Begin 5.5a]						*/
/*  6 Aug 09.		WJS						*/
/*	generated data opt file stuff					*/
/*		[Begin 5.5]						*/
/*  8 Nov 08.		WJS						*/
/*	STRIP*BLANKS stuff						*/
/*		[Begin 5.4]						*/
/* 22 May 08.		WJS						*/
/*	DATACOMMENTS_UNKNOWN_FORMAT, DATACOMMENTS_DEF_FORMATTED		*/
/*		[Begin 5.3]						*/
/*	[Move pre-2008 comments to defgb_revision.doc.  9 Dec 09]	*/
/*	[Move pre-2002 comments to defgb_revision.doc. 13 Jun 03]	*/

#include "utils.h"
#include "path_info_routines.h"		/* core.h #include'd here	*/

#define FULL_DEFGBH_VERSION \
 DEFGBH_VERSION"/"FULL_PATH_INFO_ROUTINESH_VERSION"/"FULL_UTILSH_VERSION

#include INNEROPTIONS

#define TRANSVAR_CALL(synonym,variable) \
	transvar((synonym),sizeof((synonym)),(variable))

/*	Characters							*/
/* COMMENT_CHAR			Character in first position of data	*/
/*			    record which indicates that what follows is	*/
/*			    a comment					*/
/* INDIRECT_FILE_CHAR		Prefix character that indicates that	*/
/*			    file name which follows contains name of	*/
/*			    desired file (instead of being that file)	*/
/* LEVEL_CONTINUATION_CHAR 	Character in variable list that indi-	*/
/*			    cates that a new level begins at this point	*/
/* SCRIPT_PARAM_SEP		Character which separates shell script	*/
/* 			    file name from its parameters		*/
/* OMIT_FROM_TAG_CHAR		Character in METHOD_NAME which, if	*/
/*			    present, indicates that it, what follows,	*/
/*			    and any immediately preceding blanks are to	*/
/*			    be omitted from the tag on inserted 	*/
/*			    tags (see diagnostics optional file)	*/
/* OBJECT_PARAM_STRING_SEP	Within a data source string that in-	*/
/*			    dicates a JGOFS object, the character that	*/
/*			    separates parameters within the parameter	*/
/*			    string (if any) of that object		*/
#define COMMENT_CHAR '#'
#define INDIRECT_FILE_CHAR '@'
#define LEVEL_CONTINUATION_CHAR '>'
#define SCRIPT_PARAM_SEP ' '
#define OMIT_FROM_TAG_CHAR '('
#define OBJECT_PARAM_STRING_SEP ','

/*    Strings								*/
/* *_ENTRY_SEPARATORS		Characters which separate consecutive	*/
/*			    entries in an optional file.  Data struc-	*/
/*			    ture has room for a per-option string,	*/
/*			    but in general, the default is used.  If a	*/
/*			    per-option is desired, define it here and	*/
/*			    use it in init code (probably get_files)	*/
/*			    If null, whole record is 1 entry		*/
/*			    If non-null, should share same whitespace	*/
/*			    chars as *ITEM_SEPARATORS, w/ at least 1	*/
/*			    unique non-whitespace char			*/
/* *_SEPARATORS 		Characters which separate items within 	*/
/* 			    entries in an input file.  See *_ENTRY_SEP-	*/
/*			    ARATORS comment above			*/
/* DEFAULT_ENTRY_SEPARATORS	Separators between "pairs" for "common	*/
/*			    format" opt files.  See DEFAULT_ITEM_	*/
/*			    SEPARATORS					*/
/* DEFAULT_ITEM_SEPARATORS	Separators within "pairs" for "common	*/
/*			    format" opt files.  Must be disjoint from	*/
/*			    DEFAULT_ENTRY_SEPARATORS.  Whitespace	*/
/*			    characters go w/innermost parsing unit,	*/
/*			    which is ITEM				*/
/* REMOVAL_SEPARATORS		Separators for removal opt file		*/
/* REQUIRED_SEPARATORS		Characters which must appear in 	*/
/*			    SEPARATORS string (& hence not in data)	*/
/*			    Reason is that rest of system assumes this,	*/
/*			    so we don't want to accept data that will	*/
/*			    be unusable...				*/
/* DEFAULT_SEPARATORS		Default separators for data files	*/
/* DEFAULT_ALT_SEPARATORS	Default alternate separators		*/
/* COMM_TRUNC_IND		String which indicates truncated comment*/
/* OBJECT_PARAM_STRING_DELIM	Within a data source string that in-	*/
/*			    dicates a JGOFS object, the delimiters that	*/
/*			    surround the parameter string of that object*/
/* TAG_DELIM			Characters that surround comment tag	*/
/* DEFAULT_ERR_PREFIX		Default for ERR_PREFIX string		*/
/* NULL_INPUT			String that represents non-existent	*/
/*			    input.  Will provide a "missing value"	*/
/*			    line for such devices, if necessary		*/
/* FLAG_FOR_COLL_FROM_OBJOBJ	String which, if specified, enables	*/
/*			    COLL_FROM_OBJOBJ stuff.  It's looked for in	*/
/*			    optional file and environment, and is put	*/
/*			    into environment.  Needs coordination.	*/
/*			    Uppercased version of this string is used	*/
/*			    as environment variable name		*/
/* DEFAULT_COLL_FROM_OBJOBJ_OBJ	Default for COLL_FROM_OBJOBJ_OBJ.  See	*/
/*			    below					*/
/* DEF_QUOTES		    Quote chars def removed from tokens.  It	*/
/*			    didn't treat quotes the way we do, but if	*/
/*			    the token is properly quoted, behavior will	*/
/*			    be the same.  Some of the special treatment	*/
/*			    of tokens surrounded by these quotes	*/
/*			    happens in outer, which doesn't use this	*/
/*			    parametrization				*/
/* UNPRINT_REPL_CHARS	    Characters that can be used to replace un-	*/
/*			    printable characters in error messages	*/
/*			    Order generally determines which char gets	*/
/*			    used.  Repeats at end are for those deter-	*/
/*			    minations that pick the "last OK" char in-	*/
/*			    stead of the "first OK" char		*/
#define DEFAULT_ENTRY_SEPARATORS ";"
#define DEFAULT_ITEM_SEPARATORS "=\n \t"
#define REMOVAL_SEPARATORS "\n,; \t"
#define REQUIRED_SEPARATORS "\n\t"
#define DEFAULT_SEPARATORS "\n ,\r\t"
#define DEFAULT_ALT_SEPARATORS "\'\'"
#define COMM_TRUNC_IND " ..."
#define OBJECT_PARAM_STRING_DELIM "()"
#define TAG_DELIM "{}"
#define DEFAULT_ERR_PREFIX JGOFS_ERR_PREFIX	/* Defined in core.h	*/
#define NULL_INPUT NULL_DEVICE			/* Defined in core.h	*/
#define FLAG_FOR_COLL_FROM_OBJOBJ "varname_for_level1_specs"
#define DEFAULT_COLL_FROM_OBJOBJ_OBJ "/list_level1_specs"
#define DEF_QUOTES "\"\""
#define UNPRINT_REPL_CHARS "?@#$&*%!|~^#@?"
/*	Configurable strings-see defgb.h.  Default values come from	*/
/*	this file							*/
/* ERR_PREFIX								*/
/* ALT_SEPARATORS							*/
/* SEPARATORS								*/
/* COLL_FROM_OBJOBJ_OBJ 						*/

  /*  Next statement defines default order of optional file types in  	*/
  /*    indirect input file						*/
  /*  Descriptors are put into place at runtime in init_file_structs,	*/
  /*    among other places.						*/
  /*  Do not change the values of these, since it could break indirect	*/
  /*    files that do not keyword their entries				*/
  /*  Don't know how to parametrize so max value of defines gets to be	*/
  /*    size of array.  						*/
#define DATAFILE 0
#define TRANSVAR 1
#define INPWIDTHS 2
#define REMOVALS 3
#define TIMEDATEPARAMS 4
#define DIAGNOSTICS 5
#define LATLONPARAMS 6
#define DATAFIELDOPTS 7
#define DISPWIDTHS 8
#define VARLIST 9
#define VARLISTOPTS 10
#define DATACOMMENTS 11
#define COMMENTSOURCE 12
#define IDMISSING 13
#define COORDMISSING 14
#define GENERATEDDATA 15
#define NFILETYPES 16

/************************************************************************/
/*		Datafield options					*/
    /*  Table contains the 5 keywords (max size 46), 3 TRUE/FALSEs,	*/
    /*  2 separator strings (for convenience, use same size as FALSE;	*/
    /*  namely, 5) and, for each keyword/variable pair, 2 separators	*/
    /*	and a blank							*/
#define NUM_DATAFIELDOPTS 5
#define DATAFIELDOPTS_WJSTBL NUM_DATAFIELDOPTS*(46 + 5 + 2 +1)

/************************************************************************/
/*		Time/date options					*/

  /*  Next 2 kind of arbitrary.  With my luck I'll live until 2100...	*/
#define YEAR_MIN 1800
#define YEAR_MAX 2100

  /*  Defining minimum as 1800 avoids the gross calendar changes of	*/
  /*  earlier times, and also gives seconds-since-year a fighting	*/
  /*  of fitting into an unsigned 32 bit integer (although we don't	*/
  /*  calculate it as an integer).					*/
#define MINIMUM_JULIAN_BASE_YEAR 1800
#define DEFAULT_JULIAN_BASE_YEAR 1970

  /*  Pick next flag carefully.  For example, -1 cannot be used since	*/
  /*  is a valid time offset.  Fragments can have this flag for far	*/
  /*  more reasons than their input is missing				*/
#define MISSING_TIME_FLAG -9999

struct cumtime {
    /*  Save latest time/date info that passes through calc_timedate.	*/
    /*  It may save calculations.  Code must check that this info is	*/
    /*  applicable to the calculations, however ... mostly done while	*/
    /*  setting up in get_timedateparams				*/
    /*  I suspect that as of v 1.1, these variables (except		*/
    /*  leapyear) could be replaced with outtime[x_FRAG].val, but this	*/
    /*  seems to work...						*/
    /*	  Leap year info is all we want.  However, need to know if	*/
    /*	  saved leap year is valid; hence save year as flag.  While	*/
    /*    we're at it, we use saved year to avoid leap year recalc.	*/
    /*    year is init'ed in init_time_structs				*/
  int year;
    /*	Process Julian day exactly once and save results in month & day	*/
    /*	Whichever output (day or month) occurs first does calculation;	*/
    /*	the other output just copies the saved value			*/
    /*	Ditto for 24-hour time						*/
  int month,day;
  int hour,minute;
    /*  Save pieces of HHMM time displacement for time zone conversion	*/
  int hours_offset,minutes_offset;
  Logical leapyear;
};

  /*		fraction stuff						*/
struct timefrac {
  double frac;		/*  0 <= frac < 1.  Contents are described by	*/
			/*  fractype; vary as we go along		*/
  int julday;		/*  Fractional year input immediately changed	*/
			/*  into this, so that processing fractional	*/
			/*  years is exactly processing the appropriate	*/
			/*  # of julian days				*/
  int fracdigits;	/*  Starts out as number of significant digits	*/
			/*  in fractional part of input string.  Used	*/
			/*  in output of minutes and/or seconds data	*/
			/*  (guess it should be one or other!), so is	*/
			/*  modified w/o changing its variable name	*/
  Logical frac_missing;	/*  Flag for datum in a particular input record	*/
  Logical fracyear;	/*  Set if frac year fragment type is one of	*/
			/*  the several fractional year types.		*/
  char fractype;	/*  Type of data in frac variable		*/
};

  /* wjstbl-format strings for recognized time zone abbreviations with	*/
  /* their displacements.  Displacement is from UTC (which, when added	*/
  /* to UTC, gives the local time).  Takes HH or HHMM format; leading + */
  /* optional, as are leading zeros.					*/
  /* Need separate table for DST since DST zone name conflicts with 	*/
  /* other possible DST input						*/
#define TZTBL \
	"/PST/-8 /MST/-7 /CST/-6 /EST/-5 /AST/-4 /NST/-0330 /GMT/0 /UTC/0 "
#define TZDSTTBL \
	"/PDT/-7 /MDT/-6 /CDT/-5 /EDT/-4 /ADT/-3 /NDT/-0230 "

#define NUM_OUTTIMES 10
  /*  Sequence stuff refers to how time (and latlon) keywords are 	*/
  /*  grouped; to wit, given keyword "X", the first instance of X is	*/
  /*  named prefix_tag1_X.  The 2nd instance is prefix_tag2_X, etc	*/
  /*  Applying "sequence" to this is misleading.  It comes from the	*/
  /*  limitation that tagN must be a small integer; ie, we started by	*/
  /*  demanding that tag1=1, tag2=2, etc.  However, the ordering was	*/
  /*  relaxed.  The requirement that tagN be an integer made parsing	*/
  /*  easier since the underscores are optional (original code did not	*/
  /*  not allow them, in fact).  We can just put strtol on tagN to get	*/
  /*  no matter how it ends						*/
#define MAXLEN_SEQUENCE_TAG 3	/*  Also applies to latlon sequencing	*/
  /*  Change TIMEDATE_WJSTBL if lengths of next 2 change		*/
#define TIMEDATE_SEQUENCE_PREFIX "time"
#define TIMEDATE_INPUT_KEYWORD_PREFIX "invar"

    /*  Types of time/date data fragments				*/
#define YEAR_FRAG 0
#define MONTH_FRAG 1
#define DAY_FRAG 2
#define YEARMONTHDAY_FRAG 3
#define ISO8601_FRAG 4
#define HOUR_FRAG 5
#define TIME_OFFSET_FRAG 6
#define JULIAN_FRAG 7
#define NUM_OUTTIME_VARIABLES 8	/* = # frags above			*/
#define MINUTE_FRAG 8
#define SECOND_FRAG 9
#define FRACTION_FRAG 10
#define DST_FRAG 11
#define AMPM_FRAG 12
#define NUM_TIMEDATE_FRAGS 13	/* Count.  keep = last frag + 1		*/
    /*  We use _FRAG in the case part of switch statements.  Therefore	*/
#if NUM_TIMEDATE_FRAGS > 255
#error "NUM_TIMEDATE_FRAGS does not fit in a byte"
#endif


    /*  A single valid format could theoretically specify every output	*/
    /*  time variable as well as skip an arbitrary number of fields, as	*/
    /*  well has have an arbitrary number of punctuation characters.	*/
    /*  We also stick a %1s (length 3) on the end of each input format	*/
    /*  to check for extra characters in an input field			*/
    /*  A single format conversion specifier can be as big as 21	*/
    /*  (%*99[A-Z,a-z,0-9,+,-]  see code).				*/
    /*  Allow for as many skipped fields as valid ones, and		*/
    /*  15 punctuation characters.  We do NOT check overflow for this	*/
    /*  buffer in the code (since we build it char by char), so it's	*/
    /*  grossly oversized...						*/
#define MAXLEN_TIMEDATE_INPFORMAT 3 + (2 * NUM_OUTTIME_VARIABLES * 21) + 15

    /*  Allow for hhmm.mmmmm, which should be enough precision		*/
    /*  This is well-named, but was being used for the fragbuf size.	*/
    /*    fragbufs hold input data, not output data.  Sigh		*/
    /*  Idea that MAXLEN_OUTTIME is function of single-field precision	*/
    /*    may have ignored yearmonthday format, which happens to indeed	*/
    /*    have a length < hhmm.mmmmm.  However, ISO8601 format produces	*/
    /*    a bigger string; to wit, YYYY-MM-DDTHH:MM:SS.SSZ.  General	*/
    /*    format allows for +HH:MM time displacement instead of Z and	*/
    /*    doesn't limit precision of seconds.  We'll add some just in	*/
    /*    in case							*/ 
#define MAX_OUTTIME_PRECISION 5  
#define MAXLEN_HRMIN_OUTTIME 2 + 2 + 1 + MAX_OUTTIME_PRECISION
#define ISO8601_SECONDS_SLOP 10	/*  Decimal seconds plus arbitrary	*/
#define MAXLEN_ISO8601_STRING	\
	4 + 1  +  2 + 1  +  2	\
		+   1   +  	\
	2 + 1  +  2 + 1  +  2 + 1 + ISO8601_SECONDS_SLOP \
		+   1   +	\
	2 + 1  +  2
#if MAXLEN_HRMIN_OUTTIME > MAXLEN_ISO8601_STRING
#define MAXLEN_OUTTIME_VARIABLE MAXLEN_HRMIN_OUTTIME
#else
#define MAXLEN_OUTTIME_VARIABLE MAXLEN_ISO8601_STRING
#endif


struct intime {
  int var;		/* Input variable w/time info			*/
  int fragbuf_index;	/*     Index into vector of length numfrags.	*/
			/* Each vector element is a pointer to a buffer	*/
			/* that will hold a fragment.  Buffers are in	*/
			/* order that the fragments appear in this	*/
			/* input variable				*/
  int nstrings;		/* Number of substrings in input variable	*/
  int nfrags_in_substring;
			/* 	If nstrings = 1, how many frags does it	*/
			/* contain?  At present, at most 2 (the 2nd	*/
			/* being the decimal portion of int portion.)	*/
			/* 	Also a flag for whether input template	*/
			/* is widthless (0 = no; >0 = yes)		*/
  char format[MAXLEN_TIMEDATE_INPFORMAT+1]; /* sscanf format string	*/
			/* that gets substrings from variable.		*/
};

  /*  Add offset to utc to get local... that's how whole program is	*/
  /*  supposed to work!							*/
#define CONVERT_LOCAL_TO_UTC 1
#define NO_TIME_ZONE_CONVERSION 0
#define CONVERT_UTC_TO_LOCAL -1

  /*  Indicate result of conversion, as well as input convention if	*/
  /*  no conversion is getting performed				*/
#define OUTPUT_IS_UTC 1
#define OUTPUT_IS_LOCAL 0

  /*  Special outtime.source_field_types.  Used as flags, etc		*/
#define JULIAN_SOURCES '*'
#define MULTIFIELD_OUTTIME_SOURCES '&'

  /*  Special values for data that are variable numbers			*/
  /*    Must not be valid variable indices, which are 0 <= index < NVAR	*/
  /*    Keep OUTPUT_NOT_REQUESTED & INPUT_NOT_SUPPLIED at -1; they	*/
  /*	  were hardcoded that way.					*/
  /*    Be wary about using #s below -1, in case there was code that	*/
  /*    said "<0 means not requested"					*/
  /*	Don't know if anything uses NVAR for a boundary, etc		*/
#define INPUT_NOT_SUPPLIED -1
#define OUTPUT_NOT_REQUESTED -1
#define TIME_INTERNAL_USE NVAR+1

struct outtime {
  int var;		/* Output time/date variable that will include	*/
			/*   this fragment. Can take on special values	*/
			/*   (up to this .h file to be sure they are	*/
			/*   special)					*/
			/*   OUTPUT_NOT_REQUESTED structure not in use	*/
			/*   TIME_INTERNAL_USE = structure for internal	*/
			/*     use; calculate but do not return to user	*/
  int lev;		/* Level on which var occurs			*/
  int intime_index;	/* Index of intime structure describing		*/
			/*   input variable from which fragment comes	*/
  int val;		/* Temp buffer for values of this fragment as	*/
			/*   we do processing				*/
  int max;		/* Maximum value for this fragment.  Fixed for	*/
			/*   some fragments, variable for others...	*/
			/*   Largest permissible value for some frags,	*/
			/*   smallest impermissible value for others...	*/
  int baseyear;		/* For julian days-since-base-year format	*/
			/*   Seems like a waste to have it in all out-	*/
			/*   time structures, but user could change it	*/
			/*   per outtime variable...			*/
  char *var_type;	/* Name of output variable (not fragment)	*/
			/*   corresponding to this structure		*/
  char *fmt;		/* Output format for this fragment		*/
			/*   Set in init_time_structs			*/
  char fragbuf[DATUMSIZE+1]; 		/* Fragment buffer		*/
  char source_field_type[1+1];		/* Kind of field fragment	*/
			/* was derived from.  Used as flag telling if	*/
			/* fragment found & in error msg if found twice */
			/* String for err msg convenience		*/
  signed char conv;	/* Output conversion info.  Meaning depends on	*/
			/* structure.					*/
			/*  For HOUR (representing hr/min/sec),		*/
			/* indicates UTC/local conversion.		*/
			/*  For JULIAN, it's a template letter indica-	*/
			/* ting the type of julian output.  See tem-	*/
			/* plate documentation or code			*/
			/*  For ISO8601, indicates if output is UTC	*/
};

/************************************************************************/
/*		Lat/lon structure					*/
#define NUM_LATLON 10
#define MAXLATLONFORMATSIZE 10
  /*  If next string changes, change LATLON_WJSTBL. 			*/
#define LATLON_SEQUENCE_PREFIX "latlon"
#define DEFAULT_LATLONSEP ' '
#define DEFAULT_LATLONFORMAT "decdeg"
  /*  Upcase direction that defaults to positive is 1st char of nxt 2	*/
#define LEGAL_LATCARDINALS "NnSs"
#define LEGAL_LONCARDINALS "EeWw"
struct latlonformat {
  int var;
  char *legal_cardinal;
  char sep[2];
  char format[MAXLATLONFORMATSIZE+1];
  char convention;
};

/************************************************************************/
/*		Output options						*/

  /*  Parametrize various output levels					*/
  /*    Error output levels						*/
#define NOERROR_OUTPUT 0
#define ERROR_MESSAGE 10
#define ID_INNER 20
#define ID_SESSION 25
#define ID_PROBLEM_FILE 50
#define GET_MORE_FROM_SCRIPT 60
#define ID_ALL_OPEN_FILES 80
  /*    Trace output levels						*/
#define NOTRACE 0
#define TRACE_IOOPEN 10
#define DUMP_ENVIRONMENT 13
#define TRACE_OPTFILE_ROUTINES 20
#define TRACE_PERFILE_ROUTINES 40
#define TRACE_COMMENTS 50
#define TRACE_IOREADREC 70


  /*  Comments sent to ADD_TO_BUFFER_FILE won't go there directly-they	*/
  /*  will be buffered until outer wants them.				*/
#define ADD_TO_BUFFER_FILE STDOUT_NAME

  /*  By default, errors are sent to outer, which takes care of things	*/
  /*  like setting up html environment or issuing JGOFS protocol prefix	*/
  /*  if necessary.  We need to buffer messages sent to outer's sink	*/
  /*  rather than writing them ourselves				*/
#define JGOFS_ERROR_FILE STDOUT_NAME
  /*  Errors in dealing w/sinks go to error sink.  Define where we will	*/
  /*  send messages about errors w/error sink itself.			*/
  /*  If sink changes, stream may have to be opened in the code		*/
#define ULTIMATE_ERROR_STREAM stderr
  /*  Define where to send primary sinks if user spec's duplicate sink	*/
#define PRIMARY_DEBUG_FILE STDERR_NAME 
#define PRIMARY_ERROR_FILE JGOFS_ERROR_FILE

  /*	Characteristics of outinfo structure				*/
#define DATA_COMMENT_SINK 0
#define NON_DATA_COMMENT_SINK 1
#define ERROR_SINK 2
#define DIAG_SINK 3
#define NUM_USER_SPECIFIABLE_SINKS 4  /* Subcount.  User can spec	*/
				/* sinks above here, but not below	*/
#define PRIMARY_ERROR_SINK 4
#define PRIMARY_DIAG_SINK 5
#define NUM_SINKS 6		/* Count.  keep = last sink + 1		*/

#define NUM_DIAG_FLAGS 3	/* inserted_comments, *comment_id	*/
#define NUM_DIAG_LEVELS 2	/* trace_ & error_			*/
#define NUM_EXTRA_DIAG_SOURCES 1  /* maxscriptdiags			*/
 /* Each level has a counter and a addl- counter which user can spec	*/
 /* So does each extra diag source					*/
 /* There is one counter per opt file, iovalstr, iovalreal, and they	*/
 /*   all have an addl- version						*/
#define NUM_DIAG_COUNTERS 2*(NUM_DIAG_LEVELS + NUM_EXTRA_DIAG_SOURCES + \
      NFILETYPES + 2)
 /* Number of things user can specify.					*/
#define NUM_DIAG_KEYWORDS NUM_SINKS + NUM_DIAG_FLAGS + NUM_DIAG_COUNTERS
 /* Size the table.  Max keyword size of 18 comes from doc (must be	*/
 /* maxed w/ biggest descriptor string); +12 is for biggest prefix/	*/
 /* suffix we add ("print__lines" at the moment), +5 is for		*/
 /* addl-; max file size of 40 a punt; max flag value is false-hence	*/
 /* size 5; allow 4 digit counters/levels				*/
#define DIAGS_WJSTBL 40*NUM_SINKS + 5*NUM_DIAG_FLAGS + 4*NUM_DIAG_COUNTERS + \
		     (18+12+5)*NUM_DIAG_KEYWORDS

  /*  Control of how much non-def data is generated, and where it goes	*/
  /*  Structure is filled in in configure_output.  Some defaults are	*/
  /*  hardcoded; some default to values in this file (some of which, in	*/
  /*  turn, can be specified at compile time by the user)		*/
  /*  All _sink strings may be file specifications (including /dev/null	*/
  /*  /dev/stdout or /dev/stderr (latter 2 may be used even if they are	*/
  /*  not defined on a system)).					*/
  /*  Use Logical instead of unsigned int since we want to have 	*/
  /*  pointers to some of the flags					*/
struct outfile {
  Logical *open_ptr;	/*  Will point to one of outsink_open_flags	*/
  FILE **stream_ptr;	/*  Will point to one of outsink_streams[i]	*/
  char **mode_ptr;	/*  Will point to one of outsink_modes		*/
  char *sink;		/*  Will end up non-null.  Expect ptr to 	*/
			/*   /dev/null if people want to chuck stuff;	*/
			/*    will write to /dev/null.  Will skip writ-	*/
			/*     ing if (somehow) 0 len string gets in	*/
  char *descrip;
  struct stat fileinfo;
  Logical processed;	/*  For help during input to protect agnst user	*/
			/*   spec'ing sink > once			*/
  Logical dup;
};
struct outinfo {
    /*  defgb can generate information at the beginning of the main	*/
    /*  comment stream.  The next items allow specification of where	*/
    /*  this data should go, and what it should consist of		*/
  struct outfile file[NUM_SINKS];
  Logical outsink_open_flags[NUM_SINKS];
  FILE *outsink_streams[NUM_SINKS];
  char *outsink_modes[NUM_SINKS];	/* Append or new file		*/
  Logical inserted_comments;		/* Insert lines identfying opt	*/
					/* file & indirect file sources	*/
  Logical inserted_comment_id; 		/* Tag inserted lines with name	*/
					/* of opt file routine		*/
					/* generating line		*/
  Logical opt_file_comment_id;		/* Tag comment lines from opt	*/
					/* files with name of opt file 	*/
					/* routine reading line		*/
    /*  Debugging stuff.  Includes original DEBUG & DEBUG0 output	*/
    /*  Input data dump numbers in fileinfo structure			*/
  int trace_level;	/* Level of output to primary sink		*/
  int dup_trace_level;	/* Level of output to duplicate sink		*/
  int iovalstr;		/* Dump every 'iovalstr'th call to iovalstr	*/
  int iovalreal;	/*	      'iovalreal'th call to iovaldouble	*/
			/*  (or iovalreal - 1 or other is called)	*/
  int dup_iovalstr;	/* Dump every 'dup_iovalstr'th call to iovalstr	*/
			/*  to dup diag sink				*/
  int dup_iovalreal;	/* Dump every 'dup_iovalreal'th call to		*/
			/*  iovaldouble (or iovalreal) to dup diag sink	*/
  int n_iovalstrs;	/* Count of calls to iovalstr			*/
  int n_iovalreals;	/*		     iovaldouble (iovalreal)	*/
    /*  How much error stuff 						*/
  int error_level;		/* Level of output to primary sink	*/
  int dup_error_level;		/* Level of output to duplicate sink	*/
  int maxscriptdiags;		/* # of "extra" script msgs to primary	*/
				/*   sink				*/
};
/****								     ****/
/***************   end defgb_nonconfigurable.h   ************************/

/* ERR_PREFIX			String which, if found at the beginning	*/
/*			    of any data record, indicates that record	*/
/*			    is actually an error message		*/
#ifndef ERR_PREFIX
#define ERR_PREFIX DEFAULT_ERR_PREFIX
#endif

/* COLL_FROM_OBJOBJ_OBJ		Name of object which implements "coll-	*/
/*			    ection from object of objects" feature	*/
/*			    (with punctuation).  Note that it must be	*/
/*			    in the same place on all remote nodes.  See	*/
/*			    varlistopts in param1.doc			*/
#ifndef COLL_FROM_OBJOBJ_OBJ
#define COLL_FROM_OBJOBJ_OBJ DEFAULT_COLL_FROM_OBJOBJ_OBJ		
#endif

  /*  Used to allow METHOD & METHOD_PROTOTYPE as compilation switches	*/
  /*  When those became obsolete (see "switches" doc, issued diagnostic	*/
  /*  now (defgb.h v 4.3) ... too bad if spec'd; they're ignored	*/
#define METHOD DEFGB
#define DEFAULT_METHOD_NAME "defgb"

#ifndef METHOD_NAME
#define METHOD_NAME DEFAULT_METHOD_NAME
#endif
/*********								*/

/*  _OPT switches allow control of optional capabilities spec'd via     */
/*  the indirect parameter file.  The default value of 0 allows 	*/
/*  or disallows capability based on whether or not the relevant file	*/
/*  is provided in the parameter file.  If _OPT is positive, relevant	*/
/*  file MUST be provided in the parameter file.  If _OPT is negative,	*/
/*  file must NOT be provided in parameter file.			*/
#ifndef TRANS_OPT
#define TRANS_OPT 0
#endif
#ifndef INPWIDTH_OPT
#define INPWIDTH_OPT 0
#endif
#ifndef REMOVAL_OPT
#define REMOVAL_OPT 0
#endif
#ifndef TIMEDATE_OPT
#define TIMEDATE_OPT 0
#endif
#ifndef LATLON_OPT
#define LATLON_OPT 0
#endif
#ifndef DATAFIELDOPTS_OPT
#define DATAFIELDOPTS_OPT 0
#endif
#ifndef DISPWIDTH_OPT
#define DISPWIDTH_OPT 0
#endif
#ifndef VARLIST_OPT
#define VARLIST_OPT 0
#endif
#ifndef VARLISTOPTS_OPT
#define VARLISTOPTS_OPT 0
#endif
#ifndef DATACOMMENTS_OPT
#define DATACOMMENTS_OPT 0
#endif
#ifndef IDMISSING_OPT
#define IDMISSING_OPT 0
#endif
#ifndef COORDMISSING_OPT
#define COORDMISSING_OPT 0
#endif

/*	No DIAGS_OPT -can't see purpose of it				*/

#ifndef READ_COMMANDS	/* Compile w/EXEC capability.  Saying NO allows	*/
			/*  defgb use where startchild not written	*/
#define READ_COMMANDS TRUE
#endif

#ifndef READ_OBJECTS	/* Allow use of JGOFS objects as input.  Saying	*/
			/* NO allows defgb use where jdb routines (or	*/
			/* the http libs they use) not available	*/
#define READ_OBJECTS TRUE
#endif

#ifndef OPTIMIZE_OBJECT_TRANSFER
#define OPTIMIZE_OBJECT_TRANSFER READ_OBJECTS
#endif
  /*  No sense to optimize object stuff when method won't read objects	*/
  /*  Be sure we don't try to compile in jdb stuff in this case		*/
#if OPTIMIZE_OBJECT_TRANSFER
#if ! READ_OBJECTS
#undef OPTIMIZE_OBJECT_TRANSFER
#define OPTIMIZE_OBJECT_TRANSFER FALSE
#endif
#endif

#ifndef TOKEN 
#define TOKEN 240
#endif
#if TOKEN < MAXLEN_OUTTIME_VARIABLE
#undef TOKEN
#define TOKEN MAXLEN_OUTTIME_VARIABLE
#endif

#ifndef NVAR 
#define NVAR 250
#endif

  /*  COMMENTLINE, VARNAMESIZE from default.h.  We had called them max	*/
  /*    "since the start" 						*/
  /*  COMMENTLINE does not include # or \n				*/
#define MAXCOMMENTLINE COMMENTLINE
#define MAXVARNAMESIZE VARNAMESIZE

#ifndef DISPLAY_WIDTH		/* To right-justify inserted comments,	*/
#define DISPLAY_WIDTH 80	/*  need to know rightmost column.  In	*/
#endif				/*   html mode, outer inserts a hash &	*/
#define LENGTH_OUTER_DISPLAY_PREFIX 2  /* a blank before each comment	*/
#define EFFECTIVE_DISPLAY_WIDTH DISPLAY_WIDTH-LENGTH_OUTER_DISPLAY_PREFIX

#ifndef COMMENTSIZE 
#define COMMENTSIZE 2430
/*	Note that as of defgb 3.8a, comment buffer is dynamically	*/
/*	allocated, and this is just the "chunk" size.  (jdb, however,	*/
/*	has a static buffer, presumably of this size (coming from	*/
/*	"include OPTIONS" - OPTIONS being spec'ed on compilation line))	*/
/*	(jdb 1.2 allocates comment buffer dynamically also)		*/
#endif

/*	MAXREC originally 1257.  No particular reason for this value	*/
/*	according to Glenn 3 Dec 96					*/
/*  Apr 16 - not sure where MAXREC was originally used.  It's not in	*/
/*  def, for example.  In 1998, it was raised to 10000 w/only the	*/
/*  above (OK, I didn't try to correlate things w/1998 comments in all	*/
/*  sources).								*/
/*	From defgb's perspective, MAXREC is "the" buffer size for each	*/
/*  input file, required and optional (unless defgb knows that a small-	*/
/*  er buffer will do.  The most obvious thing it limits is the size of	*/
/*  a def-formatted input record.  However it also limits, for example,	*/
/*  the size of a varlist record (I think - I didn't check.  The prin-	*/
/*  ciple is the thing here).  It has nothing to do with INBUFSIZE	*/
/*  which is max size rec that the jdb routines will read when they	*/
/*  an object.								*/
/*	From a system build perspective, though, installers are allowed	*/
/*  to fiddle with INBUFSIZE (via inner.h) and presumably not supposed	*/
/*  to fiddle with this file (and they certainly won't WANT to fiddle	*/
/*  with the make file).  When their data gets bigger, they increase	*/
/*  INBUFSIZE and hope.  So, using INBUFSIZE if it gets big might help	*/
/*  Further, there IS some justification in linking the 2.  If defgb	*/
/*  is reading from an object, presumably it reads from jdbread and	*/
/*  stores in a buffer whose size is controlled by MAXREC ...		*/
#ifndef MAXREC
#define DEFAULT_MAXREC 15000

#ifdef INBUFSIZE

#if INBUFSIZE > DEFAULT_MAXREC
#define MAXREC INBUFSIZE
#else
#define MAXREC DEFAULT_MAXREC
#endif

#else

#define MAXREC DEFAULT_MAXREC

#endif

#endif

/*	Lists that contain input from various opt files			*/
#ifndef TRANS_LIST
#define TRANS_LIST 10000
#endif
#ifndef VAR_DATA_WIDTHS
#define VAR_DATA_WIDTHS 1000
#endif
#ifndef DISP_DATA_WIDTHS
#define DISP_DATA_WIDTHS 1000
#endif

/*	Params below define differences from defw.  Allow these to be	*/
/*	set on compile line						*/
/*	To enable fixed-format input, specify an inpwidths file in an	*/
/*	indirect input file (see doc)					*/

#ifdef SEPARATOR	    /* See also doc for fileinfo struct		*/
#define SEPARATORS SEPARATOR
#else
#define SEPARATORS DEFAULT_SEPARATORS
#endif

  /*  Allow separators within fields by delimiting them with		*/
  /*  separator characters						*/
#ifdef ALT_SEPARATOR
#define ALT_SEPARATORS ALT_SEPARATOR
#else
#define ALT_SEPARATORS DEFAULT_ALT_SEPARATORS
#endif
  /*  If set, consecutive SEPARATORS characters mean empty fields	*/
  /*  This applies only to free field data; not variable lists, and not	*/
  /*    to any subfile field following the data				*/
#ifndef SIGNIFICANT_CONSECUTIVE_SEPARATORS
#define SIGNIFICANT_CONSECUTIVE_SEPARATORS FALSE
#endif
  /*  In fixed fields, does an embedded separator mean 2 fields and,	*/
  /*  therefore, an error?						*/
#ifndef SIGNIFICANT_EMBEDDED_SEPARATORS
#define SIGNIFICANT_EMBEDDED_SEPARATORS TRUE
#endif
  /*  Historical info about next set of params:				*/
  /*  iovalstr__, copied from def, stripped leading blanks.  The rest	*/
  /*  of defgb didn't care (as long as blanks weren't separators).	*/
  /*  This meant  1) As far as outer was concerned, STRIP_LEADING was	*/
  /*  TRUE and STRIP_TRAILING was false  2) As far as internal defgb	*/
  /*  use of the data was concerned (eg, in a time transform), STRIP_	*/
  /*  LEADING and STRIP_TRAILING were both false 3) As far as outer	*/
  /*  was concerned, it could get an empty string			*/
#ifndef STRIP_LEADING_BLANKS
#define STRIP_LEADING_BLANKS TRUE
#endif
#ifndef STRIP_TRAILING_BLANKS
#define STRIP_TRAILING_BLANKS FALSE
#endif
#define TREAT_ALL_BLANK_STRINGS_AS_MISSING 1
#define TREAT_ALL_BLANK_STRINGS_AS_SINGLE_BLANK 2
#ifndef TREAT_ALL_BLANK_STRINGS_DEFAULT
#define TREAT_ALL_BLANK_STRINGS_DEFAULT TREAT_ALL_BLANK_STRINGS_AS_MISSING
#endif

  /*  What character represents a field to skip in a time/date template	*/
#ifndef TIMEDATE_SKIPFIELD_CHAR 
#define TIMEDATE_SKIPFIELD_CHAR '*'
#endif
  /*  Character interpreted by SSCANF to mean "skip this field"		*/
#define SSCANF_SKIPFIELD_CHAR '*'

  /*  Are there variable lists in with the data files or not?		*/
#define MIN_VARLISTS_END -2
  /*  Next value can be any illegal varlists_end value			*/
#define NO_VARLISTS_END_SPECIFIED MIN_VARLISTS_END-1
#ifndef VARLISTS_END	/* Last level w/ variable lists			*/
			/*   0 = traditional defgb_noheader (level 0	*/
			/*      has list; rest don't)			*/
			/*  -1 would be no data files w/lists (must	*/
			/*	spec varlist opt!)			*/
			/*  -2 means all levels have list		*/
			/*  Any positive # OK, too, if they want...	*/
#define VARLISTS_END -2
#endif

/************************************************************************/
/*  Compile-time configurable portions of indirect input files		*/
/*  (should be possible to specify all of these at runtime, too -see	*/
/*  runtime doc)							*/
/*  Also see init* modules in ioopen_routines to see how these values	*/
/*  get applied to the actual data structures.				*/

/*		Output options						*/
  /*    Set up default.  Can be overridden at runtime via diagnostics	*/
  /*	opt file.  Final value set in configure_output			*/
#ifndef DEFAULT_ERROR_LEVEL
#define DEFAULT_ERROR_LEVEL GET_MORE_FROM_SCRIPT
#endif
#ifndef DEFAULT_MAXSCRIPTDIAGS
#define DEFAULT_MAXSCRIPTDIAGS 5
#endif

  /*    Set up default trace level.  Can be overridden at runtime via   */
  /*	diagnostics opt file.  Final value set in configure_output	*/
#ifndef DEFAULT_TRACE_LEVEL
#ifdef DEBUG			/*  Compatibility w/older inners	*/
#define DEFAULT_TRACE_LEVEL TRACE_PERFILE_ROUTINES
#else
#define DEFAULT_TRACE_LEVEL NOTRACE
#endif
#endif
  /*	Data trace default (compatibility w/older inners)		*/
#ifdef DEBUG0
#define DEFAULT_DATA_TRACE 1
#else
#define DEFAULT_DATA_TRACE 0
#endif
  /*  User-changeable default sinks-since there are some messages	*/
  /*  generated before diags get set up.  Note that comments generated	*/
  /*  before the comment sinks are set up are buffered, so we just	*/
  /*  reprocess them from the buffer after we know where they should go	*/
#ifndef DEFAULT_DEBUG_FILE
#define DEFAULT_DEBUG_FILE PRIMARY_DEBUG_FILE
#endif
#ifndef DEFAULT_ERROR_FILE
#define DEFAULT_ERROR_FILE PRIMARY_ERROR_FILE
#endif
#ifndef DEFAULT_OTHER_COMMENT_FILE
#define DEFAULT_OTHER_COMMENT_FILE NULL_DEVICE
#endif

  /*	Inserted comment switch defaults				*/
#ifndef DEFAULT_INSERTED_MSGS
#define DEFAULT_INSERTED_MSGS TRUE
#endif
#ifndef DEFAULT_INSERTED_MSG_TAG
#define DEFAULT_INSERTED_MSG_TAG TRUE
#endif
#ifndef DEFAULT_COMMENT_SOURCE_TAG
#define DEFAULT_COMMENT_SOURCE_TAG TRUE
#endif

  /*  Structure containing info about replacement of unprintable chars	*/
  /*  in error messages.  Mostly a convenience so we don't have to	*/
  /*  sling 6 args between functions.					*/
struct unprint_repl {
  char repl_char;		/*  Replacement character		*/
  int chars_replaced;		/*  How many unprintables were replaced	*/

    /*  First character we replaced.  Unsigned for convenience printing	*/
  unsigned char first_bad_char;
  char *first_repl_char_ptr;    /*  Ptr to first char replaced		*/

    /*  If we are unlucky, all prospective replacement characters ap-	*/
    /*  peared in message somewhere.  Count how many there were before	*/
    /*  we added ours							*/
  int repl_char_already_in_msg;
    /*  Pointer to first replacement character that was in message be-	*/
    /*  fore we added ours						*/
  char *first_repl_char_already_in_msg;
};

    /*  Time/date table contains up to 5 pairs of keyword (max size 26)	*/
    /*  & variable, up to 10 pairs of keyword (max size 18) & variable	*/
    /*  up to 2 pairs of keyword (max size 24) & convention (max size	*/
    /*  5, and up to 10 pairs of keyword (max size 22) & template.	*/
    /*  Each pair also requires 2 separators and a blank		*/
    /*  Note that keyword sizes depend on TIMEDATE*PREFIX params	*/
#define TIMEDATE_WJSTBL \
   NUM_OUTTIME_VARIABLES* (26 + MAXLEN_SEQUENCE_TAG + MAXVARNAMESIZE + 2 + 1) \
	+  NUM_TIMEDATE_FRAGS*(18 + MAXVARNAMESIZE + 2 + 1) \
	+  2*(24 + 5 + 2 + 1) \
	+  NUM_TIMEDATE_FRAGS*(22 + TOKEN + 2 + 1)


    /*  Latlon table allows 14 keywords (max size 35 = size prefix(6) +	*/
    /*  2 underscores + max size keyword(27 (? seems to me		*/
    /*  that max size is 13.  Use older, bigger, value.  Apr 07)),	*/
    /*  16 values, and, for each keyword/variable pair, 2 separators	*/
    /*  and a blank.  The values can be single characters, formats, or	*/
    /*  variable names							*/
#define NUM_LATLONPARAMS 14
#if MAXVARNAMESIZE > MAXLATLONFORMATSIZE
#define MAXLATLONVALUESIZE MAXVARNAMESIZE
#else
#define MAXLATLONVALUESIZE MAXLATLONFORMATSIZE
#endif
#define LATLON_WJSTBL NUM_LATLONPARAMS* \
			(35 + MAXLEN_SEQUENCE_TAG + MAXLATLONVALUESIZE +2 +1)

    /*  12, 57, 24 & 20 are the sizes of the keywords; 5 is size of	*/
    /*  FALSE;	1 is max # digits in a level; 1 is for possible -,	*/
    /*  MAXVARNAMESIZE is size of a variable name; 2s are wjstbl	*/
    /*  separators; MAXREC here represents the size of a file name -	*/
    /*  only sure limit is max chars defgb will read from an opt file;	*/
    /*  100 is slop so user can enter bad keyword and we		*/
    /*  can diagnose it (also, so we can be wrong about defns of other	*/
    /*  fields!!)							*/
#define VARLISTOPTS_WJSTBL (12 + 1 + 1 + 2) + \
			   (57 + 5 + 2) + \
			   (24 + MAXVARNAMESIZE + 2) + \
			   (20 + MAXREC + 2) + \
			   100

/******** 								*/
/*		IDMISSING & COORDMISSING stuff				*/

#define NUM_IDMISSING 10
  /*  If next string changes, change IDMISSING_WJSTBL. 			*/
#define IDMISSING_SEQUENCE_PREFIX "missingdatum"

  /*  Existing wjstbl routines require fixed-length strings.  Fix the	*/
  /*  length of the idmissing varlist to be big enough for 10 vars.	*/
  /*  Length must include IDMISSING_VARLIST_SEP* characters		*/
  /*  Since most varnames are shorter than MAXVARNAMESIZE, user can	*/
  /*  likely get more than 10						*/
#define IDMISSING_MIN_VARS_IN_VARLIST 10
#define MAXLEN_IDMISSING_VARLIST \
		IDMISSING_MIN_VARS_IN_VARLIST*(MAXVARNAMESIZE+1) - 1
    /*  Character that separates list of varnames that share a		*/
    /*  particular missing value					*/
#define IDMISSING_VARLIST_SEP_STRING ","

    /*  Length of string that represents "missing".  It doesn't have	*/
    /*  to be a datum, but that's a good max size.  Could also be	*/
    /*  ***all***, so be sure it's at least 9				*/
#define IDMISSING_FOR_ALL_VARIABLES "***all***"
#if DATUMSIZE>9
#define MAXLEN_MISSING_IN_DATA DATUMSIZE
#else
#define MAXLEN_MISSING_IN_DATA 9
#endif
#define IDMISSING_DEFAULT_VARLIST IDMISSING_FOR_ALL_VARIABLES

    /*  We allow user to redefine string below, but we'll limit the	*/
    /*  replacement string length to our length				*/
#define NOTDECODABLE_SPECIAL_STRING "***not-decodable***"
#define MAXLEN_NOTDECODABLE_SPECIAL_STRING 19

    /*  User can define tolerance as a number.  Set a max for that	*/
    /*  number's string representation on input				*/
#define MAXLEN_IDMISSING_TOLERANCE 30
    /*  longest datatype keyword is  floatingpoint 			*/
#define MAXLEN_IDMISSING_DATATYPE 13
    /*  longest nonnumeric keyword is  illegal				*/
#define MAXLEN_IDMISSING_NONNUMERIC 7
    /*  Code uses a temp buffer for each of the above (and comparison)	*/
    /*  Calculate its size.  As noted below, comparison IS 14 or lots	*/
    /*  has to change							*/
#define MAXLEN_IDMISSING_TEMP_BUFFER 14
#if MAXLEN_IDMISSING_TOLERANCE > MAXLEN_IDMISSING_TEMP_BUFFER 
#undef MAXLEN_IDMISSING_TEMP_BUFFER 
#define MAXLEN_IDMISSING_TEMP_BUFFER MAXLEN_IDMISSING_TOLERANCE 
#endif
#if MAXLEN_IDMISSING_DATATYPE > MAXLEN_IDMISSING_TEMP_BUFFER 
#undef MAXLEN_IDMISSING_TEMP_BUFFER 
#define MAXLEN_IDMISSING_TEMP_BUFFER MAXLEN_IDMISSING_DATATYPE 
#endif
#if MAXLEN_IDMISSING_NONNUMERIC > MAXLEN_IDMISSING_TEMP_BUFFER 
#undef MAXLEN_IDMISSING_TEMP_BUFFER 
#define MAXLEN_IDMISSING_TEMP_BUFFER MAXLEN_IDMISSING_NONNUMERIC 
#endif

    /*  IDMISSING files have up to 7 keywords				*/
    /*		Each keyword can have a  missingdatum_NNN_  prefix	*/
#define IDMISSING_KEYWORD_PREFIX_LEN 12 + 1 + 3 + 1
    /*    "varlist" can take a list of varnames.  See above for length	*/
    /*    "nonnumeric" takes a 7 char max string			*/
    /*    "comparison" takes a 14 char string.  Code assumes particular	*/
    /*		fixed format, so if the 14 changes, lots else will	*/
    /*    "not-decodable_special_word" takes an "arbitrary length" 	*/
    /*					string - we define limit	*/
    /*    "value" takes a takes an "arbitrary length" 			*/
    /*					string - we define limit	*/
    /*    "datatype" takes a 13 char max string				*/
    /*    "tolerance" takes a number					*/
    /*  2s are wjstbl separators					*/
#define IDMISSING_WJSTBL (   7 * IDMISSING_KEYWORD_PREFIX_LEN    ) + \
			 (7 + MAXLEN_IDMISSING_VARLIST  + 2) + \
			 (10 + 7 + 2) + \
			 (10 + 14 + 2) + \
			 (26 + MAXLEN_NOTDECODABLE_SPECIAL_STRING + 2 ) + \
			 (5 + MAXLEN_MISSING_IN_DATA + 2) + \
			 (8 + MAXLEN_IDMISSING_DATATYPE  + 2) + \
			 (9 + MAXLEN_IDMISSING_TOLERANCE + 2)

  /*  Next block all need to fit into  char  variables.  Don't use 0	*/
  /*  as a protection against some random overflow			*/
#define IDMISSING_CASEBLIND -1
#define IDMISSING_CASESENSITIVE 1

#define IDMISSING_DATATYPE_CHAR 'C'
#define IDMISSING_DATATYPE_LONG 'I'
#define IDMISSING_DATATYPE_FLOAT 'F'

#define IDMISSING_COMPARISON_OFFSET 10
#define IDMISSING_DATUM_LT_VAL -2 + IDMISSING_COMPARISON_OFFSET 
#define IDMISSING_DATUM_LE_VAL -1 + IDMISSING_COMPARISON_OFFSET 
#define IDMISSING_DATUM_EQ_VAL  0 + IDMISSING_COMPARISON_OFFSET 
#define IDMISSING_DATUM_GE_VAL  1 + IDMISSING_COMPARISON_OFFSET 
#define IDMISSING_DATUM_GT_VAL  2 + IDMISSING_COMPARISON_OFFSET 
#define IDMISSING_BAD_COMPARISON_OPERATOR -100

#define IDMISSING_NOTDECODABLE_ABORT 'X'
#define IDMISSING_NOTDECODABLE_MISSING 'M'
#define IDMISSING_NOTDECODABLE_ALLOW 'A'
#define IDMISSING_NOTDECODABLE_DEFAULT IDMISSING_NOTDECODABLE_ABORT

  /*  Each idmissing 1 struct has details about 1  datum		*/
  /*  that might represent missing					*/
  /*  The 3 "val_as_" locations as well as the all_non_numerics could	*/
  /*  be union-ed - only 1 of them will be used at a time		*/
struct idmissing {
  char *val_as_string;
  double val_as_double;
  double tolerance;
  long val_as_long;
  char datatype;		/*  Gets one of vals defined above	*/
  char comparison;		/*  Gets one of vals defined above	*/
  char notdecodable_action;	/*  Gets one of vals defined above	*/
  Logical do_comparison_test;	/*  Determines whether comparison btwn	*/
				/*  datum & val in this structure	*/
				/*  should be performed.  It's NOT per-	*/
				/*  formed if the criterion for missing	*/
				/*  is just "missing if not decodable	*/
				/*  as a number"			*/
				/*  strcmp (val,special_string) != 0	*/
  Logical caseblindcomparison;
};

    /*  Character that separates list of varnames whose missing status	*/
    /*  depends on "master" var's missing status.  In terms of the	*/
    /*  above descriptions, this is a "within within item" separator	*/
    /*  since it separates the fields in the "right half" of an item	*/
#define COORDMISSING_VARLIST_SEP_CHAR ','

/******** 								*/


#define MAX_DATACOMMENTS_SOURCES 9
#define VARLIST_PTR ".varlist"
#define LEVEL0_PTR ".level_0"
#define DATACOMMENTS_KEYWORD "source"
#define DATACOMMENTS_UNKNOWN_FORMAT 'U'
#define DATACOMMENTS_DEF_FORMATTED 'D'

#define OBJ_KEY ".objects_parameter"
