23 Dec

Full Simplified JSON support in json.h

In a previous post (Partial) Simplified JSON support in json.h I covered the partially added simplified JSON support I had added to json.h. One of the things I covered was my unwillingness to implement two of the features of simplified JSON, commas being optional and replacing : with =. I argued that both of these were unnecessary and stupid additions to the library.

I was wrong. The immediate feedback I received detailed good reasons why these were useful, but more importantly – why did I half-arse implementing a feature that was requested by a user!

So today, I’ve implemented all of simplified JSON. You can now parse;

foo = "bar"
yada = 2
meow = true

by using the following code;

const char payload[] = ...; // the string above!
json_value_s* json = json_parse_ex(
  payload,
  strlen(payload),
  json_parse_flags_allow_simplified_json,
  0);

A few caveats to remember when writing/using this code though:

  • json_parse_flags_allow_simplified_json is a bitmask enabling many other json_parse_flags that you can enable separately. As such, the behaviour of each of them applies collectively when using this flag
  • commas aren’t banned, they are just not required. You can mix commas/no-commas throughout your simplified JSON. You can also have trailing commas after the last element in an object/array now too
  • unquoted keys aren’t banned, you can mix and match quoted/unquoted keys
  • you always have a global object. Even if your JSON string was ‘{}’, you would have a global object that contained one empty object with simplified JSON enabled
  • colons aren’t banned, you can mix ‘:’ and ‘=’ when separating your key/value pairs within objects

I hope you find this option useful, and I intend to keep working on json.h over my Christmas holidays so stay tuned!

11 Dec

Introducing utest.h!

So as you may (or may not) already know – I’ve written two tiny C libraries – utf8.h and json.h. One of the questions that most plagued me when writing these libraries was ‘How should I write the tests for them?’ I could put them in a separate repository, I could put them within the repository, should I create a new testing framework every time? It would be useful to be able to have test cases spread across multiple files… and the thoughts went on and on.

Basically what I wanted was a single header variant of googletest – and for it to be able to work in C. I scoured the interwebs a bit, but I couldn’t really find exactly what I wanted. When in doubt, write your own I say!

So I’m introducing utest.h – a single header C/C++ unit tester. It’s licensed under the public domain (via the unlicense), and it works and is tested on Mac OSX, Linux and Windows, with both C and C++ files in the same tested executable. I’ve tried to mimic googletest‘s command line output as much as possible, even using the coloured text output where possible.

To start testing with utest.h, the absolute minimum you need is a TESTCASE(set, name) and UTEST_MAIN() to be in one of your source files. UTEST_MAIN() defines an int main(…) entry point function, so don’t try and define your own! For example;

#include "utest.h"

TESTCASE(foo, bar) {
 ASSERT_TRUE(1);
}

UTEST_MAIN();

I use the gcc/clang extension __attribute__((constructor)) to allow multiple files to register test cases pre-main, and an even uglier MSVC workaround to mimic __attribute__((constructor)) on Windows. The bottom line though – it works, and everyone can test across C/C++ to their heart’s delight.

Future work will include having command line arguments to select what test cases to run, and being able to output an xunit/junit xml file so that continuous integrations can easily pick up the results of the test cases. Stay tuned!

04 Dec

(Partial) Simplified JSON support in json.h

With the help of the rather awesome @ocornut – I’ve managed to get a variant of simplified JSON support into json.h!

So first off – what is simplified JSON?  Taken straight from the Bitsquid blog;

  1. Assume an object definition at the root level (no need to surround entire file with { })
  2. Commas are optional
  3. Quotes around object keys are optional if the keys are valid identifiers
  4. Replace : with =

Of the four points above, I’m going to argue that only 1. and 3. are actually useful.


1. Assume an object definition at the root level (no need to surround entire file with { })

If you are always going to start a JSON file with an object (which is the recommended behaviour when using JSON), it can be quite tedious to surround the parent object with { }’s. Imagine we have the following;

{
  "a" : true,
  "b" : false,
  "c" : null
}

Whereas with 1. this could read;

"a" : true,
"b" : false,
"c" : null

As we can see, it reads that little bit nicer overall. It has a nice benefit of also meaning you don’t have to indent the parent key/value elements of the main object – if you like me are rather over the top about indentation this is a nice space saver. The one downside for the JSON security purists is that someone could easily append onto the object with new elements – something that I know is a problem in certain domains.

2. Commas are optional

I really dislike this idea. Essentially the idea is that;

{
  "a" : true
  "b" : false
  "c" : null
}

Would be entirely valid with simplified JSON. I dislike this because you can end up with some really disgusting code. The code above looks like the newlines are basically replacing the commas to denote new elements, but the above would be functionally equivalent to;

{
  "a" : true"b" : false"c" : null
}

Which looks utterly hideous. This also adds some pretty funky parsing variants for json.h which I just wasn’t keen to add.

3. Quotes around object keys are optional if the keys are valid identifiers

It can be a real chore and also quite expensive in terms of file size to surround all the keys of objects with ” “‘s too! For the example;

{
  "a" : true,
  "b" : false,
  "c" : null
}

Given that “a”, “b” and “c” don’t contain funky characters or whitespace, why not allow them to be specified like;

{
  a : true,
  b : false,
  c : null
}

It looks pretty nice, and saves some space, to be able to specify them without the ” “‘s.

4. Replace : with =

This rule I dislike simply because it is a stylistic choice. Even reading the Bitsquid blog that specified simplified JSON – it was done to make the code read more like Lua. This is something we could add, but I don’t see the point as its not a functional change, its a stylistic change.

Solving the problem with 2.

So as I said in my comments on 2., I don’t like the ‘commas are optional’ rule. To my rescue came @ocornut – who happened to suggest that allowing trailing commas on elements would be a useful helper for some work he was doing with my json.h library, and it got me thinking – this seems to solve at least part of the problem with 2.! Making it such that commas are a little easier to use makes them seem that little bit more innocuous for developers to use.

So I’ve settled on a happy medium of the features from simplified JSON that I think are useful. In the next post I’ll explain how I changed the API to allow both pure/original/unadulterated JSON to survive alongside my partial simplified JSON support!