text: //
  // jWrite.h
  //
  // A *really* simple JSON writer in C  (C89)
  // - a collection of functions to generate JSON semi-automatically
  //
  // The idea is to simplify writing native C values into a JSON string and
  // to provide some error trapping to ensure that the result is valid JSON.
  //
  // Example:
  //		jwOpen( buffer, buflen, JW_OBJECT, JW_PRETTY );		// open root node as object
  //		jwObj_string( "key", "value" );
  //		jwObj_int( "int", 1 );
  //		jwObj_array( "anArray");
  //			jwArr_int( 0 );
  //			jwArr_int( 1 );
  //			jwArr_int( 2 );
  //		jwEnd();
  //		err= jwClose();								// close root object
  //
  // results in:
  //
  //		{
  //		    "key": "value",
  //		    "int": 1,
  //		    "anArray": [
  //		        0,
  //		        1,
  //		        2
  //		    ]
  //		}
  //
  // Note that jWrite handles string quoting and getting commas in the right place.
  // If the sequence of calls is incorrect
  // e.g.
  //		jwOpen( buffer, buflen, JW_OBJECT, 1 );
  //		jwObj_string( "key", "value" );
  //			jwArr_int( 0 );
  //      ...
  //
  // then the error code returned from jwClose() would indicate that you attempted to
  // put an array element into an object (instead of a key:value pair)
  // To locate the error, the supplied buffer has the JSON created upto the error point
  // and a call to jwErrorPos() would return the function call at which the error occurred
  // - in this case 3, the 3rd function call "jwArr_int(0)" is not correct at this point.
  //
  // The root JSON type can be JW_OBJECT or JW_ARRAY.
  //
  // For more information on each function, see the prototypes below.
  //
  //
  // GLOBAL vs. Application-Supplied Control Structure
  // -------------------------------------------------
  // jWrite requires a jWriteControl structure to save the internal state.
  // For many applications it is much simpler for this to be a global variable as
  // used by the above examples.
  //
  // To use multiple instances of jWrite, an application has to supply unique instances
  // of jWriteControl structures. 
  //
  // This feature is enabled by commenting out the definition of JW_GLOBAL_CONTROL_STRUCT
  //
  // All the jWrite functions then take an additional parameter: a ptr to the structure
  // e.g.
  //		struct jWriteControl jwc;
  //
  //		jwOpen( &jwc, buffer, buflen, JW_OBJECT, 1 );
  //		jwObj_string( &jwc, "key", "value" );
  //		jwObj_int( &jwc, "int", 1 );
  //		jwObj_array( &jwc, "anArray");
  //			jwArr_int( &jwc, 0 );
  //			jwArr_int( &jwc, 1 );
  //			jwArr_int( &jwc, 2 );
  //		jwEnd( &jwc );
  //		err= jwClose( &jwc );
  //
  // - which is more flexible, but a pain to type in !
  //
  // TonyWilk, Mar 2015
  //
  // 
  #define JW_GLOBAL_CONTROL_STRUCT	// <--- comment this out to use applic-supplied jWriteControl
  
  #define JWRITE_STACK_DEPTH 32			// max nesting depth of objects/arrays
  
  #define JW_COMPACT	0					// output string control for jwOpen()
  #define JW_PRETTY	1					// pretty adds \n and indentation
  
  enum jwNodeType{
  	JW_OBJECT= 1,
  	JW_ARRAY
  };
  
  struct jwNodeStack{
  	enum jwNodeType nodeType;
  	int elementNo;
  };
  
  struct jWriteControl{
  	char *buffer;						// pointer to application's buffer
  	unsigned int buflen;				// length of buffer
  	char *bufp;							// current write position in buffer
  	char tmpbuf[32];					// local buffer for int/double convertions
  	int error;							// error code
  	int callNo;							// API call on which error occurred
  	struct jwNodeStack nodeStack[JWRITE_STACK_DEPTH];	// stack of array/object nodes
  	int stackpos;
  	int isPretty;						// 1= pretty output (inserts \n and spaces)
  };
  
  // Error Codes
  // -----------
  #define JWRITE_OK           0
  #define JWRITE_BUF_FULL     1		// output buffer full
  #define JWRITE_NOT_ARRAY	2		// tried to write Array value into Object
  #define JWRITE_NOT_OBJECT	3		// tried to write Object key/value into Array
  #define JWRITE_STACK_FULL	4		// array/object nesting > JWRITE_STACK_DEPTH
  #define JWRITE_STACK_EMPTY	5		// stack underflow error (too many 'end's)
  #define JWRITE_NEST_ERROR	6		// nesting error, not all objects closed when jwClose() called
  
  
  // API functions
  // -------------
  
  // Returns '\0'-termianted string describing the error (as returned by jwClose())
  //
  char *jwErrorToString( int err );
  
  
  #ifdef JW_GLOBAL_CONTROL_STRUCT		/* USING GLOBAL g_jWriteControl */
  
  // jwOpen
  // - initialises jWrite with the application supplied 'buffer' of length 'buflen'
  //   in operation, the buffer will always contain a valid '\0'-terminated string
  // - jWrite will not overrun the buffer (it returns an "output buffer full" error)
  // - rootType is the base JSON type: JW_OBJECT or JW_ARRAY
  // - isPretty controls 'prettifying' the output: JW_PRETTY or JW_COMPACT
  void jwOpen( char *buffer, unsigned int buflen, enum jwNodeType rootType, int isPretty );
  
  // jwClose
  // - closes the element opened by jwOpen()
  // - returns error code (0 = JWRITE_OK)
  // - after an error, all following jWrite calls are skipped internally
  //   so the error code is for the first error detected
  int jwClose( );
  
  // jwErrorPos
  // - if jwClose returned an error, this function returns the number of the jWrite function call
  //   which caused that error.
  int jwErrorPos( );
  
  // Object insertion functions
  // - used to insert "key":"value" pairs into an object
  //
  void jwObj_string( char *key, char *value );
  void jwObj_int( char *key, int value );
  void jwObj_double( char *key, double value );
  void jwObj_bool( char *key, int oneOrZero );
  void jwObj_null( char *key );
  void jwObj_object( char *key );
  void jwObj_array( char *key );
  
  // Array insertion functions
  // - used to insert "value" elements into an array
  //
  void jwArr_string( char *value );
  void jwArr_int( int value );
  void jwArr_double( double value );
  void jwArr_bool( int oneOrZero );
  void jwArr_null( );
  void jwArr_object( );
  void jwArr_array( );
  
  // jwEnd
  // - defines the end of an Object or Array definition
  int jwEnd( );
  
  
  // these 'raw' routines write the JSON value as the contents of rawtext
  // i.e. enclosing quotes are not added
  // - use if your app. supplies its own value->string functions
  //
  void jwObj_raw( char *key, char *rawtext );
  void jwArr_raw( char *rawtext );
  
  #else  /* JW_GLOBAL_CONTROL_STRUCT not defined */
  // Same API functions with app-supplied control struct option
  //
  void jwOpen( struct jWriteControl *jwc, char *buffer, unsigned int buflen, enum jwNodeType rootType, int isPretty );
  int jwClose( struct jWriteControl *jwc );
  int jwErrorPos( struct jWriteControl *jwc );
  void jwObj_string( struct jWriteControl *jwc, char *key, char *value );
  void jwObj_int( struct jWriteControl *jwc, char *key, int value );
  void jwObj_double( struct jWriteControl *jwc, char *key, double value );
  void jwObj_bool( struct jWriteControl *jwc, char *key, int oneOrZero );
  void jwObj_null( struct jWriteControl *jwc, char *key );
  void jwObj_object( struct jWriteControl *jwc, char *key );
  void jwObj_array( struct jWriteControl *jwc, char *key );
  void jwArr_string( struct jWriteControl *jwc, char *value );
  void jwArr_int( struct jWriteControl *jwc, int value );
  void jwArr_double( struct jWriteControl *jwc, double value );
  void jwArr_bool( struct jWriteControl *jwc, int oneOrZero );
  void jwArr_null( struct jWriteControl *jwc );
  void jwArr_object( struct jWriteControl *jwc );
  void jwArr_array( struct jWriteControl *jwc );
  int jwEnd( struct jWriteControl *jwc );
  void jwObj_raw( struct jWriteControl *jwc, char *key, char *rawtext );
  void jwArr_raw( struct jWriteControl *jwc, char *rawtext );
  
  #endif /* JW_GLOBAL_CONTROL_STRUCT */
  
  
  /* end of jWrite.h */
  