239 lines
6.3 KiB
C
239 lines
6.3 KiB
C
|
#include <PublicDomain.txt>
|
||
|
|
||
|
// Simple function I wrote to make my life easier while playing with Kore C web server
|
||
|
//
|
||
|
// Should be easily portable to not use any json libraries at all if you really wanna to
|
||
|
//
|
||
|
// I know that it uses ?: GCC extension but in this file it can be expanded to standard C ternary operator with simple
|
||
|
// sed expression, everything for your closed-source "can't add useful features to my compiler" needs :)
|
||
|
//
|
||
|
// Usage:
|
||
|
// N-th variadic argument starts new context with one of the json types
|
||
|
// N+1 sets the name of object if current context is not an array, can be NULL
|
||
|
// N+2 sets the object value
|
||
|
// N+M marks the end with JSON_END flag if the context was object or array
|
||
|
//
|
||
|
// Example:
|
||
|
// root = json_construct( NULL,
|
||
|
// JSON_TYPE_OBJECT, NULL,
|
||
|
// JSON_TYPE_STRING, "version", "2.1",
|
||
|
// JSON_TYPE_OBJECT, "software",
|
||
|
// JSON_TYPE_STRING, "name", "apserv",
|
||
|
// JSON_TYPE_STRING, "version", "0.0.1",
|
||
|
// JSON_TYPE_STRING, "repository", "https://git.mentality.rip/FWGS/apserv",
|
||
|
// JSON_TYPE_STRING, "homepage", "https://git.mentality.rip/FWGS/apserv",
|
||
|
// JSON_END,
|
||
|
// JSON_TYPE_ARRAY, "protocols",
|
||
|
// JSON_TYPE_STRING, "activitypub",
|
||
|
// JSON_END,
|
||
|
// JSON_TYPE_OBJECT, "services",
|
||
|
// JSON_TYPE_ARRAY, "inbound", JSON_END,
|
||
|
// JSON_TYPE_ARRAY, "outbound", JSON_END,
|
||
|
// JSON_END,
|
||
|
// JSON_TYPE_LITERAL, "openRegistrations", APSERV_OPEN_REGISTRATIONS ? JSON_TRUE : JSON_FALSE,
|
||
|
// JSON_TYPE_OBJECT, "usage",
|
||
|
// JSON_TYPE_OBJECT, "users",
|
||
|
// JSON_TYPE_U64, "total", 0,
|
||
|
// JSON_TYPE_U64, "activeHalfyear", 0,
|
||
|
// JSON_TYPE_U64, "activeMonth", 0,
|
||
|
// JSON_END,
|
||
|
// JSON_END,
|
||
|
// JSON_TYPE_OBJECT, "metadata",
|
||
|
// JSON_END,
|
||
|
// JSON_END);
|
||
|
//
|
||
|
// This generates an object below:
|
||
|
// {
|
||
|
// "version": "2.1",
|
||
|
// "software": {
|
||
|
// "name": "apserv",
|
||
|
// "version": "0.0.1",
|
||
|
// "repository": "https://git.mentality.rip/FWGS/apserv",
|
||
|
// "homepage": "https://git.mentality.rip/FWGS/apserv"
|
||
|
// },
|
||
|
// "protocols": [
|
||
|
// "activitypub"
|
||
|
// ],
|
||
|
// "services": {
|
||
|
// "inbound": [],
|
||
|
// "outbound": []
|
||
|
// },
|
||
|
// "openRegistrations": false,
|
||
|
// "usage": {
|
||
|
// "users": {
|
||
|
// "total": 0,
|
||
|
// "activeHalfyear": 0,
|
||
|
// "activeMonth": 0
|
||
|
// }
|
||
|
// },
|
||
|
// "metadata": {}
|
||
|
// }
|
||
|
//
|
||
|
|
||
|
|
||
|
#include <stdarg.h>
|
||
|
#include <inttypes.h>
|
||
|
#include <stdbool.h>
|
||
|
#include <kore/kore.h>
|
||
|
|
||
|
#define JSON_END 0
|
||
|
#define JSON_TYPE_OBJECT KORE_JSON_TYPE_OBJECT
|
||
|
#define JSON_TYPE_ARRAY KORE_JSON_TYPE_ARRAY
|
||
|
#define JSON_TYPE_STRING KORE_JSON_TYPE_STRING
|
||
|
#define JSON_TYPE_NUMBER KORE_JSON_TYPE_NUMBER
|
||
|
#define JSON_TYPE_LITERAL KORE_JSON_TYPE_LITERAL
|
||
|
#define JSON_TYPE_I32 (1U<<31)
|
||
|
#define JSON_TYPE_U32 (1U<<30)
|
||
|
#define JSON_TYPE_I64 KORE_JSON_TYPE_INTEGER
|
||
|
#define JSON_TYPE_U64 KORE_JSON_TYPE_INTEGER_U64
|
||
|
|
||
|
#define JSON_FALSE KORE_JSON_FALSE
|
||
|
#define JSON_TRUE KORE_JSON_TRUE
|
||
|
#define JSON_NULL KORE_JSON_NULL
|
||
|
|
||
|
struct kore_json_item *json_construct( struct kore_json_item *parent, int type, ... );
|
||
|
|
||
|
#define JSON_CONSTRUCT_DEBUG
|
||
|
|
||
|
#ifdef JSON_CONSTRUCT_DEBUG
|
||
|
#define CONSTRUCT_DEBUG(...) kore_log( LOG_DEBUG, __VA_ARGS__ )
|
||
|
#else
|
||
|
#define CONSTRUCT_DEBUG(...)
|
||
|
#endif
|
||
|
|
||
|
static struct kore_json_item *json_construct_onev( struct kore_json_item *parent, bool skipname, int type, va_list ap )
|
||
|
{
|
||
|
struct kore_json_item *ret = NULL;
|
||
|
const char *name, *parent_name;
|
||
|
|
||
|
if( type == JSON_END )
|
||
|
{
|
||
|
fatal( "%s: this shouldn't happen", __func__ );
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if( parent )
|
||
|
{
|
||
|
if( parent->name )
|
||
|
parent_name = parent->name;
|
||
|
else parent_name = "(noname)";
|
||
|
}
|
||
|
else parent_name = "(noparent)";
|
||
|
|
||
|
if( !skipname )
|
||
|
name = va_arg( ap, const char * );
|
||
|
else name = NULL;
|
||
|
|
||
|
if( type == JSON_TYPE_OBJECT || type == JSON_TYPE_ARRAY )
|
||
|
{
|
||
|
const char *strtype = type == JSON_TYPE_OBJECT ? "object" : "array";
|
||
|
struct kore_json_item *f;
|
||
|
|
||
|
f = kore_json_create_item( parent, name, type );
|
||
|
if( !ret ) ret = f;
|
||
|
|
||
|
CONSTRUCT_DEBUG( "(%s) creating %s \"%s\"", parent_name, strtype, name ?: "" );
|
||
|
|
||
|
for( ;; )
|
||
|
{
|
||
|
int nexttype = va_arg( ap, int );
|
||
|
if( nexttype == JSON_END )
|
||
|
{
|
||
|
CONSTRUCT_DEBUG( "(%s) closing %s \"%s\"", parent_name, strtype, name ?: "" );
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
json_construct_onev( f, type == JSON_TYPE_ARRAY, nexttype, ap );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
switch( type )
|
||
|
{
|
||
|
case JSON_TYPE_STRING:
|
||
|
{
|
||
|
const char *szValue = va_arg( ap, const char * );
|
||
|
|
||
|
CONSTRUCT_DEBUG( "(%s) creating string object \"%s\": \"%s\"", parent_name, name ?: "", szValue );
|
||
|
|
||
|
ret = kore_json_create_string( parent, name, szValue );
|
||
|
break;
|
||
|
}
|
||
|
case JSON_TYPE_NUMBER:
|
||
|
{
|
||
|
double flValue = va_arg( ap, double );
|
||
|
|
||
|
CONSTRUCT_DEBUG( "(%s) creating number parameter \"%s\": %f", parent_name, name ?: "", flValue );
|
||
|
|
||
|
ret = kore_json_create_number( parent, name, flValue );
|
||
|
break;
|
||
|
}
|
||
|
case JSON_TYPE_LITERAL:
|
||
|
{
|
||
|
int32_t iValue = va_arg( ap, int );
|
||
|
const char *szValue;
|
||
|
|
||
|
switch( iValue )
|
||
|
{
|
||
|
case JSON_FALSE: szValue = "false"; break;
|
||
|
case JSON_TRUE: szValue = "true"; break;
|
||
|
case JSON_NULL: szValue = "null"; break;
|
||
|
default: fatal("illegal value %d for literal type", iValue );
|
||
|
}
|
||
|
|
||
|
CONSTRUCT_DEBUG( "(%s) creating literal parameter \"%s\": %s", parent_name, name ?: "", szValue );
|
||
|
|
||
|
ret = kore_json_create_literal( parent, name, iValue );
|
||
|
break;
|
||
|
}
|
||
|
case JSON_TYPE_I32:
|
||
|
{
|
||
|
int32_t iValue = va_arg( ap, int32_t );
|
||
|
|
||
|
CONSTRUCT_DEBUG( "(%s) creating int32 parameter \"%s\": %d", parent_name, name ?: "", iValue );
|
||
|
|
||
|
ret = kore_json_create_integer( parent, name, iValue );
|
||
|
break;
|
||
|
}
|
||
|
case JSON_TYPE_U32:
|
||
|
{
|
||
|
uint32_t uValue = va_arg( ap, uint32_t );
|
||
|
|
||
|
CONSTRUCT_DEBUG( "(%s) creating uint32 parameter \"%s\": %u", parent_name, name ?: "", uValue );
|
||
|
|
||
|
ret = kore_json_create_integer( parent, name, uValue );
|
||
|
break;
|
||
|
}
|
||
|
case JSON_TYPE_I64:
|
||
|
{
|
||
|
int64_t lValue = va_arg( ap, int64_t );
|
||
|
|
||
|
CONSTRUCT_DEBUG( "(%s) creating int64 parameter \"%s\": " PRId64, parent_name, name ?: "", lValue );
|
||
|
|
||
|
ret = kore_json_create_integer( parent, name, lValue );
|
||
|
break;
|
||
|
}
|
||
|
case JSON_TYPE_U64:
|
||
|
{
|
||
|
uint64_t ulValue = va_arg( ap, uint64_t );
|
||
|
|
||
|
CONSTRUCT_DEBUG( "(%s) creating uint64 parameter \"%s\": " PRIu64, parent_name, name ?: "", ulValue );
|
||
|
|
||
|
ret = kore_json_create_integer_u64( parent, name, ulValue );
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
struct kore_json_item *json_construct( struct kore_json_item *parent, int type, ... )
|
||
|
{
|
||
|
va_list ap;
|
||
|
|
||
|
va_start( ap, type );
|
||
|
parent = json_construct_onev( parent, type == JSON_TYPE_ARRAY, type, ap );
|
||
|
va_end( ap );
|
||
|
|
||
|
return parent;
|
||
|
}
|