From 163047aedabc2d43249239b0c0bdf92b8e664131 Mon Sep 17 00:00:00 2001
From: John Estabrook <jestabro@vyos.io>
Date: Fri, 28 Aug 2020 15:50:12 -0500
Subject: configd: T2582: add mkjson for use by shim

(https://github.com/Jacajack/mkjson.git)
---
 src/shim/mkjson/LICENSE  |  21 ++++
 src/shim/mkjson/makefile |  30 +++++
 src/shim/mkjson/mkjson.c | 307 +++++++++++++++++++++++++++++++++++++++++++++++
 src/shim/mkjson/mkjson.h |  50 ++++++++
 4 files changed, 408 insertions(+)
 create mode 100644 src/shim/mkjson/LICENSE
 create mode 100644 src/shim/mkjson/makefile
 create mode 100644 src/shim/mkjson/mkjson.c
 create mode 100644 src/shim/mkjson/mkjson.h

(limited to 'src/shim/mkjson')

diff --git a/src/shim/mkjson/LICENSE b/src/shim/mkjson/LICENSE
new file mode 100644
index 000000000..8c4284c91
--- /dev/null
+++ b/src/shim/mkjson/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Jacek Wieczorek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/src/shim/mkjson/makefile b/src/shim/mkjson/makefile
new file mode 100644
index 000000000..ba75399d2
--- /dev/null
+++ b/src/shim/mkjson/makefile
@@ -0,0 +1,30 @@
+CFLAGS = -Wall -Os -I.
+CC = gcc
+AR = ar
+
+#USE_ASPRINTF make flag can be used in order to encourage asprintf use inside the library
+ifeq ($(USE_ASPRINTF),1)
+CFLAGS += -D_GNU_SOURCE
+endif
+
+#Builds object and a static library file
+all: clean force
+	$(CC) $(CFLAGS) -c mkjson.c -o obj/mkjson.o
+	$(AR) -cvq lib/libmkjson.a obj/mkjson.o
+	$(AR) -t lib/libmkjson.a
+
+#Normal cleanup
+clean:
+	-rm -rf obj
+	-rm -rf lib
+
+#Environment init
+force:
+	-mkdir obj
+	-mkdir lib
+
+#Build the example snippet
+example: all
+	gcc -o example examples/example.c -I. -Llib -lmkjson
+
+	
diff --git a/src/shim/mkjson/mkjson.c b/src/shim/mkjson/mkjson.c
new file mode 100644
index 000000000..1172664fb
--- /dev/null
+++ b/src/shim/mkjson/mkjson.c
@@ -0,0 +1,307 @@
+/* mkjson.c - a part of mkjson library
+ *
+ * Copyright (C) 2018 Jacek Wieczorek
+ *
+ * This software may be modified and distributed under the terms
+ * of the MIT license.	See the LICENSE file for details.
+ */
+
+#include <mkjson.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+// Works like asprintf, but it's always there
+// I don't want the name to collide with anything
+static int allsprintf( char **strp, const char *fmt, ... )
+{
+	int len;
+	va_list ap;
+	va_start( ap, fmt );
+
+	#ifdef _GNU_SOURCE
+		// Just hand everything to vasprintf, if it's available
+		len = vasprintf( strp, fmt, ap );
+	#else
+		// Or do it the manual way
+		char *buf;
+		len = vsnprintf( NULL, 0, fmt, ap );
+		if ( len >= 0 )
+		{
+			buf = malloc( ++len );
+			if ( buf != NULL )
+			{
+				// Hopefully, that's the right way to do it
+				va_end( ap );
+				va_start( ap, fmt );
+
+				// Write and return the data
+				len = vsnprintf( buf, len, fmt, ap );
+				if ( len >= 0 )
+				{
+					*strp = buf;
+				}
+				else
+				{
+					free( buf );
+				}
+			}
+		}
+	#endif
+
+	va_end( ap );
+	return len;
+}
+
+// Return JSON string built from va_arg arguments
+// If no longer needed, should be passed to free() by user
+char *mkjson( enum mkjson_container_type otype, int count, ... )
+{
+	int i, len, goodchunks = 0, failure = 0;
+	char *json, *prefix, **chunks, ign;
+
+	// Value - type and data
+	enum mkjson_value_type vtype;
+	const char *key;
+	long long int intval;
+	long double dblval;
+	const char *strval;
+
+	// Since v0.9 count cannot be a negative value and datatype is indicated by a separate argument
+	// Since I'm not sure whether it's right to put assertions in libraries, the next line is commented out
+	// assert( count >= 0 && "After v0.9 negative count is prohibited; please use otype argument instead" );
+	if ( count < 0 || ( otype != MKJSON_OBJ && otype != MKJSON_ARR ) ) return NULL;
+
+	// Allocate chunk pointer array - on standard platforms each one should be NULL
+	chunks = calloc( count, sizeof( char* ) );
+	if ( chunks == NULL ) return NULL;
+
+	// This should rather be at the point of no return
+	va_list ap;
+	va_start( ap, count );
+
+	// Create chunks
+	for ( i = 0; i < count && !failure; i++ )
+	{
+		// Get value type
+		vtype = va_arg( ap, enum mkjson_value_type );
+
+		// Get key
+		if ( otype == MKJSON_OBJ )
+		{
+			key = va_arg( ap, char* );
+			if ( key == NULL )
+			{
+				failure = 1;
+				break;
+			}
+		}
+		else key = "";
+
+		// Generate prefix
+		if ( allsprintf( &prefix, "%s%s%s",
+			otype == MKJSON_OBJ ? "\"" : "",            // Quote before key
+			key,                                        // Key
+			otype == MKJSON_OBJ ? "\": " : "" ) == -1 ) // Quote and colon after key
+		{
+			failure = 1;
+			break;
+		}
+
+		// Depending on value type
+		ign = 0;
+		switch ( vtype )
+		{
+			// Ignore string / JSON data
+			case MKJSON_IGN_STRING:
+			case MKJSON_IGN_JSON:
+				(void) va_arg( ap, const char* );
+				ign = 1;
+				break;
+
+			// Ignore string / JSON data and pass the pointer to free
+			case MKJSON_IGN_STRING_FREE:
+			case MKJSON_IGN_JSON_FREE:
+				free( va_arg( ap, char* ) );
+				ign = 1;
+				break;
+
+			// Ignore int / long long int
+			case MKJSON_IGN_INT:
+			case MKJSON_IGN_LLINT:
+				if ( vtype == MKJSON_IGN_INT )
+					(void) va_arg( ap, int );
+				else
+					(void) va_arg( ap, long long int );
+				ign = 1;
+				break;
+
+			// Ignore double / long double
+			case MKJSON_IGN_DOUBLE:
+			case MKJSON_IGN_LDOUBLE:
+				if ( vtype == MKJSON_IGN_DOUBLE )
+					(void) va_arg( ap, double );
+				else
+					(void) va_arg( ap, long double );
+				ign = 1;
+				break;
+
+			// Ignore boolean
+			case MKJSON_IGN_BOOL:
+				(void) va_arg( ap, int );
+				ign = 1;
+				break;
+
+			// Ignore null value
+			case MKJSON_IGN_NULL:
+				ign = 1;
+				break;
+
+			// A null-terminated string
+			case MKJSON_STRING:
+			case MKJSON_STRING_FREE:
+				strval = va_arg( ap, const char* );
+
+				// If the pointer points to NULL, the string will be replaced with JSON null value
+				if ( strval == NULL )
+				{
+					if ( allsprintf( chunks + i, "%snull", prefix ) == -1 )
+						chunks[i] = NULL;
+				}
+				else
+				{
+					if ( allsprintf( chunks + i, "%s\"%s\"", prefix, strval ) == -1 )
+						chunks[i] = NULL;
+				}
+
+				// Optional free
+				if ( vtype == MKJSON_STRING_FREE )
+					free( (char*) strval );
+				break;
+
+			// Embed JSON data
+			case MKJSON_JSON:
+			case MKJSON_JSON_FREE:
+				strval = va_arg( ap, const char* );
+
+				// If the pointer points to NULL, the JSON data is replaced with null value
+				if ( allsprintf( chunks + i, "%s%s", prefix, strval == NULL ? "null" : strval ) == -1 )
+					chunks[i] = NULL;
+
+				// Optional free
+				if ( vtype == MKJSON_JSON_FREE )
+					free( (char*) strval );
+				break;
+
+			// int / long long int
+			case MKJSON_INT:
+			case MKJSON_LLINT:
+				if ( vtype == MKJSON_INT )
+					intval = va_arg( ap, int );
+				else
+					intval = va_arg( ap, long long int );
+
+				if ( allsprintf( chunks + i, "%s%Ld", prefix, intval ) == -1 ) chunks[i] = NULL;
+				break;
+
+			// double / long double
+			case MKJSON_DOUBLE:
+			case MKJSON_LDOUBLE:
+				if ( vtype == MKJSON_DOUBLE )
+					dblval = va_arg( ap, double );
+				else
+					dblval = va_arg( ap, long double );
+
+				if ( allsprintf( chunks + i, "%s%Lf", prefix, dblval ) == -1 ) chunks[i] = NULL;
+				break;
+
+			// double / long double
+			case MKJSON_SCI_DOUBLE:
+			case MKJSON_SCI_LDOUBLE:
+				if ( vtype == MKJSON_SCI_DOUBLE )
+					dblval = va_arg( ap, double );
+				else
+					dblval = va_arg( ap, long double );
+
+				if ( allsprintf( chunks + i, "%s%Le", prefix, dblval ) == -1 ) chunks[i] = NULL;
+				break;
+
+			// Boolean
+			case MKJSON_BOOL:
+				intval = va_arg( ap, int );
+				if ( allsprintf( chunks + i, "%s%s", prefix, intval ? "true" : "false" ) == -1 ) chunks[i] = NULL;
+				break;
+
+			// JSON null
+			case MKJSON_NULL:
+				if ( allsprintf( chunks + i, "%snull", prefix ) == -1 ) chunks[i] = NULL;
+				break;
+
+			// Bad type specifier
+			default:
+				chunks[i] = NULL;
+				break;
+		}
+
+		// Free prefix memory
+		free( prefix );
+
+		// NULL chunk without ignore flag indicates failure
+		if ( !ign && chunks[i] == NULL ) failure = 1;
+
+		// NULL chunk now indicates ignore flag
+		if ( ign ) chunks[i] = NULL;
+		else goodchunks++;
+	}
+
+	// We won't use ap anymore
+	va_end( ap );
+
+	// If everything is fine, merge chunks and create full JSON table
+	if ( !failure )
+	{
+		// Get total length (this is without NUL byte)
+		len = 0;
+		for ( i = 0; i < count; i++ )
+			if ( chunks[i] != NULL )
+				len += strlen( chunks[i] );
+
+		// Total length = Chunks length + 2 brackets + separators
+		if ( goodchunks == 0 ) goodchunks = 1;
+		len = len + 2 + ( goodchunks - 1 ) * 2;
+
+		// Allocate memory for the whole thing
+		json = calloc( len + 1, sizeof( char ) );
+		if ( json != NULL )
+		{
+			// Merge chunks (and do not overwrite the first bracket)
+			for ( i = 0; i < count; i++ )
+			{
+				// Add separators:
+				// - not on the begining
+				// - always after valid chunk
+				// - between two valid chunks
+				// - between valid and ignored chunk if the latter isn't the last one
+				if ( i != 0 && chunks[i - 1] != NULL && ( chunks[i] != NULL || ( chunks[i] == NULL && i != count - 1 ) ) )
+					strcat( json + 1, ", ");
+
+				if ( chunks[i] != NULL )
+					strcat( json + 1, chunks[i] );
+			}
+
+			// Add proper brackets
+			json[0] = otype == MKJSON_OBJ ? '{' : '[';
+			json[len - 1] = otype == MKJSON_OBJ ? '}' : ']';
+		}
+	}
+	else json = NULL;
+
+	// Free chunks
+	for ( i = 0; i < count; i++ )
+		free( chunks[i] );
+	free( chunks );
+
+	return json;
+}
+
diff --git a/src/shim/mkjson/mkjson.h b/src/shim/mkjson/mkjson.h
new file mode 100644
index 000000000..38cc07b26
--- /dev/null
+++ b/src/shim/mkjson/mkjson.h
@@ -0,0 +1,50 @@
+/* mkjson.h - a part of mkjson library
+ *
+ * Copyright (C) 2018 Jacek Wieczorek
+ *
+ * This software may be modified and distributed under the terms
+ * of the MIT license.	See the LICENSE file for details.
+ */
+
+#ifndef MKJSON_H
+#define MKJSON_H
+
+// JSON container types
+enum mkjson_container_type
+{
+	MKJSON_ARR = 0, // An array
+	MKJSON_OBJ = 1  // An object (hash or whatever you call it)
+};
+
+// JSON data types
+enum mkjson_value_type
+{
+	MKJSON_STRING      = (int)('s'), // const char* - String data
+	MKJSON_STRING_FREE = (int)('f'), // char* - String data, but pointer is freed
+	MKJSON_JSON        = (int)('r'), // const char* - JSON data (like string, but no quotes)
+	MKJSON_JSON_FREE   = (int)('j'), // char* - JSON data, but pointer is freed
+	MKJSON_INT         = (int)('i'), // int - An integer
+	MKJSON_LLINT       = (int)('I'), // long long int - A long integer
+	MKJSON_DOUBLE      = (int)('d'), // double - A double
+	MKJSON_LDOUBLE     = (int)('D'), // long double - A long double
+	MKJSON_SCI_DOUBLE  = (int)('e'), // double - A double with scientific notation
+	MKJSON_SCI_LDOUBLE = (int)('E'), // long double - A long double with scientific notation
+	MKJSON_BOOL        = (int)('b'), // int - A boolean value
+	MKJSON_NULL        = (int)('n'),  // -- - JSON null value
+
+	// These cause one argument of certain type to be ignored
+	MKJSON_IGN_STRING      = (-MKJSON_STRING),
+	MKJSON_IGN_STRING_FREE = (-MKJSON_STRING_FREE),
+	MKJSON_IGN_JSON        = (-MKJSON_JSON),
+	MKJSON_IGN_JSON_FREE   = (-MKJSON_JSON_FREE),
+	MKJSON_IGN_INT         = (-MKJSON_INT),
+	MKJSON_IGN_LLINT       = (-MKJSON_LLINT),
+	MKJSON_IGN_DOUBLE      = (-MKJSON_DOUBLE),
+	MKJSON_IGN_LDOUBLE     = (-MKJSON_LDOUBLE),
+	MKJSON_IGN_BOOL        = (-MKJSON_BOOL),
+	MKJSON_IGN_NULL        = (-MKJSON_NULL)
+};
+
+extern char *mkjson( enum mkjson_container_type otype, int count, ... );
+
+#endif
-- 
cgit v1.2.3