Skip to content

Instantly share code, notes, and snippets.

@Chubek
Last active June 19, 2023 01:54
Show Gist options
  • Save Chubek/17523b0c6c5f3aa86e69dcff99d8c3df to your computer and use it in GitHub Desktop.
Save Chubek/17523b0c6c5f3aa86e69dcff99d8c3df to your computer and use it in GitHub Desktop.
shibajs1.h: Quick and Dirty JSON Parsing (not an advertisement!)

Browse further to see shibajs1.h, this is just comments on top of the file for people who might be on a portable device.

Fun fact: shibajs1.h has 79! = 8.94618213 E+116 different combinations. Can you generate them all? Haha.

NOTICE: Parts of this program remains partly untested. The reason for posting this is overall comments

    Contact the Author:
      * Github: Github.com/chubek
      * Email: [email protected]
      * Discord: .chubak

shibajs1.h: Quick and Dirty JSON Parsing

No lexing, no syntax analysis, JUST PARSING!

Notice that this tagline is not a feature. I have made this header-only 'thingy' for my own use, mostly in Native Messaging between my C daemons and browsers, and other applications with a higher interface which yield a good JSON serializer. I am posting this application programming interface on the world-wide web for comments only. However, I am going to teach you how to use it. Most of shibajs1.h is macros. There's a lot of them. All these macros begin with J_ as not to be mixed with macros in other source or header files which will be in the application source tree. If you wish to change this prefix you may CTRL+F, CTRL+H it. Or you can undefine that macro using #undef J_[MACRO].

shibajs1.h also has another type of macro, which direct the course of CPP in preprocessing the file. There is a long list of these macros which I will mention so shortly. These macros, for example, let you control wether you want Unicode support or not (which is off by default), whether you want your integer type to be signed, long etc, whether you want the string parser to mind the escape characters, etc etc.

But before introducing these macros, let me tell you about the functions. There is a total of 9 functions available. The prefix of these functions is shibajs1_* but you may change it, as we will see later. 8 of these functions are for parsing various aspects of a JSON stream. The 9th function is for freeing any memory reserved by the key-value pair. These functions are:

  • jstream_t shibajs1_parse_key(jstream_t, jkvpair_t*)
  • jstream_t shibajs1_parse_primitive(jstream_t, jkvpair_t*)
  • jstream_t shibajs1_parse_integer(jstream_t, jkvpair_t*)
  • jstream_t shibajs1_parse_float(jstream_t, jkvpair_t*)
  • jstream_t shibajs1_parse_string(jstream_t, jkvpair_t*)
  • jstream_t shibajs1_parse_ineger_array(jstream_t, jkvpair_t*, jlength_t)
  • jstream_t shibajs1_parse_float_array(jstream_t, jkvpair_t*, jlength_t)
  • jstream_t shibajs1_parse_string_array(jstream_t, jkvpair_t*, jlength_t)
  • void shibajs1_free_json(jkvpair_t*)

Keep this in mind: shibajs1.h does NOT do any I/O! You yourself must handle the I/O. Whether it be Unicode, or ASCII. Generally, to parse a this JSON string:

{
  "myNull": null,
  "myTrue": true,
  "myFalse": false,
  "myInt": 12000,
  "myFloat": 1e-12,
  "myString": "myValue",
  "myIntArray": [
    1,
    2,
    4
  ],
  "myFloatArray": [1.23, 11.2, 1.222, 1e-2],
  "myStringArray": [
    "myValue1",
    "myValue3"
  ]
}

Regardless of where it comes from:

jstream_t jstream = "....";
jkvpair_t kvpair;
jstream = shibajs1_parse_key(jstream, &kvpair);
jstream = shibajs1_parse_primitive(jstream, &kvpair);
//  ...operate on kvpair...
shibajs1_free_json(&kvpair);
jstream = shibajs1_parse_key(jstream, &kvpair);
jstream = shibajs1_parse_primitive(jstream, &kvpair);
//  ...operate on kvpair...
shibajs1_free_json(&kvpair);
jstream = shibajs1_parse_key(jstream, &kvpair);
jstream = shibajs1_parse_primitive(jstream, &kvpair);
//  ...operate on kvpair...
shibajs1_free_json(&kvpair);
jstream = shibajs1_parse_key(jstream, &kvpair);
jstream = shibajs1_parse_integer(jstream, &kvpair);
//  ...operate on kvpair...
shibajs1_free_json(&kvpair);
jstream = shibajs1_parse_key(jstream, &kvpair);
jstream = shibajs1_parse_float(jstream, &kvpair);
shibajs1_free_json(&kvpair);
jstream = shibajs1_parse_key(jstream, &kvpair);
jstream = shibajs1_parse_string(jstream, &kvpair);
//  ...operate on kvpair...
shibajs1_free_json(&kvpair);
jstream = shibajs1_parse_key(jstream, &kvpair);
jstream = shibajs1_parse_integer_array(jstream, &kvpair, 3);
//  ...operate on kvpair...
shibajs1_free_json(&kvpair);
jstream = shibajs1_parse_key(jstream, &kvpair);
jstream = shibajs1_parse_float_array(jstream, &kvpair, 4);
shibajs1_free_json(&kvpair);
jstream = shibajs1_parse_key(jstream, &kvpair);
jstream = shibajs1_parse_string_array(jstream, &kvpair, 2);
//  ...operate on kvpair...
shibajs1_free_json(&kvpair);

You don't need to NECESSIRALY use it like this, this is a general guide line as of how to utilize the functions. NOTE: ALWAYS FREE THE KEY-VALUE PAIR AFTER USE!!!! Even if it is an integer, float or a primitive, the key is allocated dynamically (unless you enable J_ALLOC_ON_STACK, as we will see).

So now, let's see what directive preprocessor macros you may use to change the function of these program. There is a total of 79 macros provided, you can use any of them basically. Here they are, in alphabetic from:

__J_ALLOC_ON_STACK__
__J_CUST_FALSE_LIT_LEN__
__J_CUST_FALSE_LIT__
__J_CUST_FALSE_VAL__
__J_CUST_FLTCONVFN_REENTRANT__
__J_CUST_FLTCONVFN__
__J_CUST_FN_PREFIX__
__J_CUST_INTCONVFN_REENTRANT__
__J_CUST_INTCONVFN__
__J_CUST_INT_BASE__
__J_CUST_MEMALLOCFN__
__J_CUST_MEMALLOCFN___
__J_CUST_MEMCPYFN__
__J_CUST_MEMFREEFN__
__J_CUST_MEMSETFN__
__J_CUST_NULL_LIT_LEN__
__J_CUST_NULL_LIT__
__J_CUST_NULL_VAL__
__J_CUST_PRIMITIVE_VALS__
__J_CUST_SENTINEL__
__J_CUST_STRCMPFN__
__J_CUST_TRUE_LIT_LEN__
__J_CUST_TRUE_LIT__
__J_CUST_TRUE_VAL__
__J_ECONOMIC_ALLOC__
__J_HEX_MSB_LEFT__
__J_NO_ERRORS_AT_PREPROCESS__
__J_NO_FREE_FN__
__J_NO_INC_ALLOCA_H__
__J_NO_INC_STDLIB_H__
__J_NO_INC_STRING_H__
__J_NO_INC_UNISTD_H__
__J_NO_INC_WCHAR_H__
__J_NO_INLINE__
__J_NO_PARSE_FLOAT_FN__
__J_NO_PARSE_FLT_ARRAY_FN__
__J_NO_PARSE_INTEGER_FN__
__J_NO_PARSE_INT_ARRAY_FN__
__J_NO_PARSE_KEY_FN__
__J_NO_PARSE_PRIMITIVE_FN__
__J_NO_PARSE_STRING_FN__
__J_NO_PARSE_STR_ARRAY_FN__
__J_NO_REGISTER__
__J_NO_SHIBAJS1_PREFIX__
__J_NO_STATIC__
__J_NO_STR_ESCAPE__
__J_NO_ZERO_OUT__
__J_PEDANTIC_PREPROCESS__
__J_TYMEMOD_FLOAT_F64__
__J_TYPEMOD_FLOAT_E64__
__J_TYPEMOD_FLOAT_F32__
__J_TYPEMOD_INTEGER_INT__
__J_TYPEMOD_INTEGER_LONG_LONG__
__J_TYPEMOD_INTEGER_LONG__
__J_TYPEMOD_INTEGER_NONE__
__J_TYPEMOD_INTEGER_SHORT__
__J_TYPEMOD_INTEGER_SIGNED__
__J_TYPEMOD_INTEGER_UNSIGNED__
__J_TYPEMOD_LENGTH_INT__
__J_TYPEMOD_LENGTH_LONG_LONG__
__J_TYPEMOD_LENGTH_LONG__
__J_TYPEMOD_LENGTH_NO_SIGN__
__J_TYPEMOD_LENGTH_SHORT__
__J_TYPEMOD_LENGTH_SIGNED__
__J_TYPEMOD_LENGTH_UNSIGNED__
__J_UNICODE__
__J_USE_ATOF__
__J_USE_ATOI__
__J_USE_ATOLL__
__J_USE_ATOL__
__J_USE_C_PRIMITIVE_VALS__
__J_USE_MALLOC__
__J_USE_MEMCPY__
__J_USE_STRCMP__
__J_USE_STRTOF__
__J_USE_STRTOLD__
__J_USE_STRTOLL__
__J_USE_STRTOL__
__J_USE_STRTOULL__

I do believe these are, name-wise, descriptive enough so I don't need to explain them. But just so you know, if you define __J_PEDANTIC_PREPROCESS__, the preprocessor will warn you about the wrong choices that you may make. The directive __J_NO_ERRORS_AT_PREPROCESS__ will disable any errors that CPP may ommit based on your choices.

As I said, I posted this online mostly for comments. Please share them with me. I have my contacts above, and I will definitely post this on various fora.

Thanks, Chubak!

/*
* Licensing Info: 2023 - Chubak Bidpaa
* This program is free for use under any conditions or lack thereof.
* Redistribution of this file is permitted under the warranty that the
* distributor agrees with the possible errors and shortcomings of this
program.
* There is zero promise that this code will function without any issues.
* This program has been produced for limited, personal use, and although it
is free
* to distribute and use, the author of this program offers nothing in terms
of assurance
* that it will work and function as the distributor or the user expects it
to do so.
* NOTICE: Parts of this program remains partly untested. The reason for
posting this is overall comments
Contact the Author:
* Github: Github.com/chubek
* Email: [email protected]
* Discord: .chubak
---- shibajs1.h: Quick and Dirty JSON Parsing ----
No lexing, no syntax analysis, JUST PARSING!
Notice that this tagline is not a feature. I have made this header-only
'thingy' for my own use, mostly in Native Messaging between my C daemons and
browsers, and other applications with a higher interface which yield a good JSON
serializer. I am posting this application programming interface on the
world-wide web for comments only. However, I am going to teach you how to use
it. Most of shibajs1.h is macros. There's a lot of them. All these macros begin
with J_ as not to be mixed with macros in other source or header files which
will be in the application source tree. If you wish to change this prefix you
may CTRL+F, CTRL+H it. Or you can undefine that macro using `#undef J_[MACRO]`.
shibajs1.h also has another type of macro, which direct the course of CPP in
preprocessing the file. There is a long list of these macros which I will
mention so shortly. These macros, for example, let you control wether you want
Unicode support or not (which is off by default), whether you want your integer
type to be signed, long etc, whether you want the string parser to mind the
escape characters, etc etc.
But before introducing these macros, let me tell you about the functions.
There is a total of 9 functions available. The prefix of these functions is
`shibajs1_*` but you may change it, as we will see later. 8 of these functions
are for parsing various aspects of a JSON stream. The 9th function is for
freeing any memory reserved by the key-value pair. These functions are:
* jstream_t shibajs1_parse_key(jstream_t, jkvpair_t*)
* jstream_t shibajs1_parse_primitive(jstream_t, jkvpair_t*)
* jstream_t shibajs1_parse_integer(jstream_t, jkvpair_t*)
* jstream_t shibajs1_parse_float(jstream_t, jkvpair_t*)
* jstream_t shibajs1_parse_string(jstream_t, jkvpair_t*)
* jstream_t shibajs1_parse_ineger_array(jstream_t, jkvpair_t*, jlength_t)
* jstream_t shibajs1_parse_float_array(jstream_t, jkvpair_t*, jlength_t)
* jstream_t shibajs1_parse_string_array(jstream_t, jkvpair_t*, jlength_t)
* void shibajs1_free_json(jkvpair_t*)
Keep this in mind: shibajs1.h does NOT do any I/O! You yourself must handle the
I/O. Whether it be Unicode, or ASCII. Generally, to parse a this JSON string:
```
{
"myNull": null,
"myTrue": true,
"myFalse": false,
"myInt": 12000,
"myFloat": 1e-12,
"myString": "myValue",
"myIntArray": [
1,
2,
4
],
"myFloatArray": [1.23, 11.2, 1.222, 1e-2],
"myStringArray": [
"myValue1",
"myValue3"
]
}
```
Regardless of where it comes from:
```
jstream_t jstream = "....";
jkvpair_t kvpair;
jstream = shibajs1_parse_key(jstream, &kvpair);
jstream = shibajs1_parse_primitive(jstream, &kvpair);
// ...operate on kvpair...
shibajs1_free_json(&kvpair);
jstream = shibajs1_parse_key(jstream, &kvpair);
jstream = shibajs1_parse_primitive(jstream, &kvpair);
// ...operate on kvpair...
shibajs1_free_json(&kvpair);
jstream = shibajs1_parse_key(jstream, &kvpair);
jstream = shibajs1_parse_primitive(jstream, &kvpair);
// ...operate on kvpair...
shibajs1_free_json(&kvpair);
jstream = shibajs1_parse_key(jstream, &kvpair);
jstream = shibajs1_parse_integer(jstream, &kvpair);
// ...operate on kvpair...
shibajs1_free_json(&kvpair);
jstream = shibajs1_parse_key(jstream, &kvpair);
jstream = shibajs1_parse_float(jstream, &kvpair);
shibajs1_free_json(&kvpair);
jstream = shibajs1_parse_key(jstream, &kvpair);
jstream = shibajs1_parse_string(jstream, &kvpair);
// ...operate on kvpair...
shibajs1_free_json(&kvpair);
jstream = shibajs1_parse_key(jstream, &kvpair);
jstream = shibajs1_parse_integer_array(jstream, &kvpair, 3);
// ...operate on kvpair...
shibajs1_free_json(&kvpair);
jstream = shibajs1_parse_key(jstream, &kvpair);
jstream = shibajs1_parse_float_array(jstream, &kvpair, 4);
shibajs1_free_json(&kvpair);
jstream = shibajs1_parse_key(jstream, &kvpair);
jstream = shibajs1_parse_string_array(jstream, &kvpair, 2);
// ...operate on kvpair...
shibajs1_free_json(&kvpair);
```
You don't need to NECESSIRALY use it like this, this is a general guide line
as of how to utilize the functions. NOTE: ALWAYS FREE THE KEY-VALUE PAIR AFTER
USE!!!! Even if it is an integer, float or a primitive, the key is allocated
dynamically (unless you enable __J_ALLOC_ON_STACK__, as we will see).
So now, let's see what directive preprocessor macros you may use to change the
function of these program. There is a total of 79 macros provided, you can use
any of them basically. Here they are, in alphabetic from:
```
__J_ALLOC_ON_STACK__
__J_CUST_FALSE_LIT_LEN__
__J_CUST_FALSE_LIT__
__J_CUST_FALSE_VAL__
__J_CUST_FLTCONVFN_REENTRANT__
__J_CUST_FLTCONVFN__
__J_CUST_FN_PREFIX__
__J_CUST_INTCONVFN_REENTRANT__
__J_CUST_INTCONVFN__
__J_CUST_INT_BASE__
__J_CUST_MEMALLOCFN__
__J_CUST_MEMALLOCFN___
__J_CUST_MEMCPYFN__
__J_CUST_MEMFREEFN__
__J_CUST_MEMSETFN__
__J_CUST_NULL_LIT_LEN__
__J_CUST_NULL_LIT__
__J_CUST_NULL_VAL__
__J_CUST_PRIMITIVE_VALS__
__J_CUST_SENTINEL__
__J_CUST_STRCMPFN__
__J_CUST_TRUE_LIT_LEN__
__J_CUST_TRUE_LIT__
__J_CUST_TRUE_VAL__
__J_ECONOMIC_ALLOC__
__J_HEX_MSB_LEFT__
__J_NO_ERRORS_AT_PREPROCESS__
__J_NO_FREE_FN__
__J_NO_INC_ALLOCA_H__
__J_NO_INC_STDLIB_H__
__J_NO_INC_STRING_H__
__J_NO_INC_UNISTD_H__
__J_NO_INC_WCHAR_H__
__J_NO_INLINE__
__J_NO_PARSE_FLOAT_FN__
__J_NO_PARSE_FLT_ARRAY_FN__
__J_NO_PARSE_INTEGER_FN__
__J_NO_PARSE_INT_ARRAY_FN__
__J_NO_PARSE_KEY_FN__
__J_NO_PARSE_PRIMITIVE_FN__
__J_NO_PARSE_STRING_FN__
__J_NO_PARSE_STR_ARRAY_FN__
__J_NO_REGISTER__
__J_NO_SHIBAJS1_PREFIX__
__J_NO_STATIC__
__J_NO_STR_ESCAPE__
__J_NO_ZERO_OUT__
__J_PEDANTIC_PREPROCESS__
__J_TYMEMOD_FLOAT_F64__
__J_TYPEMOD_FLOAT_E64__
__J_TYPEMOD_FLOAT_F32__
__J_TYPEMOD_INTEGER_INT__
__J_TYPEMOD_INTEGER_LONG_LONG__
__J_TYPEMOD_INTEGER_LONG__
__J_TYPEMOD_INTEGER_NONE__
__J_TYPEMOD_INTEGER_SHORT__
__J_TYPEMOD_INTEGER_SIGNED__
__J_TYPEMOD_INTEGER_UNSIGNED__
__J_TYPEMOD_LENGTH_INT__
__J_TYPEMOD_LENGTH_LONG_LONG__
__J_TYPEMOD_LENGTH_LONG__
__J_TYPEMOD_LENGTH_NO_SIGN__
__J_TYPEMOD_LENGTH_SHORT__
__J_TYPEMOD_LENGTH_SIGNED__
__J_TYPEMOD_LENGTH_UNSIGNED__
__J_UNICODE__
__J_USE_ATOF__
__J_USE_ATOI__
__J_USE_ATOLL__
__J_USE_ATOL__
__J_USE_C_PRIMITIVE_VALS__
__J_USE_MALLOC__
__J_USE_MEMCPY__
__J_USE_STRCMP__
__J_USE_STRTOF__
__J_USE_STRTOLD__
__J_USE_STRTOLL__
__J_USE_STRTOL__
__J_USE_STRTOULL__
```
I do believe these are, name-wise, descriptive enough so I don't need to
explain them. But just so you know, if you define
`__J_PEDANTIC_PREPROCESS__`, the preprocessor will warn you about the wrong
choices that you may make. The directive `__J_NO_ERRORS_AT_PREPROCESS__` will
disable any errors that CPP may ommit based on your choices.
As I said, I posted this online mostly for comments. Please share them with
me. I have my contacts above, and I will definitely post this on various fora.
Thanks, Chubak!
Fun fact: shibajs1.h has 79! = 8.94618213 E+116 different combinations. Can you generate them all? Haha.
*/
#ifndef __SHIBAJS1_H_
#define __SHIBAJS1_H_
#if !defined(__INC_STDLIB_H_) && !defined(__J_NO_INC_STDLIB_H__)
#define __INC_STDLIB_H_
#include <stdlib.h>
#endif
#if !defined(__INC_STRING_H_) && !defined(__J_NO_INC_STRING_H__)
#define __INC_STRING_H_
#include <string.h>
#endif
#if !defined(__INC_WCHAR_H_) && !defined(__J_NO_INC_WCHAR_H__)
#define __IN_WCHAR_H_
#include <wchar.h>
#endif
#if !defined(__INC_UNISTD_H_) && !defined(__J_NO_INC_UNISTD_H__)
#define __INC_UNISTD_H_
#include <unistd.h>
#endif
#if !defined(__INC_ALLOCA_H_) && !defined(__J_NO_INC_ALLOCA_H__)
#define __INC_ALLOCA_H_
#include <alloca.h>
#endif
#ifdef __J_PEDANTIC_PREPROCESS__
#ifdef __J_CUST_INT_BASE__
#warning \
"Defining a custom base for integers means all the numerical values in the JSON string will be non-compliant to JSON grammar"
#endif
#if defined(__J_CUST_NULL_LIT__) || defined(__J_CUST_TRUE_LIT__) || \
defined(__J_CUST_FALSE_LIT__)
#warning \
"Defining custom literal values for primitives (true, false and null) means they will be non-compliant to the JSON grammar"
#endif
#ifdef __J_USE_MEMCPY__
#warning \
"Sinature of J_MEMCPYFN must be J_MEMCPYFN(void *dst, void *src, integer bytestocopy)"
#endif
#ifdef __J_CUST_MEMFREEFN__
#warning "Sinature of J_MEMFREEFN must be J_MEMFREEFN(void *address)"
#endif
#ifdef J_CUST_MEMSETFN
#warning \
"Sinature of J_MEMSETFN must be J_MEMSETFN(void *memory, integer tofillwith, integer bytestofill)"
#endif
#ifdef __J_CUST_STRCMPFN__
#warning \
"Sinature of J_STRCMPFN must be J_STRCMP(char *str1, char *str2, integer bytesstocompare)"
#endif
#ifdef __J_CUST_MEMALLOCFN__
#warning \
"The signature of J_MEMALLOCFN must be J_MEMALLOCFN(integer totalsize, integer membersize)"
#endif
#if defined(__J_USE_MALLOC__) && defined(__J_NO_ZERO_OUT__)
#warning \
"When using malloc as the J_MEMALLOCFN, it's best not to pass __J_NO_ZERO_OUT__"
#endif
#if defined(__J_USE_ATOF__) && !defined(__J_TYPEMOD_FLOAT_F32__)
#warning "When using atof, it's best to define __J_TYPEMOD_FLOAT_F32__"
#endif
#if defined(__J_USE_STRTOLD__) && !defined(__J_TYPEMOD_FLOAT_E64__)
#warning "When using atoi, it's best to define __J_TYPEMOD_FLOAT_E64__"
#endif
#if defined(__J_USE_STRTOL__) && (!defined(__J_TYPEMOD_INTEGER_LONG__) || \
defined(__J_TYPEMOD_INTEGER_UNSIGNED__))
#warning \
"When using strtol, it's best to define __J_TYPEMOD_INTEGER_LONG__ and don't define __J_TYPEMOD_INTEGER_UNSIGNED__"
#endif
#if defined(__J_USE_STRTOLL__) && \
(!defined(__J_TYPEMOD_INTEGER_LONG_LONG__) || \
defined(__J_TYPEMOD_INTEGER_UNSIGNED__))
#warning \
"When using strtoll, it's best to define __J_TYPEMOD_INTEGER_LONG_LONG__ and don't define __J_TYPEMOD_INTEGER_UNSIGNED__"
#endif
#if defined(__J_USE_STRTOULL__) && (!defined(__J_TYPEMOD_INTEGER_LONG__) || \
!defined(__J_TYPEMOD_INTEGER_UNSIGNED__))
#warning \
"When using strtoull, it's best to define __J_TYPEMOD_INTEGER_LONG_LONG__ and define __J_TYPEMOD_INTEGER_UNSIGNED__"
#endif
#if defined(__J_USE_ATOI__) && !defined(__J_TYPEMOD_INTEGER_INT__)
#warning "When using atoi, it's best to define __J_TYPEMOD_INTEGER_INT__"
#endif
#if defined(__J_CUST_FLTCONVFN__) && defined(__J_CUST_FLTCONVFN_REENTRANT__)
#warning \
"The signature of a reentrant float parser must be J_FLTCONVFN(char *eptr, char **scratch)"
#endif
#if defined(__J_CUST_FLTCONVFN__) && !defined(__J_CUST_INTCONVFN_REENTRANT__)
#warning \
"The signature of a non-reentrant float parser must be J_FLTCONVFN(char *eptr)"
#endif
#if defined(__J_CUST_INTCONVFN__) && defined(__J_CUST_INTCONVFN_REENTRANT__)
#warning \
"The signature of a reentrant integer parser must be J_INTCONVFN(char *eptr, char **scratch)"
#endif
#if defined(__J_CUST_INTCONVFN__) && !defined(__J_CUST_INTCONVFN_REENTRANT__)
#warning \
"The signature of a non-reentrant integer parser must be J_INTCONVFN(char *eptr)"
#endif
#if defined(__J_ALLOC_ON_STACK__) !defined(__INC_ALLOCA_H_)
#warning \
"You have defined __J_ALLOC_ON_STACK__ but have thwarted the inclusion of alloca.h, this could cause complications if this file is not included somewhere else"
#endif
#if !defined(__INC_WCHAR_H_) && defined(__J_UNICODE__)
#warning \
"You have defined __J_UNICODE__ but have thwarted the inclusion of wchar.h, this could cause complications if this file is not included somewhere else"
#endif
#ifdef __J_ALLOC_ON_STACK__
#warning \
"When allocating on the stack, your data only lives within that stack frame (so when a new stack frame is created, e.g. calling a new function, your data is lost)"
#endif
#endif
#ifndef __J_NO_ERRORS_AT_PREPROCESS__
#if defined(__J_CUST_PRIMITIVE_VALS__) && \
(!defined(__J_CUST_TRUE_VAL__) || !defined(__J_CUST_FALSE_VAL__) || \
!defined(__J_CUST_NULL_VAL__))
#error \
"You have defined __J_CUST_PRIMITIVE_VALS__ without all of their respective values (__J_CUST_TRUE_VAL__, __J_CUST_FALSE_VAL__ and __J_CUST_NULL_VAL__), note that these macros must be defined ``in tandem``"
#endif
#if defined(__J_CUST_TRUE_LIT__) && !defined(__J_CUST_TRUE_LIT_LEN__)
#error "You have defined __J_CUST_TRUE_LIT__ without __J_CUST_TRUE_LIT_LEN__"
#endif
#if defined(__J_CUST_FALSE_LIT__) && !defined(__J_CUST_FALSE_LIT_LEN__)
#error "You have defined __J_CUST_FALSE_LIT__ without __J_CUST_FALSE_LIT_LEN__"
#endif
#if defined(__J_CUST_NULL_LIT__) && !defined(__J_CUST_NULL_LIT_LEN__)
#error "You have defined __J_CUST_NULL_LIT__ without __J_CUST_NULL_LIT_LEN__"
#endif
#endif
#ifdef __J_NO_STATIC__
#define J_STATIC
#else
#define J_STATIC static
#endif
#ifdef __J_NO_INLINE__
#define J_INLINE
#else
#define J_INLINE inline
#endif
#ifdef __J_NO_REGISTER__
#define J_REGISTER
#else
#define J_REGISTER register
#endif
#ifdef __J_CUST_MEMFREEFN__
#define J_MEMFREEFN __J_CUST_MEMFREEFN__
#else
#define J_MEMFREEFN free
#endif
#ifdef __J_USE_MEMCPY__
#define J_MEMCPYFN memcpy
#elif __J_CUST_MEMCPYFN__
#define J_MEMCPYFN __J_CUST_MEMCPYFN__
#else
#define J_MEMCPYFN memmove
#endif
#ifdef __J_CUST_MEMSETFN__
#define J_MEMSETFN __J_CUST_MEMSETFN__
#else
#define J_MEMSETFN memset
#endif
#ifdef __J_USE_STRCMP__
#define J_STRCMPFN(str1, str2, len) strcmp(str1, str2)
#elif __J_CUST_STRCMPFN__
#define J_STRCMPFN __J_CUST_STRCMPFN__
#else
#define J_STRCMPFN(str1, str2, len) strncmp(str1, str2, len)
#endif
#ifdef __J_ALLOC_ON_STACK__
#define J_MEMALLOCFN(alloclen, memlen) alloca((alloclen)*memlen)
#elif __J_USE_MALLOC__
#define J_MEMALLOCFN(alloclen, memlen) malloc((alloclen)*memlen)
#elif __J_CUST_MEMALLOCFN__
#define J_MEMALLOCFN __J_CUST_MEMALLOCFN___
#else
#define J_MEMALLOCFN(alloclen, memlen) calloc(alloclen, memlen)
#endif
#ifdef __J_USE_STRTOF__
#define J_FLTCONVFN strtof
#elif __J_USE_STRTOLD__
#define J_FLTCONVFN strtold
#elif __J_USE_ATOF__
#define J_FLTCONVFN(eptr, spare) atof(eptr)
#elif defined(__J_CUST_FLTCONVFN__) && defined(__J_CUST_FLTCONVFN_REENTRANT__)
#define J_FLTCONVFN __J_CUST_FLTCONVFN__
#elif defined(__J_CUST_FLTCONVFN__) && !defined(__J_CUST_FLTCONVFN_REENTRANT__)
#define J_FLTCONVFN(eptr, spare) __J_CUST_FLTCONVFN__(eptr, spare)
#else
#define J_FLTCONVFN strtod
#endif
#ifdef __J_USE_STRTOLL__
#define J_INTCONVFN strtoll
#elif __J_USE_STRTOULL__
#define J_INTCONVFN strtoull
#elif __J_USE_STRTOL__
#define J_INTCONVFN strtol
#elif __J_USE_ATOI__
#define J_INTCONVFN(eptr, spare1, spare2) atoi(eptr)
#elif __J_USE_ATOL__
#define J_INTCONVFN(eptr, spare1, spare2) atol(eptr)
#elif __J_USE_ATOLL__
#define J_INTCONVFN(eptr, spare1, spare2) atoll(eptr)
#elif defined(__J_CUST_INTCONVFN__) && defined(__J_CUST_INTCONVFN_REENTRANT__)
#define J_INTCONVFN __J_CUST_INTCONVFN__
#elif defined(__J_CUST_INTCONVFN__) && !defined(__J_CUST_INTCONVFN_REENTRANT__)
#define J_INTCONVFN(eptr, spare) __J_CUST_INTCONVFN__(eptr, spare)
#else
#define J_INTCONVFN strtoul
#endif
#ifdef __J_CUST_PRIMITIVE_VALS__
#define J_TRUE __J_CUST_TRUE_VAL__
#define J_FALSE __J_CUST_FALSE_VAL__
#define J_NULL __J_CUST_NULL_VAL__
#elif __J_USE_C_PRIMITIVE_VALS__
#define J_TRUE 1
#define J_FALSE 0
#define J_NULL NULL
#else
#define J_TRUE 1
#define J_FALSE 2
#define J_NULL 3
#endif
#if defined(__J_CUST_TRUE_LIT__) && defined(__J_CUST_TRUE_LIT_LEN__)
#define J_TRUE_LIT __J_CUST_TRUE_LIT__
#define J_TRUE_LIT_LEN __J_CUST_TRUE_LIT_LEN__
#else
#define J_TRUE_LIT "true"
#define J_TRUE_LIT_LEN 5
#endif
#if defined(__J_CUST_FALSE_LIT__) && defined(__J_CUST_FALSE_LIT_LEN__)
#define J_FALSE_LIT __J_CUST_FALSE_LIT__
#define J_FALSE_LIT_LEN __J_CUST_FALSE_LIT_LEN__
#else
#define J_FALSE_LIT "false"
#define J_FALSE_LIT_LEN 6
#endif
#if defined(__J_CUST_NULL_LIT__) && defined(__J_CUST_NULL_LIT_LEN__)
#define J_NULL_LIT __J_CUST_NULL_LIT__
#define J_NULL_LIT_LEN __J_CUST_NULL_LIT_LEN__
#else
#define J_NULL_LIT "null"
#define J_NULL_LIT_LEN 4
#endif
#ifdef __J_CUST_INT_BASE__
#define J_INT_BASE __J_CUST_INT_BASE__
#else
#define J_INT_BASE 10
#endif
#ifdef __J_CUST_SENTINEL__
#define J_SENTINEL __J_CUST_SENTINEL__
#else
#define J_SENTINEL -1
#endif
#ifdef __J_TYPEMOD_LENGTH_SIGNED__
#define J_TYPEMOD_LENGTH_SIGN signed
#elif __J_TYPEMOD_LENGTH_UNSIGNED__
#define J_TYPEMOD_LENGTH_SIGN unsigned
#elif __J_TYPEMOD_LENGTH_NO_SIGN__
#define J_TYPEMOD_LENGTH_SIGN
#else
#define J_TYPEMOD_LENGTH_SIGN unsigned
#endif
#ifdef __J_TYPEMOD_INTEGER_SIGNED__
#define J_TYPEMOD_INTEGER_SIGN signed
#elif __J_TYPEMOD_INTEGER_UNSIGNED__
#define J_TYPEMOD_INTEGER_SIGN unsigned
#elif __J_TYPEMOD_INTEGER_NONE__
#define J_TYPEMOD_INTEGER_SIGN
#else
#define J_TYPEMOD_INTEGER_SIGN unsigned
#endif
#ifdef __J_TYPEMOD_LENGTH_LONG__
#define J_TYPEMOD_LENGTH_SIZE long int
#elif __J_TYPEMOD_LENGTH_LONG_LONG__
#define J_TYPEMOD_LENGTH_SIZE long long int
#elif __J_TYPEMOD_LENGTH_SHORT__
#define J_TYPEMOD_LENGTH_SIZE short int
#elif __J_TYPEMOD_LENGTH_INT__
#define J_TYPEMOD_LENGTH_SIZE int
#else
#define J_TYPEMOD_LENGTH_SIZE long int
#endif
#ifdef __J_TYPEMOD_INTEGER_LONG__
#define J_TYPEMOD_INTEGER_SIZE long int
#elif __J_TYPEMOD_INTEGER_LONG_LONG__
#define J_TYPEMOD_INTEGER_SIZE long long int
#elif __J_TYPEMOD_INTEGER_SHORT__
#define J_TYPEMOD_INTEGER_SIZE short int
#elif __J_TYPEMOD_INTEGER_INT__
#define J_TYPEMOD_INTEGER_SIZE int
#else
#define J_TYPEMOD_INTEGER_SIZE long int
#endif
#define J_LENGTH_TYPE J_TYPEMOD_LENGTH_SIGN J_TYPEMOD_LENGTH_SIZE
#define J_INTEGER_TYPE J_TYPEMOD_INTEGER_SIGN J_TYPEMOD_INTEGER_SIZE
#ifdef __J_TYPEMOD_FLOAT_F32__
#define J_FLOAT_TYPE float
#elif __J_TYMEMOD_FLOAT_F64__
#define J_FLOAT_TYPE double
#elif __J_TYPEMOD_FLOAT_E64__
#define J_FLOAT_TYPE long double
#else
#define J_FLOAT_TYPE double
#endif
#ifdef __J_UNICODE__
#define J_CHAR_TYPE wchar_t
#else
#define J_CHAR_TYPE char
#endif
#define J_UNICODE_ESCAPE_LEN 4
#define J_ESCAPE_SEQ_LEN 2
#define J_INT_BASE_HEXA 16
#define J_STATICMEM_INTEGER 0ULL
#define J_STATICMEM_FLOAT 2ULL
#define J_STATICMEM_PRIMITIVE 4ULL
#define J_ALLOCABLE_STRING 1ULL
#define J_ALLOCABLE_INTEGER 3ULL
#define J_ALLOCABLE_FLOAT 7ULL
#define J_ALLOCABLE_MEMADDR 15ULL
#define J_CURR_CHR(stream) *stream
#define J_ADVANCE_PTR(stream) stream++
#define J_ADVANCE_PTR_N(stream, n) stream += n
#define J_NEXT_CHR(stream) *stream++
#define J_PEEK_NXT(stream) *(stream + 1)
#define J_PEEK_PRV(stream) *(stream - 2)
#ifndef __J_UNICODE__
#define J_IS_SENTINEL(character) (character == J_SENTINEL)
#define J_IS_NULLCHR(character) (character == '\0')
#define J_IS_QUOTE(character) (character == '"')
#define J_IS_LBRACK(character) (character == '[')
#define J_IS_RBRACK(character) (character == ']')
#define J_IS_LCURLY(character) (character == '{')
#define J_IS_RCURLY(character) (character == '}')
#define J_IS_BSOLIDUS(character) (character == '\\')
#define J_IS_COMMA(character) (character == ',')
#define J_IS_COLON(character) (character == ':')
#define J_IS_DIGIT(character) (character >= '0' && character <= '9')
#define J_IS_SIGN(character) (character == '+' || character == '-')
#define J_IS_EXP(character) (character == 'e' || character == 'E')
#define J_IS_FRACT(character) (character == '.')
#define J_IS_UNCDESCAPE(character) (character == 'u')
#define J_IS_ESCAPECHR(character) \
(character == 'b' || character == 'u' || character == 'n' || \
character == '\\' || character == '/' || character == 't' || \
character == 'r' || character == 'f')
#define J_IS_WSPACE(character) \
(character == '\n' || character == ' ' || character == '\t' || \
character == '\r')
#define J_IS_PRINTABLE(character) (character >= ' ')
#else
#define J_IS_SENTINEL(character) (character == J_SENTINEL)
#define J_IS_NULLCHR(character) (character == L'\0')
#define J_IS_QUOTE(character) (character == L'"')
#define J_IS_LBRACK(character) (character == L'[')
#define J_IS_RBRACK(character) (character == L']')
#define J_IS_LCURLY(character) (character == L'{')
#define J_IS_RCURLY(character) (character == L'}')
#define J_IS_BSOLIDUS(character) (character == L'\\')
#define J_IS_COMMA(character) (character == L',')
#define J_IS_COLON(character) (character == L':')
#define J_IS_DIGIT(character) (character >= L'0' && character <= L'9')
#define J_IS_SIGN(character) (character == L'+' || character == L'-')
#define J_IS_EXP(character) (character == L'e' || character == L'E')
#define J_IS_FRACT(character) (character == L'.')
#define J_IS_UNCDESCAPE(character) (character == L'u')
#define J_IS_ESCAPECHR(character) \
(character == L'b' || character == L'u' || character == L'n' || \
character == L'\\' || character == L'/' || character == L't' || \
character == L'r' || character == L'f')
#define J_IS_WSPACE(character) \
(character == L'\n' || character == L' ' || character == L'\t' || \
character == L'\r')
#define J_IS_PRINTABLE(character) (character >= L' ')
#endif
#define J_QUOTE_NO_ESCAPE(chrcur, chrprv) \
(J_IS_QUOTE(chrcur) && !J_IS_BSOLIDUS(chrprv))
#define J_IS_KVSEP(character) (J_IS_COLON(character) || J_IS_WSPACE(character))
#define J_IS_VTERM(character) \
(J_IS_COMMA(character) || J_IS_RCURLY(character) || \
J_IS_WSPACE(character) || J_IS_SENTINEL(character) || \
J_IS_NULLCHR(character))
#define J_IS_CONTEXT(character) \
(J_IS_LCURLY(character) || J_IS_WSPACE(character) || J_IS_COMMA(character))
#define J_IS_ELTERM(character) \
(J_IS_COMMA(character) || J_IS_RBRACK(character) || J_IS_WSPACE(character))
#define J_IS_FLOAT(character) \
(J_IS_DIGIT(character) || J_IS_FRACT(character) || J_IS_EXP(character) || \
J_IS_SIGN(character))
#define J_IS_INTEGER(character) (J_IS_DIGIT(character) || J_IS_SIGN(character))
#define J_INT_ELEMENT_ENDED(stream, character) \
(J_IS_INTEGER(character) && J_IS_ELTERM(J_CURR_CHR(stream)))
#define J_FLT_ELEMENT_ENDED(stream, character) \
(J_IS_FLOAT(character) && J_IS_ELTERM(J_CURR_CHR(stream)))
#define J_STR_BEGAN(stream, character) \
(J_IS_PRINTABLE(J_CURR_CHR(stream)) && J_IS_QUOTE(character) && \
J_IS_KVSEP(J_PEEK_PRV(stream)))
#define J_STR_ENDED(stream, character) \
(J_QUOTE_NO_ESCAPE(J_CURR_CHR(stream), character) && \
J_IS_VTERM(J_PEEK_NXT(stream)))
#define J_INT_BEGAN(stream, character) \
(J_IS_INTEGER(J_CURR_CHR(stream)) && J_IS_KVSEP(character))
#define J_INT_ENDED(stream, character) \
(J_IS_INTEGER(character) && J_IS_VTERM(J_CURR_CHR(stream)))
#define J_FLT_BEGAN(stream, character) \
(J_IS_FLOAT(J_CURR_CHR(stream)) && J_IS_KVSEP(character))
#define J_FLT_ENDED(stream, character) \
(J_IS_FLOAT(character) && J_IS_VTERM(J_CURR_CHR(stream)))
#define J_ARR_BEGAN(stream, character) \
(J_IS_LBRACK(J_CURR_CHR(stream)) && J_IS_KVSEP(character))
#define J_VAL_BEGAN(stream, character) \
(J_IS_KVSEP(J_PEEK_PRV(stream)) && J_IS_PRINTABLE(character))
#define J_VAL_ENDED(stream, character) \
(J_IS_VTERM(J_CURR_CHR(stream)) && J_IS_PRINTABLE(character))
#define J_KEY_BEGAN(stream, character) \
(J_IS_PRINTABLE(J_CURR_CHR(stream)) && J_IS_QUOTE(character) && \
J_IS_CONTEXT(J_PEEK_PRV(stream)))
#define J_KEY_ENDED(stream, character) \
(J_QUOTE_NO_ESCAPE(J_CURR_CHR(stream), character) && \
J_IS_KVSEP(J_PEEK_NXT(stream)))
#define J_SKIP_TIL_STR_BEGIN(stream, character) \
for (character = J_CURR_CHR(stream); !J_STR_BEGAN(stream, character); \
character = J_NEXT_CHR(stream))
#define J_SKIP_TIL_STR_ENDED(stream, character) \
for (character = J_CURR_CHR(stream); !J_STR_ENDED(stream, character); \
character = J_NEXT_CHR(stream))
#define J_SKIP_TIL_INT_BEGIN(stream, character) \
for (character = J_CURR_CHR(stream); !J_INT_BEGAN(stream, character); \
character = J_NEXT_CHR(stream))
#define J_SKIP_TIL_INT_ENDED(stream, character) \
for (character = J_CURR_CHR(stream); !J_INT_ENDED(stream, character); \
character = J_NEXT_CHR(stream))
#define J_SKIP_TIL_FLT_BEGIN(stream, character) \
for (character = J_CURR_CHR(stream); !J_FLT_BEGAN(stream, character); \
character = J_NEXT_CHR(stream))
#define J_SKIP_TIL_FLT_ENDED(stream, character) \
for (character = J_CURR_CHR(stream); !J_FLT_ENDED(stream, character); \
character = J_NEXT_CHR(stream))
#define J_SKIP_TIL_ARR_BEGIN(stream, character) \
for (character = J_CURR_CHR(stream); !J_ARR_BEGAN(stream, character); \
character = J_NEXT_CHR(stream))
#define J_SKIP_TIL_KEY_BEGIN(stream, character) \
for (character = J_CURR_CHR(stream); !J_KEY_BEGAN(stream, character); \
character = J_NEXT_CHR(stream))
#define J_SKIP_TIL_KEY_ENDED(stream, character) \
for (character = J_CURR_CHR(stream); !J_KEY_ENDED(stream, character); \
character = J_NEXT_CHR(stream))
#define J_SKIP_TIL_VAL_BEGIN(stream, character) \
for (character = J_CURR_CHR(stream); !J_VAL_BEGAN(stream, character); \
character = J_NEXT_CHR(stream))
#define J_SKIP_TIL_VAL_ENDED(stream, character) \
for (character = J_CURR_CHR(stream); !J_VAL_ENDED(stream, character); \
character = J_NEXT_CHR(stream))
#define J_ADDR_REF(arr) (void *)&arr[0]
#ifndef __J_NO_ZERO_OUT__
#define J_ZERO_OUT(stream, len) J_MEMSETFN(J_ADDR_REF(stream), 0, len)
#else
#define J_ZERO_OUT(stream, len)
#endif
#ifndef __J_NO_SHIBAJS1_PREFIX__
#define J_DECL_FN(rettype, fnname, ...) \
J_STATIC J_INLINE rettype shibajs1_##fnname(__VA_ARGS__)
#elif __J_CUST_FN_PREFIX__
#define J_DECL_FN(rettype, fnname, ...) \
J_STATIC J_INLINE rettype __J_CUST_FN_PREFIX__##fnname(__VA_ARGS__)
#else
#define J_DECL_FN(rettype, fnname, ...) \
J_STATIC J_INLINE rettype fnname(__VA_ARGS__)
#endif
#define J_INIT_PARSE_FN(jsonStream, tmpChar, tmpLen, tmpStream, mainStream) \
J_REGISTER jchar_t tmpChar = 0; \
J_REGISTER jlength_t tmpLen = 0; \
J_REGISTER jstream_t tmpStream, mainStream; \
mainStream = &jsonStream[0]
#define J_GET_ALLOC_LEN(tmpLen, tmpStream, mainStream) \
tmpLen = (jlength_t)(tmpStream - mainStream)
#define J_ALLOC_STATIC_ASCIIZ(strName, strLen) jchar_t strName[strLen + 1]
#define J_ALLOC_KV_MEMORY(address, size, unit) \
address = J_MEMALLOCFN(size, unit)
#define J_ASSIGN_KV_TYPE(pair, tyy) pair->type = tyy
#define J_MAKE_ASCIIZ(stream) *(stream) = '\0'
#define J_ASCIIZ_LEN(len) (len + 1) * sizeof(jchar_t)
#define J_PARSE_INTEGER_VALUE(integerDst, intString) \
do { \
jstring_t scratch; \
integerDst = (jinteger_t)J_INTCONVFN(intString, &scratch, J_INT_BASE); \
} while (0)
#define J_PARSE_FLOAT_VALUE(floatDst, floatString) \
do { \
jstring_t scratch; \
floatDst = (jfloat_t)J_FLTCONVFN(floatString, &scratch); \
} while (0)
#define J_ASSIGN_ADDR(address, stream) address = &stream[0]
#define J_NULLIFY_ADDR(address) address = NULL
#ifdef __J_HEX_MSB_LEFT__
#define J_SHORT_TO_BYTE(shortint, dstbytemsb, dstbytelsb) \
do { \
dstbytelsb = (jchar_t)((shortint)&0xff); \
dstbytemsb = (jchar_t)((shortint & 0xff00) >> 8); \
} while (0)
#else
#define J_SHORT_TO_BYTE(shortint, dstbytemsb, dstbytelsb) \
do { \
dstbytemsb = (jchar_t)((shortint)&0xff); \
dstbytelsb = (jchar_t)((shortint & 0xff00) >> 8); \
} while (0)
#endif
#define J_TOKENIZE_LOOP(str, sep, scratch, tok) \
for (tok = J_STRTOKFN(str, sep, &scratch); tok; \
tok = J_STRTOKFN(str, sep, &scratch))
#ifndef __J_UNICODE__
#define J_PARSE_ESCAPE_UNICODE(mainStream, destination) \
do { \
unsigned short unicodeInteger = 0; \
const char unicodeString[J_UNICODE_ESCAPE_LEN + 1]; \
J_MEMCPYFN(J_ADDR_REF(unicodeString), J_ADDR_REF(mainStream) + 1, \
J_UNICODE_ESCAPE_LEN); \
unicodeInteger = J_INTCONVFN(unicodeString, NULL, J_INT_BASE_HEXA); \
J_SHORT_TO_BYTE(unicodeInteger, J_NEXT_CHR(destination), \
J_NEXT_CHR(destination)); \
J_ADVANCE_PTR_N(mainStream, J_UNICODE_ESCAPE_LEN + 2); \
} while (0)
#else
#define J_PARSE_ESCAPE_UNICODE(mainStream, destination) \
do { \
unsigned short unicodeInteger = 0; \
const char unicodeString[J_UNICODE_ESCAPE_LEN + 1]; \
J_MEMCPYFN(J_ADDR_REF(unicodeString), J_ADDR_REF(mainStream) + 1, \
J_UNICODE_ESCAPE_LEN); \
unicodeInteger = J_INTCONVFN(unicodeString, NULL, J_INT_BASE_HEXA); \
*(destination) = unicodeInteger; \
J_ADVANCE_PTR(destination); \
J_ADVANCE_PTR_N(mainStream, J_UNICODE_ESCAPE_LEN + 2); \
} while (0)
#endif
#ifdef __J_ECONOMIC_ALLOC__
#define J_ECONOMIZE_STR_LENGTH(stream, character, dstlen) \
do { \
jstream_t streamCopy = stream; \
J_REGISTER jlength_t lenCopy = dstlen; \
for (character = J_CURR_CHR(streamCopy); lenCopy--; \
character = J_NEXT_CHR(streamCopy)) { \
if (J_IS_BSOLIDUS(character) && \
J_IS_ESCAPECHR(J_PEEK_NXT(streamCopy))) { \
character = J_NEXT_CHR(streamCopy); \
if (J_IS_UNCDESCAPE(character)) { \
dstlen -= J_UNICD_NUM_LEN; \
streamCopy += J_UNICD_NUM_LEN * sizeof(jchar_t); \
} else { \
dstlen -= J_ESCAPE_SEQ_LEN; \
} \
} \
} \
} while (0)
#else
#define J_ECONOMIZE_STR_LENGTH(stream, character, len)
#endif
#ifndef __J_NO_STR_ESCAPE__
#define J_STR_PARSE_LOOP(stream, character, length, head) \
do { \
jstring_t streamCopy = stream; \
jstring_t headCopy = head; \
J_REGISTER jlength_t lengthCopy = length; \
do { \
character = J_NEXT_CHR(streamCopy); \
if (character == '\\') { \
character = J_NEXT_CHR(streamCopy); \
--lengthCopy; \
switch (character) { \
case 'b': \
character = '\b'; \
break; \
case 'f': \
character = '\f'; \
break; \
case 'n': \
character = '\n'; \
break; \
case 'r': \
character = '\r'; \
break; \
case 't': \
character = '\t'; \
break; \
case 'u': \
J_PARSE_ESCAPE_UNICODE(streamCopy, head); \
continue; \
default: \
break; \
} \
} \
*(headCopy++) = character; \
} while (--lengthCopy); \
} while (0)
#else
#define J_STR_PARSE_LOOP(stream, character, length, head) \
do { \
jstring_t streamCopy = stream; \
jstring_t headCopy = head; \
J_REGISTER jlength_t lengthCopy = length; \
for (*(headCopy++) = J_NEXT_CHR(streamCopy); --lengthCopy; \
*(headCopy++) = J_NEXT_CHR(streamCopy)) \
; \
} while (0)
#endif
#define J_INT_ARRAY_PARSE_LOOP(stream, character, numElements, destination) \
do { \
jstring_t scratch, integerContext = NULL; \
J_REGISTER jlength_t elementIdx = 0; \
do { \
character = J_NEXT_CHR(stream); \
if (!integerContext && J_IS_INTEGER(J_CURR_CHR(stream))) \
J_ASSIGN_ADDR(integerContext, stream); \
else if (integerContext && J_INT_ELEMENT_ENDED(stream, character)) { \
J_MAKE_ASCIIZ(stream); \
J_PARSE_INTEGER_VALUE(destination[elementIdx++], integerContext); \
J_NULLIFY_ADDR(integerContext); \
} else \
continue; \
} while (numElements > elementIdx); \
} while (0)
#define J_FLT_ARRAY_PARSE_LOOP(stream, character, numElements, destination) \
do { \
jstring_t scratch, floatContext = NULL; \
J_REGISTER jlength_t elementIdx = 0; \
do { \
character = J_NEXT_CHR(stream); \
if (!floatContext && J_IS_FLOAT(J_CURR_CHR(stream))) \
J_ASSIGN_ADDR(floatContext, stream); \
else if (floatContext && J_FLT_ELEMENT_ENDED(stream, character)) { \
J_MAKE_ASCIIZ(stream); \
J_PARSE_FLOAT_VALUE(destination[elementIdx++], floatContext); \
J_NULLIFY_ADDR(floatContext); \
} else \
continue; \
} while (numElements > elementIdx); \
} while (0)
#define J_STR_ARRAY_PARSE_LOOP(stream, character, numElements, destination) \
do { \
jstring_t head, stringContext = NULL; \
J_REGISTER jlength_t elementIdx = 0, currentLength = 0; \
do { \
character = J_NEXT_CHR(stream); \
if (J_QUOTE_NO_ESCAPE(J_CURR_CHR(stream), character)) { \
if (!stringContext) \
J_ASSIGN_ADDR(stringContext, (++stream)); \
else { \
J_GET_ALLOC_LEN(currentLength, stream, stringContext); \
J_ECONOMIZE_STR_LENGTH(stringContext, character, currentLength); \
J_ALLOC_KV_MEMORY(destination[elementIdx++] = head, currentLength, \
sizeof(jchar_t)); \
J_STR_PARSE_LOOP(stringContext, character, currentLength, head); \
J_NULLIFY_ADDR(stringContext); \
} \
} else if (J_IS_WSPACE(character)) \
continue; \
} while (numElements > elementIdx); \
} while (0)
typedef J_FLOAT_TYPE jfloat_t;
typedef J_INTEGER_TYPE jinteger_t;
typedef J_LENGTH_TYPE jlength_t;
typedef J_CHAR_TYPE *jstream_t;
typedef J_CHAR_TYPE *jstring_t;
typedef J_CHAR_TYPE *jkey_t;
typedef J_CHAR_TYPE jchar_t;
typedef J_INTEGER_TYPE jtype_t;
typedef J_INTEGER_TYPE jprimitive_t;
typedef struct JsonKVPair {
jkey_t key;
union {
jinteger_t integer;
jfloat_t floatNum;
jstring_t string;
jprimitive_t primFalse;
jprimitive_t primTrue;
jprimitive_t primNull;
jfloat_t *floatArray;
jinteger_t *integerArray;
jstring_t *stringArray;
} value;
jtype_t type;
} jkvpair_t;
#ifndef __J_NO_PARSE_KEY_FN__
J_DECL_FN(jstream_t, parse_key, jstream_t jsonStream, jkvpair_t *kvpair) {
J_INIT_PARSE_FN(jsonStream, tmpChar, tmpLen, tmpStream, mainStream);
J_SKIP_TIL_KEY_BEGIN(mainStream, tmpChar);
J_ASSIGN_ADDR(tmpStream, mainStream);
J_SKIP_TIL_KEY_ENDED(tmpStream, tmpChar);
J_GET_ALLOC_LEN(tmpLen, tmpStream, mainStream);
J_ALLOC_KV_MEMORY(kvpair->key, tmpLen + 1, sizeof(jchar_t));
J_ZERO_OUT(kvpair->key, J_ASCIIZ_LEN(tmpLen));
J_MEMCPYFN(J_ADDR_REF(kvpair->key), J_ADDR_REF(mainStream),
tmpLen * sizeof(jchar_t));
return tmpStream;
}
#endif
#ifndef __J_NO_PARSE_PRIMITIVE_FN__
J_DECL_FN(jstream_t, parse_primitive, jstream_t jsonStream, jkvpair_t *kvpair) {
J_INIT_PARSE_FN(jsonStream, tmpChar, tmpLen, tmpStream, mainStream);
J_SKIP_TIL_VAL_BEGIN(mainStream, tmpChar);
J_ASSIGN_ADDR(tmpStream, mainStream);
J_SKIP_TIL_VAL_ENDED(tmpStream, tmpChar);
J_GET_ALLOC_LEN(tmpLen, tmpStream, mainStream);
J_ALLOC_STATIC_ASCIIZ(primStr, tmpLen);
J_ZERO_OUT(primStr, J_ASCIIZ_LEN(tmpLen));
J_MEMCPYFN(J_ADDR_REF(primStr), mainStream, tmpLen);
if (!J_STRCMPFN(primStr, J_TRUE_LIT, J_TRUE_LIT_LEN))
kvpair->value.primTrue = J_TRUE;
else if (!J_STRCMPFN(primStr, J_FALSE_LIT, J_FALSE_LIT_LEN))
kvpair->value.primFalse = J_FALSE;
else if (!J_STRCMPFN(primStr, J_NULL_LIT, J_NULL_LIT_LEN))
kvpair->value.primNull = J_NULL;
J_ASSIGN_KV_TYPE(kvpair, J_STATICMEM_PRIMITIVE);
return tmpStream;
}
#endif
#ifndef __J_NO_PARSE_INTEGER_FN__
J_DECL_FN(jstream_t, parse_integer, jstream_t jsonStream, jkvpair_t *kvpair) {
J_INIT_PARSE_FN(jsonStream, tmpChar, tmpLen, tmpStream, mainStream);
J_SKIP_TIL_INT_BEGIN(mainStream, tmpChar);
J_ASSIGN_ADDR(tmpStream, mainStream);
J_SKIP_TIL_INT_ENDED(tmpStream, tmpChar);
J_GET_ALLOC_LEN(tmpLen, tmpStream, mainStream);
J_ALLOC_STATIC_ASCIIZ(intString, tmpLen);
J_ZERO_OUT(intString, J_ASCIIZ_LEN(tmpLen));
J_MEMCPYFN(J_ADDR_REF(intString), mainStream, tmpLen);
J_PARSE_INTEGER_VALUE(kvpair->value.integer, intString);
J_ASSIGN_KV_TYPE(kvpair, J_STATICMEM_INTEGER);
return tmpStream;
}
#endif
#ifndef __J_NO_PARSE_FLOAT_FN__
J_DECL_FN(jstream_t, parse_float, jstream_t jsonStream, jkvpair_t *kvpair) {
J_INIT_PARSE_FN(jsonStream, tmpChar, tmpLen, tmpStream, mainStream);
J_SKIP_TIL_FLT_BEGIN(mainStream, tmpChar);
J_ASSIGN_ADDR(tmpStream, mainStream);
J_SKIP_TIL_FLT_ENDED(tmpStream, tmpChar);
J_GET_ALLOC_LEN(tmpLen, tmpStream, mainStream);
J_ALLOC_STATIC_ASCIIZ(floatString, tmpLen);
J_ZERO_OUT(floatString, J_ASCIIZ_LEN(tmpLen));
J_MEMCPYFN(J_ADDR_REF(floatString), mainStream, tmpLen);
J_PARSE_FLOAT_VALUE(kvpair->value.floatNum, floatString);
J_ASSIGN_KV_TYPE(kvpair, J_STATICMEM_FLOAT);
return tmpStream;
}
#endif
#ifndef __J_NO_PARSE_STRING_FN__
J_DECL_FN(jstream_t, parse_string, jstream_t jsonStream, jkvpair_t *kvpair) {
J_INIT_PARSE_FN(jsonStream, tmpChar, tmpLen, tmpStream, mainStream);
J_SKIP_TIL_STR_BEGIN(mainStream, tmpChar);
J_ASSIGN_ADDR(tmpStream, mainStream);
J_SKIP_TIL_STR_ENDED(tmpStream, tmpChar);
J_GET_ALLOC_LEN(tmpLen, tmpStream, mainStream);
J_ECONOMIZE_STR_LENGTH(mainStream, tmpChar, tmpLen);
J_ALLOC_KV_MEMORY(kvpair->value.string, tmpLen + 1, sizeof(jchar_t));
J_ZERO_OUT(kvpair->value.string, J_ASCIIZ_LEN(tmpLen));
J_STR_PARSE_LOOP(mainStream, tmpChar, tmpLen, kvpair->value.string);
J_ASSIGN_KV_TYPE(kvpair, J_ALLOCABLE_STRING | (tmpLen << 4));
return tmpStream;
}
#endif
#ifndef __J_NO_PARSE_INT_ARRAY_FN__
J_DECL_FN(jstream_t, parse_integer_array, jstream_t jsonStream,
jkvpair_t *kvpair, jlength_t numElements) {
J_INIT_PARSE_FN(jsonStream, tmpChar, tmpLen, tmpStream, mainStream);
J_SKIP_TIL_ARR_BEGIN(mainStream, tmpChar);
J_ASSIGN_ADDR(tmpStream, mainStream);
J_ALLOC_KV_MEMORY(kvpair->value.integerArray, numElements,
sizeof(jinteger_t));
J_ZERO_OUT(kvpair->value.integerArray, numElements * sizeof(jinteger_t));
J_INT_ARRAY_PARSE_LOOP(tmpStream, tmpChar, numElements,
kvpair->value.integerArray);
J_ASSIGN_KV_TYPE(kvpair, J_ALLOCABLE_INTEGER | (numElements << 4));
return tmpStream;
}
#endif
#ifndef __J_NO_PARSE_FLT_ARRAY_FN__
J_DECL_FN(jstream_t, parse_float_array, jstream_t jsonStream, jkvpair_t *kvpair,
jlength_t numElements) {
J_INIT_PARSE_FN(jsonStream, tmpChar, tmpLen, tmpStream, mainStream);
J_SKIP_TIL_ARR_BEGIN(mainStream, tmpChar);
J_ASSIGN_ADDR(tmpStream, mainStream);
J_ALLOC_KV_MEMORY(kvpair->value.floatArray, numElements, sizeof(jfloat_t));
J_ZERO_OUT(kvpair->value.floatArray, numElements * sizeof(jfloat_t));
J_FLT_ARRAY_PARSE_LOOP(tmpStream, tmpChar, numElements,
kvpair->value.floatArray);
J_ASSIGN_KV_TYPE(kvpair, J_ALLOCABLE_FLOAT | (numElements << 4));
return tmpStream;
}
#endif
#ifndef __J_NO_PARSE_STR_ARRAY_FN__
J_DECL_FN(jstream_t, parse_string_array, jstream_t jsonStream,
jkvpair_t *kvpair, jlength_t numElements) {
J_INIT_PARSE_FN(jsonStream, tmpChar, tmpLen, tmpStream, mainStream);
J_SKIP_TIL_ARR_BEGIN(mainStream, tmpChar);
J_ASSIGN_ADDR(tmpStream, mainStream);
J_ALLOC_KV_MEMORY(kvpair->value.stringArray, numElements, sizeof(jstring_t));
J_ZERO_OUT(kvpair->value.stringArray, numElements * sizeof(jstring_t));
J_STR_ARRAY_PARSE_LOOP(tmpStream, tmpChar, numElements,
kvpair->value.stringArray);
J_ASSIGN_KV_TYPE(kvpair, J_ALLOCABLE_MEMADDR | (numElements << 4));
return tmpStream;
}
#endif
#ifndef __J_NO_FREE_FN__
J_DECL_FN(void, free_json, jkvpair_t *kvpair) {
J_MEMFREEFN(kvpair->key);
switch (kvpair->type & 0xf) {
case J_ALLOCABLE_STRING:
J_MEMFREEFN(kvpair->value.string);
break;
case J_ALLOCABLE_INTEGER:
J_MEMFREEFN(kvpair->value.integerArray);
break;
case J_ALLOCABLE_FLOAT:
J_MEMFREEFN(kvpair->value.floatArray);
break;
case J_ALLOCABLE_MEMADDR:
for (J_REGISTER jlength_t i = 0; i < ((kvpair->type & ~0xfULL) >> 4); i++) {
J_MEMFREEFN(kvpair->value.stringArray[i]);
}
J_MEMFREEFN(kvpair->value.stringArray);
break;
default:
break;
}
}
#endif
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment