switch from internal jReadWrite to external

This commit is contained in:
Bogdan Pilyugin 2022-08-21 15:22:55 +02:00
parent 9358549667
commit fb0fc0a30a
5 changed files with 1 additions and 1693 deletions

View File

@ -13,13 +13,10 @@ idf_component_register(
"src/MQTT.c"
"src/MQTTSysHandler.c"
"src/OTA.c"
"extlibs/jRead.c"
"extlibs/jWrite.c"
INCLUDE_DIRS "."
"include"
"src"
"extlibs"
REQUIRES nvs_flash
libespfs
@ -30,4 +27,5 @@ idf_component_register(
esp_modem
esp_https_ota
app_update
jReadWrite
)

View File

@ -1,784 +0,0 @@
// jRead.cpp
// Version 1v6
//
// jRead - an in-place JSON element reader
// =======================================
//
// Instead of parsing JSON into some structure, this maintains the input JSON as unaltered text
// and allows queries to be made on it directly.
//
// e.g. with the simple JSON:
// {
// "astring":"This is a string",
// "anumber":42,
// "myarray":[ "one", 2, {"description":"element 3"}, null ],
// "yesno":true,
// "HowMany":"1234",
// "foo":null
// }
//
// calling:
// jRead( json, "{'myarray'[0", &jElem );
//
// would return:
// jElem.dataType= JREAD_STRING;
// jElem.elements= 1
// jElem.bytelen= 3
// jElem.pValue -> "one"
//
// or you could call the helper functions:
// jRead_string( json, "{'astring'", destString, MAXLEN );
// jRead_int( json, "{'anumber'", &myint );
// jRead_string( json, "{'myarray'[3", destString, MAXLEN );
// etc.
//
// Note that the helper functions do type coersion and always return a value
// (on error an empty string is returned or value of zero etc.)
//
// The query string simply defines the route to the required data item
// as an arbitary list of object or array specifiers:
// object element= "{'keyname'"
// array element= "[INDEX"
//
// The jRead() function fills a jReadElement structure to describe the located element
// this can be used to locate any element, not just terminal values
// e.g.
// jRead( json, "{'myarray'", &jElem );
//
// in this case jElem would contain:
// jElem.dataType= JSON_ARRAY
// jElem.elements= 4
// jElem.bytelen= 46
// jElem.pValue -> [ "one", 2, {"descripton":"element 3"}, null ] ...
//
// allowing jRead to be called again on the array:
// e.g.
// jRead( jElem.pValue, "[3", &jElem ); // get 4th element - the null value
//
// .oO! see main.c runExamples() for a whole bunch of examples !Oo.
// -------------------------------------------------------
//
// Note that jRead never modifies the source JSON and does not allocate any memory.
// i.e. elements are returned as pointer and length into the source text.
//
// Functions
// =========
// Main JSON reader:
// int jRead( char * JsonSource, char *query, jReadElement &pResult );
//
// Extended function using query parameters for indexing:
// int jRead( char * JsonSource, char *query, jReadElement &pResult, int *queryParams );
//
// Function to step thru JSON arrays instead of indexing:
// char *jReadArrayStep( char *pJsonArray, struct jReadElement *pResult );
//
// Optional Helper functions:
// long jRead_long( char *pJson, char *pQuery );
// int jRead_int( char *pJson, char *pQuery );
// double jRead_double( char *pJson, char *pQuery );
// int jRead_string( char *pJson, char *pQuery, char *pDest, int destlen );
//
// Optional String output Functions
// char * jReadTypeToString( int dataType ); // string describes dataType
// char * jReadErrorToString( int error ); // string descibes error code
//
// *NEW* in 1v2
// - "{NUMBER" returns the "key" value at that index within an object
// - jReadParam() adds queryParams which can be used as indexes into arrays (or into
// objects to return key values) by specifying '*' in the query string
// e.g. jReadParam( pJson, "[*", &result, &index )
// *NEW in 1v4
// - fixed a couple of error return values
// - added #define JREAD_DOUBLE_QUOTE_IN_QUERY
// *NEW* in 1v5 (11mar2015)
// - fixed null ptr if '[*' used when null param passed
// *NEW* in 1v6 (24sep2016)
// - fixed handling of empty arrays and objects
//
// TonyWilk, 24sep2016
// mail at tonywilk . co .uk
//
// License: "Free as in You Owe Me a Beer"
// - actually, since some people really worry about licenses, you are free to apply
// whatever licence you want.
//
// Note: jRead_atol() and jRead_atof() are modified from original routines
// fast_atol() and fast_atof() 09-May-2009 Tom Van Baak (tvb) www.LeapSecond.com
//
// You may want to replace the use of jRead_atol() and jRead_atof() in helper functions
// of your own. Especially note that my atof does not handle exponents.
//
//
#include <jRead.h>
#include <stdio.h>
// By default we use single quote in query strings so it's a lot easier
// to type in code i.e. "{'key'" instead of "{\"key\""
//
#ifdef JREAD_DOUBLE_QUOTE_IN_QUERY
#define QUERY_QUOTE '\"'
#else
#define QUERY_QUOTE '\''
#endif
//------------------------------------------------------
// Internal Functions
char * jReadSkipWhitespace( char *sp );
char * jReadFindTok( char *sp, int *tokType );
char * jReadGetString( char *pJson, struct jReadElement *pElem, char quote );
int jReadTextLen( char *pJson );
int jReadStrcmp( struct jReadElement *j1, struct jReadElement *j2 );
char * jReadCountObject( char *pJson, struct jReadElement *pResult, int keyIndex );
char * jReadCountArray( char *pJson, struct jReadElement *pResult );
char * jRead_atoi( char *p, unsigned int *result );
char * jRead_atol( char *p, long *result );
char * jRead_atof( char *p, double *result);
//=======================================================
char *jReadSkipWhitespace( char *sp )
{
while( (*sp != '\0') && (*sp <= ' ') )
sp++;
return sp;
};
// Find start of a token
// - returns pointer to start of next token or element
// returns type via tokType
//
char *jReadFindTok( char *sp, int *tokType )
{
char c;
sp= jReadSkipWhitespace(sp);
c= *sp;
if( c == '\0' ) *tokType= JREAD_EOL;
else if((c == '"') || (c == QUERY_QUOTE))*tokType= JREAD_STRING;
else if((c >= '0') && (c <= '9')) *tokType= JREAD_NUMBER;
else if( c == '-') *tokType= JREAD_NUMBER;
else if( c == '{') *tokType= JREAD_OBJECT;
else if( c == '[') *tokType= JREAD_ARRAY;
else if( c == '}') *tokType= JREAD_EOBJECT;
else if( c == ']') *tokType= JREAD_EARRAY;
else if((c == 't') || (c == 'f')) *tokType= JREAD_BOOL;
else if( c == 'n') *tokType= JREAD_NULL;
else if( c == ':') *tokType= JREAD_COLON;
else if( c == ',') *tokType= JREAD_COMMA;
else if( c == '*') *tokType= JREAD_QPARAM;
else *tokType= JREAD_ERROR;
return sp;
};
// jReadGetString
// - assumes next element is "string" which may include "\" sequences
// - returns pointer to -------------^
// - pElem contains result ( JREAD_STRING, length, pointer to string)
// - pass quote = '"' for Json, quote = '\'' for query scanning
//
// returns: pointer into pJson after the string (char after the " terminator)
// pElem contains pointer and length of string (or dataType=JREAD_ERROR)
//
char * jReadGetString( char *pJson, struct jReadElement *pElem, char quote )
{
short skipch;
pElem->dataType= JREAD_ERROR;
pElem->elements= 1;
pElem->bytelen= 0;
pJson= jReadSkipWhitespace( pJson );
if( *pJson == quote )
{
pJson++;
pElem->pValue= pJson; // -> start of actual string
pElem->bytelen=0;
skipch= 0;
while( *pJson != '\0' )
{
if( skipch )
skipch= 0;
else if( *pJson == '\\' ) // "\" sequence
skipch= 1;
else if( *pJson == quote )
{
pElem->dataType= JREAD_STRING;
pJson++;
break;
}
pElem->bytelen++;
pJson++;
};
};
return pJson;
};
// jReadTextLen
// - used to identify length of element text
// - returns no. of chars from pJson upto a terminator
// - terminators: ' ' , } ]
//
int jReadTextLen( char *pJson )
{
int len= 0;
while( (*pJson > ' ' ) && // any ctrl char incl '\0'
(*pJson != ',' ) &&
(*pJson != '}' ) &&
(*pJson != ']' ) )
{
len++;
pJson++;
}
return len;
}
// compare two json elements
// returns: 0 if they are identical strings, else 1
//
int jReadStrcmp( struct jReadElement *j1, struct jReadElement *j2 )
{
int i;
if( (j1->dataType != JREAD_STRING) ||
(j2->dataType != JREAD_STRING) ||
(j1->bytelen != j2->bytelen ) )
return 1;
for( i=0; i< j1->bytelen; i++ )
if( ((char *)(j1->pValue))[i] != ((char *)(j2->pValue))[i] )
return 1;
return 0;
}
// read unsigned int from string
char * jRead_atoi( char *p, unsigned int *result )
{
unsigned int x = 0;
while (*p >= '0' && *p <= '9') {
x = (x*10) + (*p - '0');
++p;
}
*result= x;
return p;
}
// read long int from string
//
char * jRead_atol( char *p, long *result )
{
long x = 0;
int neg = 0;
if (*p == '-') {
neg = 1;
++p;
}
while (*p >= '0' && *p <= '9') {
x = (x*10) + (*p - '0');
++p;
}
if (neg) {
x = -x;
}
*result= x;
return p;
}
#define valid_digit(c) ((c) >= '0' && (c) <= '9')
// read double from string
// *CAUTION* does not handle exponents
//
//
char * jRead_atof( char *p, double *result)
{
double sign, value;
// Get sign, if any.
sign = 1.0;
if (*p == '-') {
sign = -1.0;
p += 1;
} else if (*p == '+') {
p += 1;
}
// Get digits before decimal point or exponent, if any.
for (value = 0.0; valid_digit(*p); p += 1) {
value = value * 10.0 + (*p - '0');
}
// Get digits after decimal point, if any.
if (*p == '.') {
double pow10 = 10.0;
p += 1;
while (valid_digit(*p)) {
value += (*p - '0') / pow10;
pow10 *= 10.0;
p += 1;
}
}
*result= sign * value;
return p;
}
// read element into destination buffer and add '\0' terminator
// - always copies element irrespective of dataType (unless it's an error)
// - destBuffer is always '\0'-terminated (even on zero lenght returns)
// - returns pointer to destBuffer
//
char *jRead_strcpy( char *destBuffer, int destLength, struct jReadElement *pElement )
{
int i;
int len= pElement->bytelen;
char *pdest= destBuffer;
char *psrc= (char *)pElement->pValue;
if( pElement->error == 0 )
{
if( len >= destLength )
len= destLength;
for( i=0; i<destLength; i++ )
*pdest++= *psrc++;
}
*pdest= '\0';
return destBuffer;
}
// jReadCountObject
// - used when query ends at an object, we want to return the object length
// - on entry pJson -> "{... "
// - used to skip unwanted values which are objects
// - keyIndex normally passed as -1 unless we're looking for the nth "key" value
// in which case keyIndex is the index of the key we want
//
char * jReadCountObject( char *pJson, struct jReadElement *pResult, int keyIndex )
{
struct jReadElement jElement;
int jTok;
char *sp;
pResult->dataType= JREAD_OBJECT;
pResult->error= 0;
pResult->elements= 0;
pResult->pValue= pJson;
sp= jReadFindTok( pJson+1, &jTok ); // check for empty object
if( jTok == JREAD_EOBJECT )
{
pJson= sp+1;
}else
{
while( 1 )
{
pJson= jReadGetString( ++pJson, &jElement, '\"' );
if( jElement.dataType != JREAD_STRING )
{
pResult->error= 3; // Expected "key"
break;
}
if( pResult->elements == keyIndex ) // if passed keyIndex
{
*pResult= jElement; // we return "key" at this index
pResult->dataType= JREAD_KEY;
return pJson;
}
pJson= jReadFindTok( pJson, &jTok );
if( jTok != JREAD_COLON )
{
pResult->error= 4; // Expected ":"
break;
}
pJson= jRead( ++pJson, "", &jElement );
if( pResult->error )
break;
pJson= jReadFindTok( pJson, &jTok );
pResult->elements++;
if( jTok == JREAD_EOBJECT )
{
pJson++;
break;
}
if( jTok != JREAD_COMMA )
{
pResult->error= 6; // Expected "," in object
break;
}
}
}
if( keyIndex >= 0 )
{
// we wanted a "key" value - that we didn't find
pResult->dataType= JREAD_ERROR;
pResult->error= 11; // Object key not found (bad index)
}else{
pResult->bytelen= pJson - (char *)pResult->pValue;
}
return pJson;
}
// jReadCountArray
// - used when query ends at an array, we want to return the array length
// - on entry pJson -> "[... "
// - used to skip unwanted values which are arrays
//
char * jReadCountArray( char *pJson, struct jReadElement *pResult )
{
struct jReadElement jElement;
int jTok;
char *sp;
pResult->dataType= JREAD_ARRAY;
pResult->error= 0;
pResult->elements= 0;
pResult->pValue= pJson;
sp= jReadFindTok( pJson+1, &jTok ); // check for empty array
if( jTok == JREAD_EARRAY )
{
pJson= sp+1;
}else
{
while( 1 )
{
pJson= jRead( ++pJson, "", &jElement ); // array value
if( pResult->error )
break;
pJson= jReadFindTok( pJson, &jTok ); // , or ]
pResult->elements++;
if( jTok == JREAD_EARRAY )
{
pJson++;
break;
}
if( jTok != JREAD_COMMA )
{
pResult->error= 9; // Expected "," in array
break;
}
}
}
pResult->bytelen= pJson - (char *)pResult->pValue;
return pJson;
}
// jReadArrayStep()
// - reads one value from an array
// - assumes pJsonArray points at the start of an array or array element
//
char *jReadArrayStep( char *pJsonArray, struct jReadElement *pResult )
{
int jTok;
pJsonArray= jReadFindTok( pJsonArray, &jTok );
switch( jTok )
{
case JREAD_ARRAY: // start of array
case JREAD_COMMA: // element separator
return jRead( ++pJsonArray, "", pResult );
case JREAD_EARRAY: // end of array
pResult->error= 13; // End of array found
break;
default: // some other error
pResult->error= 9; // expected comma in array
break;
}
pResult->dataType= JREAD_ERROR;
return pJsonArray;
}
// jRead
// - reads a complete JSON <value>
// - matches pQuery against pJson, results in pResult
// returns: pointer into pJson
//
// Note: is recursive
//
char * jRead( char *pJson, char *pQuery, struct jReadElement *pResult )
{
return jReadParam( pJson, pQuery, pResult, NULL );
}
char * jReadParam( char *pJson, char *pQuery, struct jReadElement *pResult, int *queryParams )
{
int qTok, jTok, bytelen;
unsigned int index, count;
struct jReadElement qElement, jElement;
pJson= jReadFindTok( pJson, &jTok );
pQuery= jReadFindTok( pQuery, &qTok );
pResult->dataType= jTok;
pResult->bytelen= pResult->elements= pResult->error= 0;
pResult->pValue= pJson;
if( (qTok != JREAD_EOL) && (qTok != jTok) )
{
pResult->error= 1; // JSON does not match Query
return pJson;
}
switch( jTok )
{
case JREAD_ERROR: // general error, eof etc.
pResult->error= 2; // Error reading JSON value
break;
case JREAD_OBJECT: // "{"
if( qTok == JREAD_EOL )
return jReadCountObject( pJson, pResult, -1 ); // return length of object
pQuery= jReadFindTok( ++pQuery, &qTok ); // "('key'...", "{NUMBER", "{*" or EOL
if( qTok != JREAD_STRING )
{
index= 0;
switch( qTok )
{
case JREAD_NUMBER:
pQuery= jRead_atoi( (char *)pQuery, &index ); // index value
break;
case JREAD_QPARAM:
pQuery++;
index= (queryParams != NULL) ? *queryParams++ : 0; // substitute parameter
break;
default:
pResult->error= 12; // Bad Object key
return pJson;
}
return jReadCountObject( pJson, pResult, index );
}
pQuery= jReadGetString( pQuery, &qElement, QUERY_QUOTE ); // qElement = query 'key'
//
// read <key> : <value> , ... }
// loop 'til key matched
//
while( 1 )
{
pJson= jReadGetString( ++pJson, &jElement, '\"' );
if( jElement.dataType != JREAD_STRING )
{
pResult->error= 3; // Expected "key"
break;
}
pJson= jReadFindTok( pJson, &jTok );
if( jTok != JREAD_COLON )
{
pResult->error= 4; // Expected ":"
break;
}
// compare object keys
if( jReadStrcmp( &qElement, &jElement ) == 0 )
{
// found object key
return jReadParam( ++pJson, pQuery, pResult, queryParams );
}
// no key match... skip this value
pJson= jRead( ++pJson, "", pResult );
pJson= jReadFindTok( pJson, &jTok );
if( jTok == JREAD_EOBJECT )
{
pResult->error= 5; // Object key not found
break;
}
if( jTok != JREAD_COMMA )
{
pResult->error= 6; // Expected "," in object
break;
}
}
break;
case JREAD_ARRAY: // "[NUMBER" or "[*"
//
// read index, skip values 'til index
//
if( qTok == JREAD_EOL )
return jReadCountArray( pJson, pResult ); // return length of object
index= 0;
pQuery= jReadFindTok( ++pQuery, &qTok ); // "[NUMBER" or "[*"
if( qTok == JREAD_NUMBER )
{
pQuery= jRead_atoi( pQuery, &index ); // get array index
}else if( qTok == JREAD_QPARAM )
{
pQuery++;
index= (queryParams != NULL) ? *queryParams++ : 0; // substitute parameter
}
count=0;
while( 1 )
{
if( count == index )
return jReadParam( ++pJson, pQuery, pResult, queryParams ); // return value at index
// not this index... skip this value
pJson= jRead( ++pJson, "", &jElement );
if( pResult->error )
break;
count++;
pJson= jReadFindTok( pJson, &jTok ); // , or ]
if( jTok == JREAD_EARRAY )
{
pResult->error= 10; // Array element not found (bad index)
break;
}
if( jTok != JREAD_COMMA )
{
pResult->error= 9; // Expected "," in array
break;
}
}
break;
case JREAD_STRING: // "string"
pJson= jReadGetString( pJson, pResult, '\"' );
break;
case JREAD_NUMBER: // number (may be -ve) int or float
case JREAD_BOOL: // true or false
case JREAD_NULL: // null
bytelen= jReadTextLen( pJson );
pResult->dataType= jTok;
pResult->bytelen= bytelen;
pResult->pValue= pJson;
pResult->elements= 1;
pJson += bytelen;
break;
default:
pResult->error= 8; // unexpected character (in pResult->dataType)
}
// We get here on a 'terminal value'
// - make sure the query string is empty also
pQuery= jReadFindTok( pQuery, &qTok );
if( !pResult->error && (qTok != JREAD_EOL) )
pResult->error= 7; // terminal value found before end of query
if( pResult->error )
{
pResult->dataType= JREAD_ERROR;
pResult->elements= pResult->bytelen= 0;
pResult->pValue= pJson; // return pointer into JSON at error point
}
return pJson;
}
//--------------------------------------------------------------------
// Optional helper functions
// - simple routines to extract values from JSON
// - does coercion of types where possible
// - always returns a value (e.g. 0 or "" on error)
//
// Note: by default, pass NULL for queryParams
// unless you are using '*' in the query for indexing
//
// jRead_long
// - reads signed long value from JSON
// - returns number from NUMBER or STRING elements (if possible)
// returns 1 or 0 from BOOL elements
// otherwise returns 0
//
long jRead_long( char *pJson, char *pQuery, int *queryParams )
{
struct jReadElement elem;
long result;
jReadParam( pJson, pQuery, &elem, queryParams );
if( (elem.dataType == JREAD_ERROR) || (elem.dataType == JREAD_NULL))
return 0;
if( elem.dataType == JREAD_BOOL )
return *((char *)elem.pValue)=='t' ? 1 : 0;
jRead_atol( (char *)elem.pValue, &result );
return result;
}
int jRead_int( char *pJson, char *pQuery, int *queryParams )
{
return (int)jRead_long( pJson, pQuery, queryParams );
}
// jRead_double
// - returns double from JSON
// - returns number from NUMBER or STRING elements
// otherwise returns 0.0
//
double jRead_double( char *pJson, char *pQuery, int *queryParams )
{
struct jReadElement elem;
double result;
jReadParam( pJson, pQuery, &elem, queryParams );
if( elem.dataType == JREAD_ERROR )
return 0.0;
jRead_atof( (char *)elem.pValue, &result );
return result;
}
// jRead_string
// Copy string to pDest and '\0'-terminate it (upto destlen total bytes)
// returns: character length of string (excluding '\0' terminator)
//
// Note: any element can be returned as a string
//
int jRead_string( char *pJson, char *pQuery, char *pDest, int destlen, int *queryParams )
{
struct jReadElement elem;
int i;
*pDest= '\0';
jReadParam( pJson, pQuery, &elem, queryParams );
if( elem.dataType == JREAD_ERROR )
return 0;
for( i=0; (i<elem.bytelen) && (i<destlen-1); i++ )
*pDest++ = ((char *)elem.pValue)[i];
*pDest= '\0';
return elem.bytelen;
}
//-------------------------------------------------
// Optional String output Functions
//
char *jReadTypeStrings[]={
"Error", // 0
"Object", // 1
"Array", // 2
"String", // 3
"Number", // 4
"Bool", // 5
"null", // 6
"Object key", // 7
"colon", // 8
"eol", // 9
"comma", // 10
"}", // 11
"]", // 12
"* parameter" // 13
};
char *jReadTypeToString( int dataType )
{
return jReadTypeStrings[ dataType ];
};
char * jReadErrorStrings[]={
"Ok", // 0
"JSON does not match Query", // 1
"Error reading JSON value", // 2
"Expected \"key\"", // 3
"Expected ':'", // 4
"Object key not found", // 5
"Expected ',' in object", // 6
"Terminal value found before end of query", // 7
"Unexpected character", // 8
"Expected ',' in array", // 9
"Array element not found (bad index)", // 10
"Object key not found (bad index)", // 11
"Bad object key", // 12
"End of array found", // 13
"End of object found" // 14
};
char * jReadErrorToString( int error )
{
if( (error >=0 ) && (error <= 14))
return jReadErrorStrings[ error ];
return "Unknown error";
};
// end of jRead.c

View File

@ -1,128 +0,0 @@
// jRead.h
//
// see jRead.c for more information
//
// uncomment this if you really want to use double quotes in query strings instead of '
//#define JREAD_DOUBLE_QUOTE_IN_QUERY
//
// return dataTypes:
#define JREAD_ERROR 0 // general error, eof etc.
#define JREAD_OBJECT 1 // "{"
#define JREAD_ARRAY 2 // "["
#define JREAD_STRING 3 // "string"
#define JREAD_NUMBER 4 // number (may be -ve) int or float
#define JREAD_BOOL 5 // true or false
#define JREAD_NULL 6 // null
#define JREAD_KEY 7 // object "key"
// internal values:
#define JREAD_COLON 8 // ":"
#define JREAD_EOL 9 // end of input string (ptr at '\0')
#define JREAD_COMMA 10 // ","
#define JREAD_EOBJECT 11 // "}"
#define JREAD_EARRAY 12 // "]"
#define JREAD_QPARAM 13 // "*" query string parameter
//------------------------------------------------------
// jReadElement
// - structure to return JSON elements
// - error=0 for valid returns
//
// *NOTES*
// the returned pValue pointer points into the passed JSON
// string returns are not '\0' terminated.
// bytelen specifies the length of the returned data pointed to by pValue
//
struct jReadElement{
int dataType; // one of JREAD_...
int elements; // number of elements (e.g. elements in array or object)
int bytelen; // byte length of element (e.g. length of string, array text "[ ... ]" etc.)
void * pValue; // pointer to value string in JSON text
int error; // error value if dataType == JREAD_ERROR
};
//------------------------------------------------------
// The JSON reader function
//
// - reads a '\0'-terminated JSON text string from pJson
// - traverses the JSON according to the pQuery string
// - returns the result value in pResult
//
// returns: pointer into pJson after the queried value
//
// e.g.
// With JSON like: "{ ..., "key":"value", ... }"
//
// jRead( pJson, "{'key'", &result );
// returns with:
// result.dataType= JREAD_STRING, result.pValue->'value', result.bytelen=5
//
char * jRead( char *pJson, char *pQuery, struct jReadElement *pResult );
// version of jRead which allows one or more queryParam integers to be substituted
// for array or object indexes marked by a '*' in the query
//
// e.g. jReadParam( pJson, "[*", &resultElement, &arrayIndex );
//
// *!* CAUTION *!*
// You can supply an array of integers which are indexed for each '*' in pQuery
// however, horrid things will happen if you don't supply enough parameters
//
char * jReadParam( char *pJson, char *pQuery, struct jReadElement *pResult, int *queryParams );
// Array Stepping function
// - assumes pJsonArray is JSON source of an array "[ ... ]"
// - returns next element of the array in pResult
// - returns pointer to end of element, to be passed to next call of jReadArrayStep()
// - if end of array is encountered, pResult->error = 13 "End of array found"
//
// e.g.
// With JSON like: "{ ... "arrayInObject":[ elem1,elem2,... ], ... }"
//
// pJson= jRead( pJson, "{'arrayInObject'", &theArray );
// if( theArray.dataType == JREAD_ARRAY )
// {
// char *pArray= (char *)theArray.pValue;
// jReadElement arrayElement;
// int index;
// for( index=0; index < theArray.elements; index++ )
// {
// pArray= jReadArrayStep( pArray, &arrayElement );
// ...
//
// Note: this significantly speeds up traversing arrays.
//
char *jReadArrayStep( char *pJsonArray, struct jReadElement *pResult );
#define EXPORT_OPTIONAL_FUNCTIONS
#ifdef EXPORT_OPTIONAL_FUNCTIONS
//------------------------------------------------------
// Optional Helper Functions
//
long jRead_long( char *pJson, char *pQuery, int *queryParams );
int jRead_int( char *pJson, char *pQuery, int *queryParams );
double jRead_double( char *pJson, char *pQuery, int *queryParams );
int jRead_string( char *pJson, char *pQuery, char *pDest, int destlen, int *queryParams );
//------------------------------------------------------
// Optional String output Functions
//
char *jReadTypeToString( int dataType ); // string describes dataType
char * jReadErrorToString( int error ); // string descibes error code
//------------------------------------------------------
// Other jRead utilities which may be useful...
//
char * jRead_atoi( char *p, unsigned int *result ); // string to unsigned int
char * jRead_atol( char *p, long *result ); // string to signed long
char * jRead_atof( char *p, double *result); // string to double (does not do exponents)
int jReadStrcmp( struct jReadElement *j1, struct jReadElement *j2 ); // compare STRING elements
// copy element to '\0'-terminated buffer
char * jRead_strcpy( char *destBuffer, int destLength, struct jReadElement *pElement );
#endif
// end of jRead.h

View File

@ -1,561 +0,0 @@
//
// jWrite.c version 1v2
//
// A *really* simple JSON writer in C
//
// see: jWrite.h for info
//
// TonyWilk, Mar 2015
//
#define _CRT_SECURE_NO_WARNINGS // stop complaining about deprecated functions
#include <stddef.h>
#include <stdio.h>
#include <string.h> // memset()
#include <jWrite.h>
#include <stdint.h> // definintion of uint32_t, int32_t
//typedef unsigned int uint32_t;
//typedef int int32_t;
// the jWrite functions take the above jWriteControl structure pointer
// to maintain state while writing a JSON string.
//
// You can opt to use a single global instance of a jWriteControl structure
// which simplifies the function parameters or to supply your own structure
//
#ifdef JW_GLOBAL_CONTROL_STRUCT
struct jWriteControl g_jWriteControl; // global control struct
#define JWC_DECL // function parameter decl is empty
#define JWC_DECL0
#define JWC(x) g_jWriteControl.x // functions access global
#define JWC_PARAM // pointer to struct is empty
#define JWC_PARAM0
#else
#define JWC_DECL struct jWriteControl *jwc, // function parameter is ptr to control struct
#define JWC_DECL0 struct jWriteControl *jwc // function parameter, no params
#define JWC(x) jwc->x // functions use pointer
#define JWC_PARAM jwc, // pointer to stuct
#define JWC_PARAM0 jwc // pointer to stuct, no params
#endif
//------------------------------------------
// Internal functions
//
void jwPutch( JWC_DECL char c );
void jwPutstr( JWC_DECL char *str );
void jwPutraw( JWC_DECL char *str );
void modp_itoa10(int32_t value, char* str);
void modp_dtoa2(double value, char* str, int prec);
void jwPretty( JWC_DECL0 );
enum jwNodeType jwPop( JWC_DECL0 );
void jwPush( JWC_DECL enum jwNodeType nodeType );
//------------------------------------------
// jwOpen
// - open writing of JSON starting with rootType = JW_OBJECT or JW_ARRAY
// - initialise with user string buffer of length buflen
// - isPretty=JW_PRETTY adds \n and spaces to prettify output (else JW_COMPACT)
//
void jwOpen( JWC_DECL char *buffer, unsigned int buflen,
enum jwNodeType rootType, int isPretty )
{
memset( buffer, 0, buflen ); // zap the whole destination buffer
JWC(buffer)= buffer;
JWC(buflen)= buflen;
JWC(bufp)= buffer;
JWC(nodeStack)[0].nodeType= rootType;
JWC(nodeStack)[0].elementNo= 0;
JWC(stackpos)=0;
JWC(error)= JWRITE_OK;
JWC(callNo)= 1;
JWC(isPretty)= isPretty;
jwPutch( JWC_PARAM (rootType==JW_OBJECT) ? '{' : '[' );
}
//------------------------------------------
// jwClose
// - closes the root JSON object started by jwOpen()
// - returns error code
//
int jwClose( JWC_DECL0 )
{
if( JWC(error) == JWRITE_OK )
{
if( JWC(stackpos) == 0 )
{
enum jwNodeType node= JWC(nodeStack)[0].nodeType;
if( JWC(isPretty) )
jwPutch( JWC_PARAM '\n' );
jwPutch( JWC_PARAM (node == JW_OBJECT) ? '}' : ']');
}else{
JWC(error)= JWRITE_NEST_ERROR; // nesting error, not all objects closed when jwClose() called
}
}
return JWC(error);
}
//------------------------------------------
// End the current array/object
//
int jwEnd( JWC_DECL0 )
{
if( JWC(error) == JWRITE_OK )
{
enum jwNodeType node;
int lastElemNo= JWC(nodeStack)[JWC(stackpos)].elementNo;
node= jwPop( JWC_PARAM0 );
if( lastElemNo > 0 )
jwPretty( JWC_PARAM0 );
jwPutch( JWC_PARAM (node == JW_OBJECT) ? '}' : ']');
}
return JWC(error);
}
//------------------------------------------
// jwErrorPos
// - Returns position of error: the nth call to a jWrite function
//
int jwErrorPos( JWC_DECL0 )
{
return JWC(callNo);
}
//------------------------------------------
// Object insert functions
//
int _jwObj( JWC_DECL char *key );
// put raw string to object (i.e. contents of rawtext without quotes)
//
void jwObj_raw( JWC_DECL char *key, char *rawtext )
{
if(_jwObj( JWC_PARAM key ) == JWRITE_OK)
jwPutraw( JWC_PARAM rawtext);
}
// put "quoted" string to object
//
void jwObj_string( JWC_DECL char *key, char *value )
{
if(_jwObj( JWC_PARAM key ) == JWRITE_OK)
jwPutstr( JWC_PARAM value );
}
void jwObj_int( JWC_DECL char *key, int value )
{
modp_itoa10( value, JWC(tmpbuf) );
jwObj_raw( JWC_PARAM key, JWC(tmpbuf) );
}
void jwObj_double( JWC_DECL char *key, double value )
{
modp_dtoa2( value, JWC(tmpbuf), 6 );
jwObj_raw( JWC_PARAM key, JWC(tmpbuf) );
}
void jwObj_bool( JWC_DECL char *key, int oneOrZero )
{
jwObj_raw( JWC_PARAM key, (oneOrZero) ? "true" : "false" );
}
void jwObj_null( JWC_DECL char *key )
{
jwObj_raw( JWC_PARAM key, "null" );
}
// put Object in Object
//
void jwObj_object( JWC_DECL char *key )
{
if(_jwObj( JWC_PARAM key ) == JWRITE_OK)
{
jwPutch( JWC_PARAM '{' );
jwPush( JWC_PARAM JW_OBJECT );
}
}
// put Array in Object
//
void jwObj_array( JWC_DECL char *key )
{
if(_jwObj( JWC_PARAM key ) == JWRITE_OK)
{
jwPutch( JWC_PARAM '[' );
jwPush( JWC_PARAM JW_ARRAY );
}
}
//------------------------------------------
// Array insert functions
//
int _jwArr( JWC_DECL0 );
// put raw string to array (i.e. contents of rawtext without quotes)
//
void jwArr_raw( JWC_DECL char *rawtext )
{
if(_jwArr( JWC_PARAM0 ) == JWRITE_OK)
jwPutraw( JWC_PARAM rawtext);
}
// put "quoted" string to array
//
void jwArr_string( JWC_DECL char *value )
{
if(_jwArr( JWC_PARAM0 ) == JWRITE_OK)
jwPutstr( JWC_PARAM value );
}
void jwArr_int( JWC_DECL int value )
{
modp_itoa10( value, JWC(tmpbuf) );
jwArr_raw( JWC_PARAM JWC(tmpbuf) );
}
void jwArr_double( JWC_DECL double value )
{
modp_dtoa2( value, JWC(tmpbuf), 6 );
jwArr_raw( JWC_PARAM JWC(tmpbuf) );
}
void jwArr_bool( JWC_DECL int oneOrZero )
{
jwArr_raw( JWC_PARAM (oneOrZero) ? "true" : "false" );
}
void jwArr_null( JWC_DECL0 )
{
jwArr_raw( JWC_PARAM "null" );
}
void jwArr_object( JWC_DECL0 )
{
if(_jwArr( JWC_PARAM0 ) == JWRITE_OK)
{
jwPutch( JWC_PARAM '{' );
jwPush( JWC_PARAM JW_OBJECT );
}
}
void jwArr_array( JWC_DECL0 )
{
if(_jwArr( JWC_PARAM0 ) == JWRITE_OK)
{
jwPutch( JWC_PARAM '[' );
jwPush( JWC_PARAM JW_ARRAY );
}
}
//------------------------------------------
// jwErrorToString
// - returns string describing error code
//
char *jwErrorToString( int err )
{
switch( err )
{
case JWRITE_OK: return "OK";
case JWRITE_BUF_FULL: return "output buffer full";
case JWRITE_NOT_ARRAY: return "tried to write Array value into Object";
case JWRITE_NOT_OBJECT: return "tried to write Object key/value into Array";
case JWRITE_STACK_FULL: return "array/object nesting > JWRITE_STACK_DEPTH";
case JWRITE_STACK_EMPTY:return "stack underflow error (too many 'end's)";
case JWRITE_NEST_ERROR: return "nesting error, not all objects closed when jwClose() called";
}
return "Unknown error";
}
//============================================================================
// Internal functions
//
void jwPretty( JWC_DECL0 )
{
int i;
if( JWC(isPretty) )
{
jwPutch( JWC_PARAM '\n' );
for( i=0; i<JWC(stackpos)+1; i++ )
jwPutraw( JWC_PARAM " " );
}
}
// Push / Pop node stack
//
void jwPush( JWC_DECL enum jwNodeType nodeType )
{
if( (JWC(stackpos)+1) >= JWRITE_STACK_DEPTH )
JWC(error)= JWRITE_STACK_FULL; // array/object nesting > JWRITE_STACK_DEPTH
else
{
JWC(nodeStack[++JWC(stackpos)]).nodeType= nodeType;
JWC(nodeStack[JWC(stackpos)]).elementNo= 0;
}
}
enum jwNodeType jwPop( JWC_DECL0 )
{
enum jwNodeType retval= JWC(nodeStack[JWC(stackpos)]).nodeType;
if( JWC(stackpos) == 0 )
JWC(error)= JWRITE_STACK_EMPTY; // stack underflow error (too many 'end's)
else
JWC(stackpos)--;
return retval;
}
void jwPutch( JWC_DECL char c )
{
if( (unsigned int)(JWC(bufp) - JWC(buffer)) >= JWC(buflen) )
{
JWC(error)= JWRITE_BUF_FULL;
}else{
*JWC(bufp)++ = c;
}
}
// put string enclosed in quotes
//
void jwPutstr( JWC_DECL char *str )
{
jwPutch( JWC_PARAM '\"' );
while( *str != '\0' )
jwPutch( JWC_PARAM *str++ );
jwPutch( JWC_PARAM '\"' );
}
// put raw string
//
void jwPutraw( JWC_DECL char *str )
{
while( *str != '\0' )
jwPutch( JWC_PARAM *str++ );
}
// *common Object function*
// - checks error
// - checks current node is OBJECT
// - adds comma if reqd
// - adds "key" :
//
int _jwObj( JWC_DECL char *key )
{
if(JWC(error) == JWRITE_OK)
{
JWC(callNo)++;
if( JWC(nodeStack)[JWC(stackpos)].nodeType != JW_OBJECT )
JWC(error)= JWRITE_NOT_OBJECT; // tried to write Object key/value into Array
else if( JWC(nodeStack)[JWC(stackpos)].elementNo++ > 0 )
jwPutch( JWC_PARAM ',' );
jwPretty( JWC_PARAM0 );
jwPutstr( JWC_PARAM key );
jwPutch( JWC_PARAM ':' );
if( JWC(isPretty) )
jwPutch( JWC_PARAM ' ' );
}
return JWC(error);
}
// *common Array function*
// - checks error
// - checks current node is ARRAY
// - adds comma if reqd
//
int _jwArr( JWC_DECL0 )
{
if(JWC(error) == JWRITE_OK)
{
JWC(callNo)++;
if( JWC(nodeStack)[JWC(stackpos)].nodeType != JW_ARRAY )
JWC(error)= JWRITE_NOT_ARRAY; // tried to write array value into Object
else if( JWC(nodeStack)[JWC(stackpos)].elementNo++ > 0 )
jwPutch( JWC_PARAM ',' );
jwPretty( JWC_PARAM0 );
}
return JWC(error);
}
//=================================================================
//
// modp value-to-string functions
// - modified for C89
//
// We use these functions as they are a lot faster than sprintf()
//
// Origin of these routines:
/*
* <pre>
* Copyright &copy; 2007, Nick Galbreath -- nickg [at] modp [dot] com
* All rights reserved.
* http://code.google.com/p/stringencoders/
* Released under the bsd license.
* </pre>
*/
static void strreverse(char* begin, char* end)
{
char aux;
while (end > begin)
aux = *end, *end-- = *begin, *begin++ = aux;
}
/** \brief convert an signed integer to char buffer
*
* \param[in] value
* \param[out] buf the output buffer. Should be 16 chars or more.
*/
void modp_itoa10(int32_t value, char* str)
{
char* wstr=str;
// Take care of sign
unsigned int uvalue = (value < 0) ? -value : value;
// Conversion. Number is reversed.
do *wstr++ = (char)(48 + (uvalue % 10)); while(uvalue /= 10);
if (value < 0) *wstr++ = '-';
*wstr='\0';
// Reverse string
strreverse(str,wstr-1);
}
/**
* Powers of 10
* 10^0 to 10^9
*/
static const double pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000,
10000000, 100000000, 1000000000};
/** \brief convert a floating point number to char buffer with a
* variable-precision format, and no trailing zeros
*
* This is similar to "%.[0-9]f" in the printf style, except it will
* NOT include trailing zeros after the decimal point. This type
* of format oddly does not exists with printf.
*
* If the input value is greater than 1<<31, then the output format
* will be switched exponential format.
*
* \param[in] value
* \param[out] buf The allocated output buffer. Should be 32 chars or more.
* \param[in] precision Number of digits to the right of the decimal point.
* Can only be 0-9.
*/
void modp_dtoa2(double value, char* str, int prec)
{
/* if input is larger than thres_max, revert to exponential */
const double thres_max = (double)(0x7FFFFFFF);
int count;
double diff = 0.0;
char* wstr = str;
int neg= 0;
int whole;
double tmp;
uint32_t frac;
/* Hacky test for NaN
* under -fast-math this won't work, but then you also won't
* have correct nan values anyways. The alternative is
* to link with libmath (bad) or hack IEEE double bits (bad)
*/
if (! (value == value)) {
str[0] = 'n'; str[1] = 'a'; str[2] = 'n'; str[3] = '\0';
return;
}
if (prec < 0) {
prec = 0;
} else if (prec > 9) {
/* precision of >= 10 can lead to overflow errors */
prec = 9;
}
/* we'll work in positive values and deal with the
negative sign issue later */
if (value < 0) {
neg = 1;
value = -value;
}
whole = (int) value;
tmp = (value - whole) * pow10[prec];
frac = (uint32_t)(tmp);
diff = tmp - frac;
if (diff > 0.5) {
++frac;
/* handle rollover, e.g. case 0.99 with prec 1 is 1.0 */
if (frac >= pow10[prec]) {
frac = 0;
++whole;
}
} else if (diff == 0.5 && ((frac == 0) || (frac & 1))) {
/* if halfway, round up if odd, OR
if last digit is 0. That last part is strange */
++frac;
}
/* for very large numbers switch back to native sprintf for exponentials.
anyone want to write code to replace this? */
/*
normal printf behavior is to print EVERY whole number digit
which can be 100s of characters overflowing your buffers == bad
*/
if (value > thres_max) {
sprintf(str, "%e", neg ? -value : value);
return;
}
if (prec == 0) {
diff = value - whole;
if (diff > 0.5) {
/* greater than 0.5, round up, e.g. 1.6 -> 2 */
++whole;
} else if (diff == 0.5 && (whole & 1)) {
/* exactly 0.5 and ODD, then round up */
/* 1.5 -> 2, but 2.5 -> 2 */
++whole;
}
//vvvvvvvvvvvvvvvvvvv Diff from modp_dto2
} else if (frac) {
count = prec;
// now do fractional part, as an unsigned number
// we know it is not 0 but we can have leading zeros, these
// should be removed
while (!(frac % 10)) {
--count;
frac /= 10;
}
//^^^^^^^^^^^^^^^^^^^ Diff from modp_dto2
// now do fractional part, as an unsigned number
do {
--count;
*wstr++ = (char)(48 + (frac % 10));
} while (frac /= 10);
// add extra 0s
while (count-- > 0) *wstr++ = '0';
// add decimal
*wstr++ = '.';
}
// do whole part
// Take care of sign
// Conversion. Number is reversed.
do *wstr++ = (char)(48 + (whole % 10)); while (whole /= 10);
if (neg) {
*wstr++ = '-';
}
*wstr='\0';
strreverse(str, wstr-1);
}
//=================================================================
/* end of jWrite.c */

View File

@ -1,217 +0,0 @@
//
// 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
//
//
#ifndef JWRITE_H_
#define JWRITE_H_
#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 */
#endif /*JWRITE_H_ */
/* end of jWrite.h */