diff mbox series

[1/2] Replace json-c library with minimal replacement

Message ID 20200817102229.521555-1-colin.king@canonical.com
State Superseded
Headers show
Series [1/2] Replace json-c library with minimal replacement | expand

Commit Message

Colin Ian King Aug. 17, 2020, 10:22 a.m. UTC
From: Colin Ian King <colin.king@canonical.com>

FWTS uses a subset of json-c functionality, so replace it with
our own implementation that supports this subset. This also
removes the dependency of two flavours of json libraries that
fwts has been using and also allows us to perform deeper memory
allocation and leaking tracking with static analysis tools.

Signed-off-by: Colin Ian King <colin.king@canonical.com>
---
 configure.ac                |   3 -
 src/lib/include/fwts.h      |   2 +
 src/lib/include/fwts_json.h |  61 ++-
 src/lib/src/Makefile.am     |   1 +
 src/lib/src/fwts_json.c     | 917 ++++++++++++++++++++++++++++++++++++
 src/utilities/Makefile.am   |   5 +-
 6 files changed, 969 insertions(+), 20 deletions(-)
 create mode 100644 src/lib/src/fwts_json.c

Comments

Ivan Hu Aug. 21, 2020, 10:35 a.m. UTC | #1
Got build error blow, seems kernelscan.c still hasn't used these functions.
#include <json.h> in kernelscan.c

kernelscan.c: In function ‘klog_load’:
kernelscan.c:365:2: error: ‘json_object_object_get’ is deprecated
[-Werror=deprecated-declarations]
  klog_table = json_object_object_get(klog_objs, table);
  ^~~~~~~~~~
In file included from /usr/include/json-c/linkhash.h:16:0,
                 from /usr/include/json-c/json.h:22,
                 from kernelscan.c:28:
/usr/include/json-c/json_object.h:290:56: note: declared here
 THIS_FUNCTION_IS_DEPRECATED(extern struct json_object*
json_object_object_get(struct json_object* obj,
                                                        ^
/usr/include/json-c/json_object.h:17:43: note: in definition of macro
‘THIS_FUNCTION_IS_DEPRECATED’
 #define THIS_FUNCTION_IS_DEPRECATED(func) func __attribute__ ((deprecated))
                                           ^~~~
kernelscan.c:401:3: error: ‘json_object_object_get’ is deprecated
[-Werror=deprecated-declarations]
   str = (char*)json_object_get_string(json_object_object_get(obj,
"compare_mode"));
   ^~~
In file included from /usr/include/json-c/linkhash.h:16:0,
                 from /usr/include/json-c/json.h:22,
                 from kernelscan.c:28:
/usr/include/json-c/json_object.h:290:56: note: declared here
 THIS_FUNCTION_IS_DEPRECATED(extern struct json_object*
json_object_object_get(struct json_object* obj,
                                                        ^
/usr/include/json-c/json_object.h:17:43: note: in definition of macro
‘THIS_FUNCTION_IS_DEPRECATED’
 #define THIS_FUNCTION_IS_DEPRECATED(func) func __attribute__ ((deprecated))
                                           ^~~~
kernelscan.c:416:3: error: ‘json_object_object_get’ is deprecated
[-Werror=deprecated-declarations]
   str = (char*)json_object_get_string(json_object_object_get(obj,
"pattern"));
   ^~~
In file included from /usr/include/json-c/linkhash.h:16:0,
                 from /usr/include/json-c/json.h:22,
                 from kernelscan.c:28:
/usr/include/json-c/json_object.h:290:56: note: declared here
 THIS_FUNCTION_IS_DEPRECATED(extern struct json_object*
json_object_object_get(struct json_object* obj,
                                                        ^
/usr/include/json-c/json_object.h:17:43: note: in definition of macro
‘THIS_FUNCTION_IS_DEPRECATED’
 #define THIS_FUNCTION_IS_DEPRECATED(func) func __attribute__ ((deprecated))
                                           ^~~~

Ivan

On 8/17/20 6:22 PM, Colin King wrote:
> From: Colin Ian King <colin.king@canonical.com>
> 
> FWTS uses a subset of json-c functionality, so replace it with
> our own implementation that supports this subset. This also
> removes the dependency of two flavours of json libraries that
> fwts has been using and also allows us to perform deeper memory
> allocation and leaking tracking with static analysis tools.
> 
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
> ---
>  configure.ac                |   3 -
>  src/lib/include/fwts.h      |   2 +
>  src/lib/include/fwts_json.h |  61 ++-
>  src/lib/src/Makefile.am     |   1 +
>  src/lib/src/fwts_json.c     | 917 ++++++++++++++++++++++++++++++++++++
>  src/utilities/Makefile.am   |   5 +-
>  6 files changed, 969 insertions(+), 20 deletions(-)
>  create mode 100644 src/lib/src/fwts_json.c
> 
> diff --git a/configure.ac b/configure.ac
> index 39a445cd..f40c3678 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -9,8 +9,6 @@
>  	  AC_PROG_LIBTOOL
>  	  AC_C_INLINE
>  	  AM_PROG_CC_C_O
> -	  AC_SEARCH_LIBS([json_object_from_file], [json json-c], [], [ AC_MSG_ERROR([no available json library]) ])
> -	  AC_SEARCH_LIBS([json_object_object_get_ex], [json json-c], [ AC_DEFINE([JSON_HAS_GET_EX], [1], [Define if we have json_object_object_get_ex])], [])
>    	  AC_CHECK_FUNCS([localtime_r])
>  	  AC_CHECK_FUNCS([dup2])
>  	  AC_CHECK_FUNCS([getcwd])
> @@ -61,7 +59,6 @@
>  	  AC_CHECK_HEADERS([time.h])
>  	  AC_CHECK_HEADERS([sys/ioctl.h])
>  	  AC_CHECK_HEADERS([sys/time.h])
> -	  AC_CHECK_HEADERS([json/json.h])
>  	  AC_CHECK_HEADERS([glib.h])
>  	  AC_CHECK_HEADERS([gio/gio.h])
>  	  AC_CHECK_HEADERS([asm/opal-prd.h])
> diff --git a/src/lib/include/fwts.h b/src/lib/include/fwts.h
> index 1e0d5870..6f13d262 100644
> --- a/src/lib/include/fwts.h
> +++ b/src/lib/include/fwts.h
> @@ -153,6 +153,8 @@
>  
>  #define FWTS_JSON_DATA_PATH	DATAROOTDIR "/fwts"
>  
> +#include <inttypes.h>
> +
>  #include "fwts_version.h"
>  #include "fwts_backtrace.h"
>  #include "fwts_types.h"
> diff --git a/src/lib/include/fwts_json.h b/src/lib/include/fwts_json.h
> index ad51bc45..0c316e02 100644
> --- a/src/lib/include/fwts_json.h
> +++ b/src/lib/include/fwts_json.h
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (C) 2012-2020 Canonical
> + * Copyright (C) 2010-2020 Canonical
>   *
>   * This program is free software; you can redistribute it and/or
>   * modify it under the terms of the GNU General Public License
> @@ -16,26 +16,15 @@
>   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
>   *
>   */
> -
>  #ifndef __FWTS_JSON_H__
>  #define __FWTS_JSON_H__
>  
> -#include <json.h>
> -
> -#define __FWTS_JSON_ERR_PTR__ ((json_object*) -1)
>  /*
> - *  Older versions of json-c may return an error in an
> - *  object as a ((json_object*)-1), where as newer
> - *  versions return NULL, so check for these. Sigh.
> + *  Minimal subset of json for fwts
>   */
> -#define FWTS_JSON_ERROR(ptr) \
> -	( (ptr == NULL) || ((const json_object *)ptr == __FWTS_JSON_ERR_PTR__) )
>  
> -/*
> - * json-c 0.13.99 does not define TRUE/FALSE anymore
> - * the json-c maintainers replaced them with pure 1/0
> - * https://github.com/json-c/json-c/commit/0992aac61f8b
> - */
> +#define FWTS_JSON_ERROR(ptr) 	(!ptr)
> +
>  #ifndef FALSE
>  #define FALSE 0
>  #endif
> @@ -44,4 +33,46 @@
>  #define TRUE  1
>  #endif
>  
> +/*
> + *  json types supported
> + */
> +typedef enum {
> +	type_null,
> +	type_int,
> +	type_string,
> +	type_object,
> +	type_array,
> +} json_type;
> +
> +/*
> + *  json object information
> + */
> +typedef struct json_object {
> +	char *key;		/* Null if undefined */
> +	int length;		/* Length of a collection of objects */
> +	json_type type;		/* Object type */
> +        union {
> +                void *ptr;	/* string or object array pointer */
> +                int  intval;	/* integer value */
> +        } u;
> +} json_object;
> +
> +/*
> + *  minimal json c library functions as required by fwts
> + */
> +json_object *json_object_from_file(const char *filename);
> +json_object *json_object_object_get(json_object *obj, const char *key);
> +int json_object_array_length(json_object *obj);
> +json_object *json_object_array_get_idx(json_object *obj, int index);
> +const char *json_object_get_string(json_object *obj);
> +json_object *json_object_new_int(int);
> +void json_object_object_add(json_object *obj, const char *key, json_object *value);
> +
> +json_object *json_object_new_object(void);
> +json_object *json_object_new_array(void);
> +char *json_object_to_json_string(json_object *obj);
> +void json_object_put(json_object *obj);
> +json_object *json_object_new_string(const char *str);
> +int json_object_array_add(json_object *obj, json_object *item);
> +
>  #endif
> diff --git a/src/lib/src/Makefile.am b/src/lib/src/Makefile.am
> index ecc4136b..4593bb82 100644
> --- a/src/lib/src/Makefile.am
> +++ b/src/lib/src/Makefile.am
> @@ -82,6 +82,7 @@ libfwts_la_SOURCES = 		\
>  	fwts_interactive.c 	\
>  	fwts_ioport.c		\
>  	fwts_ipmi.c		\
> +	fwts_json.c		\
>  	fwts_keymap.c 		\
>  	fwts_klog.c 		\
>  	fwts_olog.c		\
> diff --git a/src/lib/src/fwts_json.c b/src/lib/src/fwts_json.c
> new file mode 100644
> index 00000000..b92a241a
> --- /dev/null
> +++ b/src/lib/src/fwts_json.c
> @@ -0,0 +1,917 @@
> +/*
> + * Copyright (C) 2010-2020 Canonical
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> + *
> + * This is a simplified json parser and json object store
> + * based on json but does not support keywords and is designed
> + * just for the fwts json data files. It is not a full json
> + * implementation and should not be used as such.
> + *
> + */
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <stdarg.h>
> +#include <stdbool.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <ctype.h>
> +
> +#include "fwts.h"
> +
> +/*
> + *  json file information
> + */
> +typedef struct {
> +	FILE *fp;		/* File pointer */
> +	const char *filename;	/* Name of file */
> +	int linenum;		/* Parser line number */
> +	int charnum;		/* Parser char position */
> +	int error_reported;	/* Error count */
> +} json_file;
> +
> +/*
> + *  json tokens, subset of full json token set as used
> + *  for fwts requirements
> + */
> +typedef enum {
> +	token_lbrace,
> +	token_rbrace,
> +	token_lbracket,
> +	token_rbracket,
> +	token_colon,
> +	token_comma,
> +	token_int,
> +	token_string,
> +	token_true,
> +	token_false,
> +	token_null,
> +	token_error,
> +	token_eof,
> +} json_token_type;
> +
> +/*
> + *  json parser token
> + */
> +typedef struct {
> +	json_token_type type;	/* token type */
> +	long offset;		/* offset in file for re-winding */
> +	union {
> +		char *str;	/* token string value */
> +		int  intval;	/* token integer value */
> +	} u;
> +} json_token;
> +
> +/*
> + *  json_token_string()
> + *	convert json token to a human readable string
> + */
> +char *json_token_string(json_token *jtoken)
> +{
> +	static char tmp[64];
> +
> +	switch (jtoken->type) {
> +	case token_lbrace:
> +		return "{";
> +	case token_rbrace:
> +		return "}";
> +	case token_lbracket:
> +		return "[";
> +	case token_rbracket:
> +		return "]";
> +	case token_colon:
> +		return ":";
> +	case token_comma:
> +		return ",";
> +	case token_int:
> +		(void)snprintf(tmp, sizeof(tmp), "%d", jtoken->u.intval);
> +		return tmp;
> +	case token_string:
> +		return jtoken->u.str;
> +	case token_error:
> +		return "<error>";
> +	case token_eof:
> +		return "end of file";
> +	default:
> +		break;
> +	}
> +	return "<illegal token>";
> +}
> +
> +/*
> + *  json_get_string()
> + *	parse a literal string
> + */
> +json_token_type json_get_string(json_file *jfile, json_token *token)
> +{
> +	char buffer[4096];
> +	size_t i = 0;
> +
> +	for (;;) {
> +		int ch;
> +
> +		ch = fgetc(jfile->fp);
> +		jfile->charnum++;
> +		if (ch == EOF) {
> +			fprintf(stderr, "json_parser: unexpected EOF in literal string\n");
> +			token->u.str = NULL;
> +			return token_error;
> +		}
> +
> +		if (ch == '\\') {
> +			ch = fgetc(jfile->fp);
> +			switch (ch) {
> +			case '\\':
> +			case '"':
> +			case '/':
> +				break;
> +			case 'b':
> +				ch = '\b';
> +				break;
> +			case 'f':
> +				ch = '\f';
> +				break;
> +			case 'n':
> +				ch = '\n';
> +				break;
> +			case 'r':
> +				ch = '\r';
> +				break;
> +			case 't':
> +				ch = '\t';
> +				break;
> +			case 'u':
> +				fprintf(stderr, "json parser: escaped hex values not supported\n");
> +				ch = '?';
> +				break;
> +			}
> +			jfile->charnum++;
> +		} else if (ch == '"') {
> +			buffer[i] = '\0';
> +			token->u.str = strdup(buffer);
> +			if (!token->u.str) {
> +				fprintf(stderr, "json parser: out of memory allocating %zd byte string\n", i);
> +				break;
> +			}
> +			return token_string;
> +		}
> +		buffer[i] = ch;
> +		i++;
> +		if (i >= sizeof(buffer)) {
> +			fprintf(stderr, "json parser: string too long, maximum size %zd bytes\n", sizeof(buffer) - 1);
> +			break;
> +		}
> +	}
> +
> +	token->u.str = NULL;
> +	return token_error;
> +}
> +
> +/*
> + *  json_get_int()
> + *	parse a simple integer
> + */
> +json_token_type json_get_int(json_file *jfile, json_token *token)
> +{
> +	char buffer[64];
> +	size_t i = 0;
> +
> +	for (;;) {
> +		int ch;
> +
> +		ch = fgetc(jfile->fp);
> +		if (!isdigit(ch)) {
> +			(void)ungetc(ch, jfile->fp);
> +			buffer[i] = '\0';
> +			token->u.intval = atoi(buffer);
> +			return token_int;
> +		}
> +		jfile->charnum++;
> +		buffer[i] = ch;
> +		i++;
> +		if (i >= sizeof(buffer)) {
> +			fprintf(stderr, "json parser: integer too long, maximum size %zd bytes\n", sizeof(buffer) - 1);
> +			break;
> +		}
> +	}
> +
> +	token->u.str = NULL;
> +	return token_error;
> +}
> +
> +/*
> + *  json_unget_token()
> + *  	push file pointer back to point before the token
> + *	to unpush the token
> + */
> +int json_unget_token(json_file *jfile, json_token *token)
> +{
> +	return fseek(jfile->fp, token->offset, SEEK_SET);
> +}
> +
> +/*
> + *  json_get_keyword()
> + *	get a keyword
> + */
> +int json_get_keyword(json_file *jfile, json_token *token)
> +{
> +	char buffer[32];
> +	size_t i = 0;
> +
> +	token->u.str = NULL;
> +	*buffer = '\0';
> +
> +	for (;;) {
> +		int ch;
> +
> +		ch = fgetc(jfile->fp);
> +		jfile->charnum++;
> +		if (ch == EOF) {
> +			fprintf(stderr, "json_parser: unexpected EOF in keyword string\n");
> +			return token_error;
> +		}
> +		if (ch < 'a' || ch > 'z')
> +			break;
> +
> +		buffer[i] = ch;
> +		i++;
> +		if (i >= sizeof(buffer)) {
> +			fprintf(stderr, "json parser: keyword too long, maximum size %zd bytes\n", sizeof(buffer) - 1);
> +			return token_error;
> +		}
> +	}
> +	if (!strcmp(buffer, "true"))
> +		return token_true;
> +	if (!strcmp(buffer, "false"))
> +		return token_false;
> +	if (!strcmp(buffer, "null"))
> +		return token_null;
> +	return token_error;
> +}
> +
> +/*
> + *  json_get_token()
> + *	read next input character(s) and return a matching token
> + */
> +json_token_type json_get_token(json_file *jfile, json_token *token)
> +{
> +	(void)memset(token, 0, sizeof(*token));
> +
> +	token->offset = ftell(jfile->fp);
> +	for (;;) {
> +		int ch;
> +
> +		ch = fgetc(jfile->fp);
> +		jfile->charnum++;
> +
> +		switch (ch) {
> +		case '\n':
> +			jfile->linenum++;
> +			continue;
> +		case ' ':
> +		case '\r':
> +		case '\t':
> +			continue;
> +		case EOF:
> +			token->type = token_eof;
> +			return token->type;
> +		case '{':
> +			token->type = token_lbrace;
> +			return token->type;
> +		case '}':
> +			token->type = token_rbrace;
> +			return token->type;
> +		case '[':
> +			token->type = token_lbracket;
> +			return token->type;
> +		case ']':
> +			token->type = token_rbracket;
> +			return token->type;
> +		case ':':
> +			token->type = token_colon;
> +			return token->type;
> +		case ',':
> +			token->type = token_comma;
> +			return token->type;
> +		case '"':
> +			token->type = json_get_string(jfile, token);
> +			return token->type;
> +		case '0'...'9':
> +			token->type = json_get_int(jfile, token);
> +			return token->type;
> +		case 'a'...'z':
> +			fprintf(stderr, "json_parser: keywords not supported\n");
> +			token->type = token_error;
> +			return token->type;
> +		default:
> +			token->type = token_error;
> +			return token->type;
> +		}
> +	}
> +
> +	/* Should never reach here */
> +	token->type = token_error;
> +	return token->type;
> +}
> +
> +/*
> + *  json_parse_error_where()
> + *	very simple parser error message, report where in the file
> + *	the parsing error occurred.
> + */
> +void json_parse_error_where(json_file *jfile)
> +{
> +	if (jfile->error_reported == 0)
> +		fprintf(stderr, "json_parser: aborted at line %d, char %d of file %s\n",
> +			jfile->linenum, jfile->charnum, jfile->filename);
> +	jfile->error_reported++;
> +}
> +
> +json_object *json_parse_object(json_file *jfile);
> +
> +/*
> + *  json_parse_array()
> + *	parse a json array
> + */
> +json_object *json_parse_array(json_file *jfile)
> +{
> +	json_object *array_obj;
> +
> +	array_obj = json_object_new_array();
> +	if (!array_obj) {
> +		fprintf(stderr, "json_parser: out of memory allocating a json array object\n");
> +		json_parse_error_where(jfile);
> +		return NULL;
> +	}
> +
> +	for (;;) {
> +		json_object *obj;
> +		json_token token;
> +
> +		obj = json_parse_object(jfile);
> +		if (!obj) {
> +			json_parse_error_where(jfile);
> +			free(array_obj);
> +			return NULL;
> +		}
> +		json_object_array_add(array_obj, obj);
> +
> +		switch (json_get_token(jfile, &token)) {
> +		case token_rbracket:
> +			return array_obj;
> +		case token_comma:
> +			continue;
> +		default:
> +			if (json_unget_token(jfile, &token) != 0) {
> +				fprintf(stderr, "json_parser: failed to unget a token\n");
> +				free(array_obj);
> +				return NULL;
> +			}
> +			break;
> +		}
> +	}
> +	return array_obj;
> +}
> +
> +/*
> + *  json_parse_object()
> + *	parse a json object (simplified fwts json format only)
> + */
> +json_object *json_parse_object(json_file *jfile)
> +{
> +	json_token token;
> +	json_object *obj, *val_obj;
> +	char *key = NULL;
> +
> +	if (json_get_token(jfile, &token) != token_lbrace) {
> +		fprintf(stderr, "json_parser: expecting '{', got %s instead\n", json_token_string(&token));
> +		return NULL;
> +	}
> +
> +	obj = json_object_new_object();
> +	if (!obj)
> +		goto err_nomem;
> +
> +	for (;;) {
> +		switch (json_get_token(jfile, &token)) {
> +		case token_rbrace:
> +			return obj;
> +		case token_string:
> +			key = token.u.str;
> +			if (!key)
> +				goto err_nomem;
> +			token.u.str = NULL;
> +			break;
> +		default:
> +			fprintf(stderr, "json_parser: expecting } or key literal string, got %s instead\n", json_token_string(&token));
> +			goto err_free;
> +		}
> +		if (json_get_token(jfile, &token) != token_colon) {
> +			fprintf(stderr, "json_parser: expecting ':', got %s instead\n", json_token_string(&token));
> +			goto err_free;
> +		}
> +		switch (json_get_token(jfile, &token)) {
> +		case token_string:
> +			val_obj = json_object_new_string(token.u.str);
> +			if (!val_obj)
> +				goto err_nomem;
> +			json_object_object_add(obj, key, val_obj);
> +			free(key);
> +			break;
> +		case token_int:
> +			val_obj = json_object_new_int(token.u.intval);
> +			if (!val_obj)
> +				goto err_nomem;
> +			json_object_object_add(obj, key, val_obj);
> +			free(key);
> +			break;
> +		case token_lbracket:
> +			val_obj = json_parse_array(jfile);
> +			if (!val_obj)
> +				goto err_nomem;
> +			json_object_object_add(obj, key, val_obj);
> +			break;
> +		case token_lbrace:
> +			fprintf(stderr, "json_parser: nested objects not supported\n");
> +			goto err_free;
> +		case token_true:
> +		case token_false:
> +		case token_null:
> +			fprintf(stderr, "json_parser: tokens %s not supported\n", json_token_string(&token));
> +			goto err_free;
> +		default:
> +			fprintf(stderr, "json_parser: unexpected token %s\n", json_token_string(&token));
> +		}
> +		switch (json_get_token(jfile, &token)) {
> +		case token_comma:
> +			continue;
> +		case token_rbrace:
> +			return obj;
> +		default:
> +			fprintf(stderr, "json_parser: expected , or }, got %s instead\n", json_token_string(&token));
> +			goto err_free;
> +		}
> +	}
> +
> +err_nomem:
> +	fprintf(stderr, "json_parser: out of memory allocating a json object\n");
> +	json_parse_error_where(jfile);
> +err_free:
> +	free(obj);
> +	return NULL;
> +}
> +
> +/*
> + *  json_object_from_file()
> + *	parse a simplified fwts json file and convert it into
> + *	a json object, return NULL if parsing failed or ran
> + *	out of memory
> + */
> +json_object *json_object_from_file(const char *filename)
> +{
> +	json_object *obj;
> +	json_file jfile;
> +
> +	jfile.filename = filename;
> +	jfile.linenum = 1;
> +	jfile.charnum = 0;
> +	jfile.error_reported = 0;
> +
> +	jfile.fp = fopen(filename, "r");
> +	if (!jfile.fp)
> +		return NULL;
> +
> +	obj = json_parse_object(&jfile);
> +
> +	fclose(jfile.fp);
> +	return obj;
> +}
> +
> +/*
> + *  json_object_new_object()
> + *	return a new json object, NULL if failed
> + */
> +json_object *json_object_new_object(void)
> +{
> +	json_object *obj;
> +
> +	obj = calloc(1, sizeof(*obj));
> +	if (!obj)
> +		return NULL;
> +	obj->type = type_object;
> +	obj->u.ptr = NULL;
> +
> +	return obj;
> +}
> +
> +/*
> + *  json_object_new_object()
> + *	return a new json object, NULL if failed
> + */
> +int json_object_array_length(json_object *obj)
> +{
> +	if (!obj)
> +		return 0;
> +	if (obj->type != type_array)
> +		return 0;
> +	return obj->length;
> +}
> +
> +/*
> + *  json_object_new_int()
> + *	return a new json integer object, NULL if failed
> + */
> +json_object *json_object_new_int(int val)
> +{
> +	json_object *obj;
> +
> +	obj = calloc(1, sizeof(*obj));
> +	if (!obj)
> +		return NULL;
> +	obj->type = type_int;
> +	obj->u.intval = val;
> +
> +	return obj;
> +}
> +
> +/*
> + *  json_object_new_string()
> + *	return a new json string object, NULL if failed
> + */
> +json_object *json_object_new_string(const char *str)
> +{
> +	json_object *obj;
> +
> +	obj = calloc(1, sizeof(*obj));
> +	if (!obj)
> +		return NULL;
> +	obj->type = type_string;
> +	obj->u.ptr = strdup(str);
> +	if (!obj->u.ptr) {
> +		free(obj);
> +		return NULL;
> +	}
> +	return obj;
> +}
> +
> +/*
> + *  json_object_new_array()
> + *	return a new json array object, NULL if failed
> + */
> +json_object *json_object_new_array(void)
> +{
> +	json_object *obj;
> +
> +	obj = calloc(1, sizeof(*obj));
> +	if (!obj)
> +		return NULL;
> +	obj->type = type_array;
> +	obj->length = 0;
> +	obj->u.ptr = NULL;
> +
> +	return obj;
> +}
> +
> +/*
> + *  json_object_array_add_item()
> + *	add an object to another object, return 0 if succeeded,
> + *	non-zero if failed
> + */
> +static int json_object_array_add_item(json_object *obj, json_object *item)
> +{
> +	json_object **obj_ptr;
> +
> +	if (obj->length < 0)
> +		return -1;
> +	obj_ptr = realloc(obj->u.ptr, sizeof(json_object *) * (obj->length + 1));
> +	if (!obj_ptr)
> +		return -1;
> +	obj->u.ptr = (void *)obj_ptr;
> +	obj_ptr[obj->length] = item;
> +	obj->length++;
> +	return 0;
> +}
> +
> +/*
> + *  json_object_array_add()
> + *	add a object to a json array object, return NULL if failed
> + */
> +int json_object_array_add(json_object *obj, json_object *item)
> +{
> +	if (!obj || !item)
> +		return -1;
> +	if (obj->type != type_array)
> +		return -1;
> +	return json_object_array_add_item(obj, item);
> +}
> +
> +
> +/*
> + *  json_object_object_add()
> + *	add a key/valyue object to a json object, return NULL if failed
> + */
> +void json_object_object_add(json_object *obj, const char *key, json_object *value)
> +{
> +	if (!obj || !key || !value)
> +		return;
> +	if (obj->type != type_object)
> +		return;
> +	value->key = strdup(key);
> +	if (!value->key)
> +		return;
> +	json_object_array_add_item(obj, value);
> +}
> +
> +/*
> + *  json_object_array_get_idx()
> + *	get an object at position index from a json array object,
> + *	return NULL if failed
> + */
> +json_object *json_object_array_get_idx(json_object *obj, int index)
> +{
> +	json_object **obj_array;
> +
> +	if (!obj)
> +		return NULL;
> +	if (obj->type != type_array)
> +		return NULL;
> +	if (index >= obj->length)
> +		return NULL;
> +	obj_array = (json_object **)obj->u.ptr;
> +	if (obj_array == NULL)
> +		return NULL;
> +	return obj_array[index];
> +}
> +
> +/*
> + *  json_object_get_string()
> + *	return a C string from a json string object
> + */
> +const char *json_object_get_string(json_object *obj)
> +{
> +	if (!obj)
> +		return NULL;
> +	if (obj->type != type_string)
> +		return NULL;
> +	return (const char *)obj->u.ptr;
> +}
> +
> +/*
> + *  json_object_put()
> + *	free a json object and all sub-objects
> + */
> +void json_object_put(json_object *obj)
> +{
> +	int i;
> +	json_object **obj_ptr;
> +
> +	if (!obj)
> +		return;
> +
> +	if (obj->key)
> +		free(obj->key);
> +
> +	switch (obj->type) {
> +	case type_array:
> +	case type_object:
> +		obj_ptr = (json_object **)obj->u.ptr;
> +
> +		for (i = 0; i < obj->length; i++) {
> +			json_object_put(obj_ptr[i]);
> +		}
> +		free(obj->u.ptr);
> +		break;
> +	case type_string:
> +		free(obj->u.ptr);
> +		break;
> +	case type_null:
> +	case type_int:
> +	default:
> +		break;
> +	}
> +	free(obj);
> +}
> +
> +/*
> + *  str_append()
> + *	append a string to a string, return NULL if failed
> + */
> +static char *str_append(char *str, char *append)
> +{
> +	char *new_str;
> +	size_t len;
> +
> +	if (!append)
> +		return NULL;
> +
> +	if (str) {
> +		len = strlen(append) + strlen(str) + 1;
> +		new_str = realloc(str, len);
> +		if (!new_str) {
> +			free(str);
> +			return NULL;
> +		}
> +		strcat(new_str, append);
> +	} else {
> +		len = strlen(append) + 1;
> +		new_str = malloc(len);
> +		if (!new_str)
> +			return NULL;
> +		strcpy(new_str, append);
> +	}
> +	return new_str;
> +}
> +
> +/*
> + *  str_indent()
> + *	add 2 spaces per indent level to a string, returns
> + *	NULL if failed
> + */
> +static char *str_indent(char *str, int indent)
> +{
> +	char buf[81];
> +	int i;
> +
> +	indent = indent + indent;
> +	if (indent > 80)
> +		indent = 80;
> +
> +	for (i = 0; i < indent; i++)
> +		buf[i] = ' ';
> +	buf[i] = '\0';
> +
> +	return str_append(str, buf);
> +}
> +
> +/*
> + *  json_object_to_json_string_indent()
> + *	turn a simplified fwts json object into a C string, returns
> + *	the stringified object or NULL if failed. Will traverse object
> + *	tree and add indentation based on recursion depth.
> + */
> +static char *json_object_to_json_string_indent(json_object *obj, int indent)
> +{
> +	int i;
> +	json_object **obj_ptr;
> +	char *str = NULL;
> +	char buf[64];
> +
> +	if (!obj)
> +		return NULL;
> +
> +	if (obj->type == type_object) {
> +		str = str_indent(str, indent);
> +		if (!str)
> +			return NULL;
> +		str = str_append(str, "{\n");
> +		if (!str)
> +			return NULL;
> +	}
> +
> +        if (obj->key) {
> +		str = str_indent(str, indent);
> +		if (!str)
> +			return NULL;
> +		str = str_append(str, "\"");
> +		if (!str)
> +			return NULL;
> +		str = str_append(str, obj->key);
> +		if (!str)
> +			return NULL;
> +		str = str_append(str, "\":");
> +		if (!str)
> +			return NULL;
> +        }
> +
> +	switch (obj->type) {
> +	case type_array:
> +		str = str_append(str, "[\n");
> +		if (!str)
> +			return NULL;
> +
> +		obj_ptr = (json_object **)obj->u.ptr;
> +		if (obj_ptr) {
> +			for (i = 0; i < obj->length; i++) {
> +				char *obj_str = json_object_to_json_string_indent(obj_ptr[i], indent + 1);
> +
> +				if (!obj_str) {
> +					free(str);
> +					return NULL;
> +				}
> +				str = str_append(str, obj_str);
> +				if (!str)
> +					return NULL;
> +			}
> +		}
> +		str = str_append(str, "\n");
> +		if (!str)
> +			return NULL;
> +		str = str_indent(str, indent);
> +		if (!str)
> +			return NULL;
> +		str = str_append(str, "]\n");
> +		if (!str)
> +			return NULL;
> +		break;
> +
> +	case type_object:
> +		obj_ptr = (json_object **)obj->u.ptr;
> +		if (obj_ptr) {
> +			for (i = 0; i < obj->length; i++) {
> +				char *obj_str = json_object_to_json_string_indent(obj_ptr[i], indent + 1);
> +
> +				if (!obj_str)
> +					return NULL;
> +				str = str_append(str, obj_str);
> +				if (!str)
> +					return NULL;
> +			}
> +		}
> +		if (!str)
> +			return NULL;
> +		break;
> +
> +	case type_string:
> +		str = str_append(str, "\"");
> +		if (!str)
> +			return NULL;
> +		str = str_append(str, (char *)obj->u.ptr);
> +		if (!str)
> +			return NULL;
> +		str = str_append(str, "\",\n");
> +		if (!str)
> +			return NULL;
> +		break;
> +
> +	case type_null:
> +		str = str_append(str, "(null)\n");
> +		if (!str)
> +			return NULL;
> +		break;
> +
> +	case type_int:
> +		snprintf(buf, sizeof(buf), "%d,\n", obj->u.intval);
> +		str = str_append(str, buf);
> +		if (!str)
> +			return NULL;
> +		break;
> +	default:
> +		return NULL;
> +	}
> +
> +	if (obj->type == type_object) {
> +		str = str_indent(str, indent);
> +		if (!str)
> +			return NULL;
> +		str = str_append(str, "},\n");
> +		if (!str)
> +			return NULL;
> +	}
> +	return str;
> +}
> +
> +/*
> + *  json_object_to_json_string
> + *	convert simplified fwts object to a C string, returns
> + *	NULL if failed
> + */
> +char *json_object_to_json_string(json_object *obj)
> +{
> +	return json_object_to_json_string_indent(obj, 0);
> +}
> +
> +/*
> + *  json_object_object_get()
> + *	return value from key/value pair from an object, returns
> + *	NULL if it can't be found
> + */
> +json_object *json_object_object_get(json_object *obj, const char *key)
> +{
> +	int i;
> +	json_object **obj_ptr;
> +
> +	if (!obj || !key)
> +		return NULL;
> +	if (obj->type != type_object)
> +		return NULL;
> +
> +	obj_ptr = (json_object **)obj->u.ptr;
> +	for (i = 0; i < obj->length; i++) {
> +		if (obj_ptr[i]->key && !strcmp(obj_ptr[i]->key, key))
> +			return obj_ptr[i];
> +	}
> +	return NULL;
> +}
> +
> diff --git a/src/utilities/Makefile.am b/src/utilities/Makefile.am
> index 98d6ebaa..2ae86038 100644
> --- a/src/utilities/Makefile.am
> +++ b/src/utilities/Makefile.am
> @@ -18,10 +18,11 @@
>  
>  AM_CPPFLAGS = -Wall -Werror -Wextra -DDATAROOTDIR=\"$(datarootdir)\" \
>  	`pkg-config --silence-errors --cflags json` \
> -	`pkg-config --silence-errors --cflags json-c`
> +	`pkg-config --silence-errors --cflags json-c` \
> +	-I../lib/include
>  
>  bin_PROGRAMS = kernelscan
> -kernelscan_SOURCES = kernelscan.c
> +kernelscan_SOURCES = kernelscan.c ../lib/src/fwts_json.c
>  
>  
>  -include $(top_srcdir)/git.mk
>
Colin Ian King Aug. 21, 2020, 10:43 a.m. UTC | #2
On 21/08/2020 11:35, ivanhu wrote:
> Got build error blow, seems kernelscan.c still hasn't used these functions.
> #include <json.h> in kernelscan.c

Hrm, it works for me with a clean clone and applying the patches. Did
you work from a fresh autoconfig. e.g.:

autoreconf -ivf
./configure
make

Colin


> 
> kernelscan.c: In function ‘klog_load’:
> kernelscan.c:365:2: error: ‘json_object_object_get’ is deprecated
> [-Werror=deprecated-declarations]
>   klog_table = json_object_object_get(klog_objs, table);
>   ^~~~~~~~~~
> In file included from /usr/include/json-c/linkhash.h:16:0,
>                  from /usr/include/json-c/json.h:22,
>                  from kernelscan.c:28:
> /usr/include/json-c/json_object.h:290:56: note: declared here
>  THIS_FUNCTION_IS_DEPRECATED(extern struct json_object*
> json_object_object_get(struct json_object* obj,
>                                                         ^
> /usr/include/json-c/json_object.h:17:43: note: in definition of macro
> ‘THIS_FUNCTION_IS_DEPRECATED’
>  #define THIS_FUNCTION_IS_DEPRECATED(func) func __attribute__ ((deprecated))
>                                            ^~~~
> kernelscan.c:401:3: error: ‘json_object_object_get’ is deprecated
> [-Werror=deprecated-declarations]
>    str = (char*)json_object_get_string(json_object_object_get(obj,
> "compare_mode"));
>    ^~~
> In file included from /usr/include/json-c/linkhash.h:16:0,
>                  from /usr/include/json-c/json.h:22,
>                  from kernelscan.c:28:
> /usr/include/json-c/json_object.h:290:56: note: declared here
>  THIS_FUNCTION_IS_DEPRECATED(extern struct json_object*
> json_object_object_get(struct json_object* obj,
>                                                         ^
> /usr/include/json-c/json_object.h:17:43: note: in definition of macro
> ‘THIS_FUNCTION_IS_DEPRECATED’
>  #define THIS_FUNCTION_IS_DEPRECATED(func) func __attribute__ ((deprecated))
>                                            ^~~~
> kernelscan.c:416:3: error: ‘json_object_object_get’ is deprecated
> [-Werror=deprecated-declarations]
>    str = (char*)json_object_get_string(json_object_object_get(obj,
> "pattern"));
>    ^~~
> In file included from /usr/include/json-c/linkhash.h:16:0,
>                  from /usr/include/json-c/json.h:22,
>                  from kernelscan.c:28:
> /usr/include/json-c/json_object.h:290:56: note: declared here
>  THIS_FUNCTION_IS_DEPRECATED(extern struct json_object*
> json_object_object_get(struct json_object* obj,
>                                                         ^
> /usr/include/json-c/json_object.h:17:43: note: in definition of macro
> ‘THIS_FUNCTION_IS_DEPRECATED’
>  #define THIS_FUNCTION_IS_DEPRECATED(func) func __attribute__ ((deprecated))
>                                            ^~~~
> 
> Ivan
> 
> On 8/17/20 6:22 PM, Colin King wrote:
>> From: Colin Ian King <colin.king@canonical.com>
>>
>> FWTS uses a subset of json-c functionality, so replace it with
>> our own implementation that supports this subset. This also
>> removes the dependency of two flavours of json libraries that
>> fwts has been using and also allows us to perform deeper memory
>> allocation and leaking tracking with static analysis tools.
>>
>> Signed-off-by: Colin Ian King <colin.king@canonical.com>
>> ---
>>  configure.ac                |   3 -
>>  src/lib/include/fwts.h      |   2 +
>>  src/lib/include/fwts_json.h |  61 ++-
>>  src/lib/src/Makefile.am     |   1 +
>>  src/lib/src/fwts_json.c     | 917 ++++++++++++++++++++++++++++++++++++
>>  src/utilities/Makefile.am   |   5 +-
>>  6 files changed, 969 insertions(+), 20 deletions(-)
>>  create mode 100644 src/lib/src/fwts_json.c
>>
>> diff --git a/configure.ac b/configure.ac
>> index 39a445cd..f40c3678 100644
>> --- a/configure.ac
>> +++ b/configure.ac
>> @@ -9,8 +9,6 @@
>>  	  AC_PROG_LIBTOOL
>>  	  AC_C_INLINE
>>  	  AM_PROG_CC_C_O
>> -	  AC_SEARCH_LIBS([json_object_from_file], [json json-c], [], [ AC_MSG_ERROR([no available json library]) ])
>> -	  AC_SEARCH_LIBS([json_object_object_get_ex], [json json-c], [ AC_DEFINE([JSON_HAS_GET_EX], [1], [Define if we have json_object_object_get_ex])], [])
>>    	  AC_CHECK_FUNCS([localtime_r])
>>  	  AC_CHECK_FUNCS([dup2])
>>  	  AC_CHECK_FUNCS([getcwd])
>> @@ -61,7 +59,6 @@
>>  	  AC_CHECK_HEADERS([time.h])
>>  	  AC_CHECK_HEADERS([sys/ioctl.h])
>>  	  AC_CHECK_HEADERS([sys/time.h])
>> -	  AC_CHECK_HEADERS([json/json.h])
>>  	  AC_CHECK_HEADERS([glib.h])
>>  	  AC_CHECK_HEADERS([gio/gio.h])
>>  	  AC_CHECK_HEADERS([asm/opal-prd.h])
>> diff --git a/src/lib/include/fwts.h b/src/lib/include/fwts.h
>> index 1e0d5870..6f13d262 100644
>> --- a/src/lib/include/fwts.h
>> +++ b/src/lib/include/fwts.h
>> @@ -153,6 +153,8 @@
>>  
>>  #define FWTS_JSON_DATA_PATH	DATAROOTDIR "/fwts"
>>  
>> +#include <inttypes.h>
>> +
>>  #include "fwts_version.h"
>>  #include "fwts_backtrace.h"
>>  #include "fwts_types.h"
>> diff --git a/src/lib/include/fwts_json.h b/src/lib/include/fwts_json.h
>> index ad51bc45..0c316e02 100644
>> --- a/src/lib/include/fwts_json.h
>> +++ b/src/lib/include/fwts_json.h
>> @@ -1,5 +1,5 @@
>>  /*
>> - * Copyright (C) 2012-2020 Canonical
>> + * Copyright (C) 2010-2020 Canonical
>>   *
>>   * This program is free software; you can redistribute it and/or
>>   * modify it under the terms of the GNU General Public License
>> @@ -16,26 +16,15 @@
>>   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
>>   *
>>   */
>> -
>>  #ifndef __FWTS_JSON_H__
>>  #define __FWTS_JSON_H__
>>  
>> -#include <json.h>
>> -
>> -#define __FWTS_JSON_ERR_PTR__ ((json_object*) -1)
>>  /*
>> - *  Older versions of json-c may return an error in an
>> - *  object as a ((json_object*)-1), where as newer
>> - *  versions return NULL, so check for these. Sigh.
>> + *  Minimal subset of json for fwts
>>   */
>> -#define FWTS_JSON_ERROR(ptr) \
>> -	( (ptr == NULL) || ((const json_object *)ptr == __FWTS_JSON_ERR_PTR__) )
>>  
>> -/*
>> - * json-c 0.13.99 does not define TRUE/FALSE anymore
>> - * the json-c maintainers replaced them with pure 1/0
>> - * https://github.com/json-c/json-c/commit/0992aac61f8b
>> - */
>> +#define FWTS_JSON_ERROR(ptr) 	(!ptr)
>> +
>>  #ifndef FALSE
>>  #define FALSE 0
>>  #endif
>> @@ -44,4 +33,46 @@
>>  #define TRUE  1
>>  #endif
>>  
>> +/*
>> + *  json types supported
>> + */
>> +typedef enum {
>> +	type_null,
>> +	type_int,
>> +	type_string,
>> +	type_object,
>> +	type_array,
>> +} json_type;
>> +
>> +/*
>> + *  json object information
>> + */
>> +typedef struct json_object {
>> +	char *key;		/* Null if undefined */
>> +	int length;		/* Length of a collection of objects */
>> +	json_type type;		/* Object type */
>> +        union {
>> +                void *ptr;	/* string or object array pointer */
>> +                int  intval;	/* integer value */
>> +        } u;
>> +} json_object;
>> +
>> +/*
>> + *  minimal json c library functions as required by fwts
>> + */
>> +json_object *json_object_from_file(const char *filename);
>> +json_object *json_object_object_get(json_object *obj, const char *key);
>> +int json_object_array_length(json_object *obj);
>> +json_object *json_object_array_get_idx(json_object *obj, int index);
>> +const char *json_object_get_string(json_object *obj);
>> +json_object *json_object_new_int(int);
>> +void json_object_object_add(json_object *obj, const char *key, json_object *value);
>> +
>> +json_object *json_object_new_object(void);
>> +json_object *json_object_new_array(void);
>> +char *json_object_to_json_string(json_object *obj);
>> +void json_object_put(json_object *obj);
>> +json_object *json_object_new_string(const char *str);
>> +int json_object_array_add(json_object *obj, json_object *item);
>> +
>>  #endif
>> diff --git a/src/lib/src/Makefile.am b/src/lib/src/Makefile.am
>> index ecc4136b..4593bb82 100644
>> --- a/src/lib/src/Makefile.am
>> +++ b/src/lib/src/Makefile.am
>> @@ -82,6 +82,7 @@ libfwts_la_SOURCES = 		\
>>  	fwts_interactive.c 	\
>>  	fwts_ioport.c		\
>>  	fwts_ipmi.c		\
>> +	fwts_json.c		\
>>  	fwts_keymap.c 		\
>>  	fwts_klog.c 		\
>>  	fwts_olog.c		\
>> diff --git a/src/lib/src/fwts_json.c b/src/lib/src/fwts_json.c
>> new file mode 100644
>> index 00000000..b92a241a
>> --- /dev/null
>> +++ b/src/lib/src/fwts_json.c
>> @@ -0,0 +1,917 @@
>> +/*
>> + * Copyright (C) 2010-2020 Canonical
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * as published by the Free Software Foundation; either version 2
>> + * of the License, or (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write to the Free Software
>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
>> + *
>> + * This is a simplified json parser and json object store
>> + * based on json but does not support keywords and is designed
>> + * just for the fwts json data files. It is not a full json
>> + * implementation and should not be used as such.
>> + *
>> + */
>> +#include <stdlib.h>
>> +#include <stdio.h>
>> +#include <stdarg.h>
>> +#include <stdbool.h>
>> +#include <string.h>
>> +#include <unistd.h>
>> +#include <ctype.h>
>> +
>> +#include "fwts.h"
>> +
>> +/*
>> + *  json file information
>> + */
>> +typedef struct {
>> +	FILE *fp;		/* File pointer */
>> +	const char *filename;	/* Name of file */
>> +	int linenum;		/* Parser line number */
>> +	int charnum;		/* Parser char position */
>> +	int error_reported;	/* Error count */
>> +} json_file;
>> +
>> +/*
>> + *  json tokens, subset of full json token set as used
>> + *  for fwts requirements
>> + */
>> +typedef enum {
>> +	token_lbrace,
>> +	token_rbrace,
>> +	token_lbracket,
>> +	token_rbracket,
>> +	token_colon,
>> +	token_comma,
>> +	token_int,
>> +	token_string,
>> +	token_true,
>> +	token_false,
>> +	token_null,
>> +	token_error,
>> +	token_eof,
>> +} json_token_type;
>> +
>> +/*
>> + *  json parser token
>> + */
>> +typedef struct {
>> +	json_token_type type;	/* token type */
>> +	long offset;		/* offset in file for re-winding */
>> +	union {
>> +		char *str;	/* token string value */
>> +		int  intval;	/* token integer value */
>> +	} u;
>> +} json_token;
>> +
>> +/*
>> + *  json_token_string()
>> + *	convert json token to a human readable string
>> + */
>> +char *json_token_string(json_token *jtoken)
>> +{
>> +	static char tmp[64];
>> +
>> +	switch (jtoken->type) {
>> +	case token_lbrace:
>> +		return "{";
>> +	case token_rbrace:
>> +		return "}";
>> +	case token_lbracket:
>> +		return "[";
>> +	case token_rbracket:
>> +		return "]";
>> +	case token_colon:
>> +		return ":";
>> +	case token_comma:
>> +		return ",";
>> +	case token_int:
>> +		(void)snprintf(tmp, sizeof(tmp), "%d", jtoken->u.intval);
>> +		return tmp;
>> +	case token_string:
>> +		return jtoken->u.str;
>> +	case token_error:
>> +		return "<error>";
>> +	case token_eof:
>> +		return "end of file";
>> +	default:
>> +		break;
>> +	}
>> +	return "<illegal token>";
>> +}
>> +
>> +/*
>> + *  json_get_string()
>> + *	parse a literal string
>> + */
>> +json_token_type json_get_string(json_file *jfile, json_token *token)
>> +{
>> +	char buffer[4096];
>> +	size_t i = 0;
>> +
>> +	for (;;) {
>> +		int ch;
>> +
>> +		ch = fgetc(jfile->fp);
>> +		jfile->charnum++;
>> +		if (ch == EOF) {
>> +			fprintf(stderr, "json_parser: unexpected EOF in literal string\n");
>> +			token->u.str = NULL;
>> +			return token_error;
>> +		}
>> +
>> +		if (ch == '\\') {
>> +			ch = fgetc(jfile->fp);
>> +			switch (ch) {
>> +			case '\\':
>> +			case '"':
>> +			case '/':
>> +				break;
>> +			case 'b':
>> +				ch = '\b';
>> +				break;
>> +			case 'f':
>> +				ch = '\f';
>> +				break;
>> +			case 'n':
>> +				ch = '\n';
>> +				break;
>> +			case 'r':
>> +				ch = '\r';
>> +				break;
>> +			case 't':
>> +				ch = '\t';
>> +				break;
>> +			case 'u':
>> +				fprintf(stderr, "json parser: escaped hex values not supported\n");
>> +				ch = '?';
>> +				break;
>> +			}
>> +			jfile->charnum++;
>> +		} else if (ch == '"') {
>> +			buffer[i] = '\0';
>> +			token->u.str = strdup(buffer);
>> +			if (!token->u.str) {
>> +				fprintf(stderr, "json parser: out of memory allocating %zd byte string\n", i);
>> +				break;
>> +			}
>> +			return token_string;
>> +		}
>> +		buffer[i] = ch;
>> +		i++;
>> +		if (i >= sizeof(buffer)) {
>> +			fprintf(stderr, "json parser: string too long, maximum size %zd bytes\n", sizeof(buffer) - 1);
>> +			break;
>> +		}
>> +	}
>> +
>> +	token->u.str = NULL;
>> +	return token_error;
>> +}
>> +
>> +/*
>> + *  json_get_int()
>> + *	parse a simple integer
>> + */
>> +json_token_type json_get_int(json_file *jfile, json_token *token)
>> +{
>> +	char buffer[64];
>> +	size_t i = 0;
>> +
>> +	for (;;) {
>> +		int ch;
>> +
>> +		ch = fgetc(jfile->fp);
>> +		if (!isdigit(ch)) {
>> +			(void)ungetc(ch, jfile->fp);
>> +			buffer[i] = '\0';
>> +			token->u.intval = atoi(buffer);
>> +			return token_int;
>> +		}
>> +		jfile->charnum++;
>> +		buffer[i] = ch;
>> +		i++;
>> +		if (i >= sizeof(buffer)) {
>> +			fprintf(stderr, "json parser: integer too long, maximum size %zd bytes\n", sizeof(buffer) - 1);
>> +			break;
>> +		}
>> +	}
>> +
>> +	token->u.str = NULL;
>> +	return token_error;
>> +}
>> +
>> +/*
>> + *  json_unget_token()
>> + *  	push file pointer back to point before the token
>> + *	to unpush the token
>> + */
>> +int json_unget_token(json_file *jfile, json_token *token)
>> +{
>> +	return fseek(jfile->fp, token->offset, SEEK_SET);
>> +}
>> +
>> +/*
>> + *  json_get_keyword()
>> + *	get a keyword
>> + */
>> +int json_get_keyword(json_file *jfile, json_token *token)
>> +{
>> +	char buffer[32];
>> +	size_t i = 0;
>> +
>> +	token->u.str = NULL;
>> +	*buffer = '\0';
>> +
>> +	for (;;) {
>> +		int ch;
>> +
>> +		ch = fgetc(jfile->fp);
>> +		jfile->charnum++;
>> +		if (ch == EOF) {
>> +			fprintf(stderr, "json_parser: unexpected EOF in keyword string\n");
>> +			return token_error;
>> +		}
>> +		if (ch < 'a' || ch > 'z')
>> +			break;
>> +
>> +		buffer[i] = ch;
>> +		i++;
>> +		if (i >= sizeof(buffer)) {
>> +			fprintf(stderr, "json parser: keyword too long, maximum size %zd bytes\n", sizeof(buffer) - 1);
>> +			return token_error;
>> +		}
>> +	}
>> +	if (!strcmp(buffer, "true"))
>> +		return token_true;
>> +	if (!strcmp(buffer, "false"))
>> +		return token_false;
>> +	if (!strcmp(buffer, "null"))
>> +		return token_null;
>> +	return token_error;
>> +}
>> +
>> +/*
>> + *  json_get_token()
>> + *	read next input character(s) and return a matching token
>> + */
>> +json_token_type json_get_token(json_file *jfile, json_token *token)
>> +{
>> +	(void)memset(token, 0, sizeof(*token));
>> +
>> +	token->offset = ftell(jfile->fp);
>> +	for (;;) {
>> +		int ch;
>> +
>> +		ch = fgetc(jfile->fp);
>> +		jfile->charnum++;
>> +
>> +		switch (ch) {
>> +		case '\n':
>> +			jfile->linenum++;
>> +			continue;
>> +		case ' ':
>> +		case '\r':
>> +		case '\t':
>> +			continue;
>> +		case EOF:
>> +			token->type = token_eof;
>> +			return token->type;
>> +		case '{':
>> +			token->type = token_lbrace;
>> +			return token->type;
>> +		case '}':
>> +			token->type = token_rbrace;
>> +			return token->type;
>> +		case '[':
>> +			token->type = token_lbracket;
>> +			return token->type;
>> +		case ']':
>> +			token->type = token_rbracket;
>> +			return token->type;
>> +		case ':':
>> +			token->type = token_colon;
>> +			return token->type;
>> +		case ',':
>> +			token->type = token_comma;
>> +			return token->type;
>> +		case '"':
>> +			token->type = json_get_string(jfile, token);
>> +			return token->type;
>> +		case '0'...'9':
>> +			token->type = json_get_int(jfile, token);
>> +			return token->type;
>> +		case 'a'...'z':
>> +			fprintf(stderr, "json_parser: keywords not supported\n");
>> +			token->type = token_error;
>> +			return token->type;
>> +		default:
>> +			token->type = token_error;
>> +			return token->type;
>> +		}
>> +	}
>> +
>> +	/* Should never reach here */
>> +	token->type = token_error;
>> +	return token->type;
>> +}
>> +
>> +/*
>> + *  json_parse_error_where()
>> + *	very simple parser error message, report where in the file
>> + *	the parsing error occurred.
>> + */
>> +void json_parse_error_where(json_file *jfile)
>> +{
>> +	if (jfile->error_reported == 0)
>> +		fprintf(stderr, "json_parser: aborted at line %d, char %d of file %s\n",
>> +			jfile->linenum, jfile->charnum, jfile->filename);
>> +	jfile->error_reported++;
>> +}
>> +
>> +json_object *json_parse_object(json_file *jfile);
>> +
>> +/*
>> + *  json_parse_array()
>> + *	parse a json array
>> + */
>> +json_object *json_parse_array(json_file *jfile)
>> +{
>> +	json_object *array_obj;
>> +
>> +	array_obj = json_object_new_array();
>> +	if (!array_obj) {
>> +		fprintf(stderr, "json_parser: out of memory allocating a json array object\n");
>> +		json_parse_error_where(jfile);
>> +		return NULL;
>> +	}
>> +
>> +	for (;;) {
>> +		json_object *obj;
>> +		json_token token;
>> +
>> +		obj = json_parse_object(jfile);
>> +		if (!obj) {
>> +			json_parse_error_where(jfile);
>> +			free(array_obj);
>> +			return NULL;
>> +		}
>> +		json_object_array_add(array_obj, obj);
>> +
>> +		switch (json_get_token(jfile, &token)) {
>> +		case token_rbracket:
>> +			return array_obj;
>> +		case token_comma:
>> +			continue;
>> +		default:
>> +			if (json_unget_token(jfile, &token) != 0) {
>> +				fprintf(stderr, "json_parser: failed to unget a token\n");
>> +				free(array_obj);
>> +				return NULL;
>> +			}
>> +			break;
>> +		}
>> +	}
>> +	return array_obj;
>> +}
>> +
>> +/*
>> + *  json_parse_object()
>> + *	parse a json object (simplified fwts json format only)
>> + */
>> +json_object *json_parse_object(json_file *jfile)
>> +{
>> +	json_token token;
>> +	json_object *obj, *val_obj;
>> +	char *key = NULL;
>> +
>> +	if (json_get_token(jfile, &token) != token_lbrace) {
>> +		fprintf(stderr, "json_parser: expecting '{', got %s instead\n", json_token_string(&token));
>> +		return NULL;
>> +	}
>> +
>> +	obj = json_object_new_object();
>> +	if (!obj)
>> +		goto err_nomem;
>> +
>> +	for (;;) {
>> +		switch (json_get_token(jfile, &token)) {
>> +		case token_rbrace:
>> +			return obj;
>> +		case token_string:
>> +			key = token.u.str;
>> +			if (!key)
>> +				goto err_nomem;
>> +			token.u.str = NULL;
>> +			break;
>> +		default:
>> +			fprintf(stderr, "json_parser: expecting } or key literal string, got %s instead\n", json_token_string(&token));
>> +			goto err_free;
>> +		}
>> +		if (json_get_token(jfile, &token) != token_colon) {
>> +			fprintf(stderr, "json_parser: expecting ':', got %s instead\n", json_token_string(&token));
>> +			goto err_free;
>> +		}
>> +		switch (json_get_token(jfile, &token)) {
>> +		case token_string:
>> +			val_obj = json_object_new_string(token.u.str);
>> +			if (!val_obj)
>> +				goto err_nomem;
>> +			json_object_object_add(obj, key, val_obj);
>> +			free(key);
>> +			break;
>> +		case token_int:
>> +			val_obj = json_object_new_int(token.u.intval);
>> +			if (!val_obj)
>> +				goto err_nomem;
>> +			json_object_object_add(obj, key, val_obj);
>> +			free(key);
>> +			break;
>> +		case token_lbracket:
>> +			val_obj = json_parse_array(jfile);
>> +			if (!val_obj)
>> +				goto err_nomem;
>> +			json_object_object_add(obj, key, val_obj);
>> +			break;
>> +		case token_lbrace:
>> +			fprintf(stderr, "json_parser: nested objects not supported\n");
>> +			goto err_free;
>> +		case token_true:
>> +		case token_false:
>> +		case token_null:
>> +			fprintf(stderr, "json_parser: tokens %s not supported\n", json_token_string(&token));
>> +			goto err_free;
>> +		default:
>> +			fprintf(stderr, "json_parser: unexpected token %s\n", json_token_string(&token));
>> +		}
>> +		switch (json_get_token(jfile, &token)) {
>> +		case token_comma:
>> +			continue;
>> +		case token_rbrace:
>> +			return obj;
>> +		default:
>> +			fprintf(stderr, "json_parser: expected , or }, got %s instead\n", json_token_string(&token));
>> +			goto err_free;
>> +		}
>> +	}
>> +
>> +err_nomem:
>> +	fprintf(stderr, "json_parser: out of memory allocating a json object\n");
>> +	json_parse_error_where(jfile);
>> +err_free:
>> +	free(obj);
>> +	return NULL;
>> +}
>> +
>> +/*
>> + *  json_object_from_file()
>> + *	parse a simplified fwts json file and convert it into
>> + *	a json object, return NULL if parsing failed or ran
>> + *	out of memory
>> + */
>> +json_object *json_object_from_file(const char *filename)
>> +{
>> +	json_object *obj;
>> +	json_file jfile;
>> +
>> +	jfile.filename = filename;
>> +	jfile.linenum = 1;
>> +	jfile.charnum = 0;
>> +	jfile.error_reported = 0;
>> +
>> +	jfile.fp = fopen(filename, "r");
>> +	if (!jfile.fp)
>> +		return NULL;
>> +
>> +	obj = json_parse_object(&jfile);
>> +
>> +	fclose(jfile.fp);
>> +	return obj;
>> +}
>> +
>> +/*
>> + *  json_object_new_object()
>> + *	return a new json object, NULL if failed
>> + */
>> +json_object *json_object_new_object(void)
>> +{
>> +	json_object *obj;
>> +
>> +	obj = calloc(1, sizeof(*obj));
>> +	if (!obj)
>> +		return NULL;
>> +	obj->type = type_object;
>> +	obj->u.ptr = NULL;
>> +
>> +	return obj;
>> +}
>> +
>> +/*
>> + *  json_object_new_object()
>> + *	return a new json object, NULL if failed
>> + */
>> +int json_object_array_length(json_object *obj)
>> +{
>> +	if (!obj)
>> +		return 0;
>> +	if (obj->type != type_array)
>> +		return 0;
>> +	return obj->length;
>> +}
>> +
>> +/*
>> + *  json_object_new_int()
>> + *	return a new json integer object, NULL if failed
>> + */
>> +json_object *json_object_new_int(int val)
>> +{
>> +	json_object *obj;
>> +
>> +	obj = calloc(1, sizeof(*obj));
>> +	if (!obj)
>> +		return NULL;
>> +	obj->type = type_int;
>> +	obj->u.intval = val;
>> +
>> +	return obj;
>> +}
>> +
>> +/*
>> + *  json_object_new_string()
>> + *	return a new json string object, NULL if failed
>> + */
>> +json_object *json_object_new_string(const char *str)
>> +{
>> +	json_object *obj;
>> +
>> +	obj = calloc(1, sizeof(*obj));
>> +	if (!obj)
>> +		return NULL;
>> +	obj->type = type_string;
>> +	obj->u.ptr = strdup(str);
>> +	if (!obj->u.ptr) {
>> +		free(obj);
>> +		return NULL;
>> +	}
>> +	return obj;
>> +}
>> +
>> +/*
>> + *  json_object_new_array()
>> + *	return a new json array object, NULL if failed
>> + */
>> +json_object *json_object_new_array(void)
>> +{
>> +	json_object *obj;
>> +
>> +	obj = calloc(1, sizeof(*obj));
>> +	if (!obj)
>> +		return NULL;
>> +	obj->type = type_array;
>> +	obj->length = 0;
>> +	obj->u.ptr = NULL;
>> +
>> +	return obj;
>> +}
>> +
>> +/*
>> + *  json_object_array_add_item()
>> + *	add an object to another object, return 0 if succeeded,
>> + *	non-zero if failed
>> + */
>> +static int json_object_array_add_item(json_object *obj, json_object *item)
>> +{
>> +	json_object **obj_ptr;
>> +
>> +	if (obj->length < 0)
>> +		return -1;
>> +	obj_ptr = realloc(obj->u.ptr, sizeof(json_object *) * (obj->length + 1));
>> +	if (!obj_ptr)
>> +		return -1;
>> +	obj->u.ptr = (void *)obj_ptr;
>> +	obj_ptr[obj->length] = item;
>> +	obj->length++;
>> +	return 0;
>> +}
>> +
>> +/*
>> + *  json_object_array_add()
>> + *	add a object to a json array object, return NULL if failed
>> + */
>> +int json_object_array_add(json_object *obj, json_object *item)
>> +{
>> +	if (!obj || !item)
>> +		return -1;
>> +	if (obj->type != type_array)
>> +		return -1;
>> +	return json_object_array_add_item(obj, item);
>> +}
>> +
>> +
>> +/*
>> + *  json_object_object_add()
>> + *	add a key/valyue object to a json object, return NULL if failed
>> + */
>> +void json_object_object_add(json_object *obj, const char *key, json_object *value)
>> +{
>> +	if (!obj || !key || !value)
>> +		return;
>> +	if (obj->type != type_object)
>> +		return;
>> +	value->key = strdup(key);
>> +	if (!value->key)
>> +		return;
>> +	json_object_array_add_item(obj, value);
>> +}
>> +
>> +/*
>> + *  json_object_array_get_idx()
>> + *	get an object at position index from a json array object,
>> + *	return NULL if failed
>> + */
>> +json_object *json_object_array_get_idx(json_object *obj, int index)
>> +{
>> +	json_object **obj_array;
>> +
>> +	if (!obj)
>> +		return NULL;
>> +	if (obj->type != type_array)
>> +		return NULL;
>> +	if (index >= obj->length)
>> +		return NULL;
>> +	obj_array = (json_object **)obj->u.ptr;
>> +	if (obj_array == NULL)
>> +		return NULL;
>> +	return obj_array[index];
>> +}
>> +
>> +/*
>> + *  json_object_get_string()
>> + *	return a C string from a json string object
>> + */
>> +const char *json_object_get_string(json_object *obj)
>> +{
>> +	if (!obj)
>> +		return NULL;
>> +	if (obj->type != type_string)
>> +		return NULL;
>> +	return (const char *)obj->u.ptr;
>> +}
>> +
>> +/*
>> + *  json_object_put()
>> + *	free a json object and all sub-objects
>> + */
>> +void json_object_put(json_object *obj)
>> +{
>> +	int i;
>> +	json_object **obj_ptr;
>> +
>> +	if (!obj)
>> +		return;
>> +
>> +	if (obj->key)
>> +		free(obj->key);
>> +
>> +	switch (obj->type) {
>> +	case type_array:
>> +	case type_object:
>> +		obj_ptr = (json_object **)obj->u.ptr;
>> +
>> +		for (i = 0; i < obj->length; i++) {
>> +			json_object_put(obj_ptr[i]);
>> +		}
>> +		free(obj->u.ptr);
>> +		break;
>> +	case type_string:
>> +		free(obj->u.ptr);
>> +		break;
>> +	case type_null:
>> +	case type_int:
>> +	default:
>> +		break;
>> +	}
>> +	free(obj);
>> +}
>> +
>> +/*
>> + *  str_append()
>> + *	append a string to a string, return NULL if failed
>> + */
>> +static char *str_append(char *str, char *append)
>> +{
>> +	char *new_str;
>> +	size_t len;
>> +
>> +	if (!append)
>> +		return NULL;
>> +
>> +	if (str) {
>> +		len = strlen(append) + strlen(str) + 1;
>> +		new_str = realloc(str, len);
>> +		if (!new_str) {
>> +			free(str);
>> +			return NULL;
>> +		}
>> +		strcat(new_str, append);
>> +	} else {
>> +		len = strlen(append) + 1;
>> +		new_str = malloc(len);
>> +		if (!new_str)
>> +			return NULL;
>> +		strcpy(new_str, append);
>> +	}
>> +	return new_str;
>> +}
>> +
>> +/*
>> + *  str_indent()
>> + *	add 2 spaces per indent level to a string, returns
>> + *	NULL if failed
>> + */
>> +static char *str_indent(char *str, int indent)
>> +{
>> +	char buf[81];
>> +	int i;
>> +
>> +	indent = indent + indent;
>> +	if (indent > 80)
>> +		indent = 80;
>> +
>> +	for (i = 0; i < indent; i++)
>> +		buf[i] = ' ';
>> +	buf[i] = '\0';
>> +
>> +	return str_append(str, buf);
>> +}
>> +
>> +/*
>> + *  json_object_to_json_string_indent()
>> + *	turn a simplified fwts json object into a C string, returns
>> + *	the stringified object or NULL if failed. Will traverse object
>> + *	tree and add indentation based on recursion depth.
>> + */
>> +static char *json_object_to_json_string_indent(json_object *obj, int indent)
>> +{
>> +	int i;
>> +	json_object **obj_ptr;
>> +	char *str = NULL;
>> +	char buf[64];
>> +
>> +	if (!obj)
>> +		return NULL;
>> +
>> +	if (obj->type == type_object) {
>> +		str = str_indent(str, indent);
>> +		if (!str)
>> +			return NULL;
>> +		str = str_append(str, "{\n");
>> +		if (!str)
>> +			return NULL;
>> +	}
>> +
>> +        if (obj->key) {
>> +		str = str_indent(str, indent);
>> +		if (!str)
>> +			return NULL;
>> +		str = str_append(str, "\"");
>> +		if (!str)
>> +			return NULL;
>> +		str = str_append(str, obj->key);
>> +		if (!str)
>> +			return NULL;
>> +		str = str_append(str, "\":");
>> +		if (!str)
>> +			return NULL;
>> +        }
>> +
>> +	switch (obj->type) {
>> +	case type_array:
>> +		str = str_append(str, "[\n");
>> +		if (!str)
>> +			return NULL;
>> +
>> +		obj_ptr = (json_object **)obj->u.ptr;
>> +		if (obj_ptr) {
>> +			for (i = 0; i < obj->length; i++) {
>> +				char *obj_str = json_object_to_json_string_indent(obj_ptr[i], indent + 1);
>> +
>> +				if (!obj_str) {
>> +					free(str);
>> +					return NULL;
>> +				}
>> +				str = str_append(str, obj_str);
>> +				if (!str)
>> +					return NULL;
>> +			}
>> +		}
>> +		str = str_append(str, "\n");
>> +		if (!str)
>> +			return NULL;
>> +		str = str_indent(str, indent);
>> +		if (!str)
>> +			return NULL;
>> +		str = str_append(str, "]\n");
>> +		if (!str)
>> +			return NULL;
>> +		break;
>> +
>> +	case type_object:
>> +		obj_ptr = (json_object **)obj->u.ptr;
>> +		if (obj_ptr) {
>> +			for (i = 0; i < obj->length; i++) {
>> +				char *obj_str = json_object_to_json_string_indent(obj_ptr[i], indent + 1);
>> +
>> +				if (!obj_str)
>> +					return NULL;
>> +				str = str_append(str, obj_str);
>> +				if (!str)
>> +					return NULL;
>> +			}
>> +		}
>> +		if (!str)
>> +			return NULL;
>> +		break;
>> +
>> +	case type_string:
>> +		str = str_append(str, "\"");
>> +		if (!str)
>> +			return NULL;
>> +		str = str_append(str, (char *)obj->u.ptr);
>> +		if (!str)
>> +			return NULL;
>> +		str = str_append(str, "\",\n");
>> +		if (!str)
>> +			return NULL;
>> +		break;
>> +
>> +	case type_null:
>> +		str = str_append(str, "(null)\n");
>> +		if (!str)
>> +			return NULL;
>> +		break;
>> +
>> +	case type_int:
>> +		snprintf(buf, sizeof(buf), "%d,\n", obj->u.intval);
>> +		str = str_append(str, buf);
>> +		if (!str)
>> +			return NULL;
>> +		break;
>> +	default:
>> +		return NULL;
>> +	}
>> +
>> +	if (obj->type == type_object) {
>> +		str = str_indent(str, indent);
>> +		if (!str)
>> +			return NULL;
>> +		str = str_append(str, "},\n");
>> +		if (!str)
>> +			return NULL;
>> +	}
>> +	return str;
>> +}
>> +
>> +/*
>> + *  json_object_to_json_string
>> + *	convert simplified fwts object to a C string, returns
>> + *	NULL if failed
>> + */
>> +char *json_object_to_json_string(json_object *obj)
>> +{
>> +	return json_object_to_json_string_indent(obj, 0);
>> +}
>> +
>> +/*
>> + *  json_object_object_get()
>> + *	return value from key/value pair from an object, returns
>> + *	NULL if it can't be found
>> + */
>> +json_object *json_object_object_get(json_object *obj, const char *key)
>> +{
>> +	int i;
>> +	json_object **obj_ptr;
>> +
>> +	if (!obj || !key)
>> +		return NULL;
>> +	if (obj->type != type_object)
>> +		return NULL;
>> +
>> +	obj_ptr = (json_object **)obj->u.ptr;
>> +	for (i = 0; i < obj->length; i++) {
>> +		if (obj_ptr[i]->key && !strcmp(obj_ptr[i]->key, key))
>> +			return obj_ptr[i];
>> +	}
>> +	return NULL;
>> +}
>> +
>> diff --git a/src/utilities/Makefile.am b/src/utilities/Makefile.am
>> index 98d6ebaa..2ae86038 100644
>> --- a/src/utilities/Makefile.am
>> +++ b/src/utilities/Makefile.am
>> @@ -18,10 +18,11 @@
>>  
>>  AM_CPPFLAGS = -Wall -Werror -Wextra -DDATAROOTDIR=\"$(datarootdir)\" \
>>  	`pkg-config --silence-errors --cflags json` \
>> -	`pkg-config --silence-errors --cflags json-c`
>> +	`pkg-config --silence-errors --cflags json-c` \
>> +	-I../lib/include
>>  
>>  bin_PROGRAMS = kernelscan
>> -kernelscan_SOURCES = kernelscan.c
>> +kernelscan_SOURCES = kernelscan.c ../lib/src/fwts_json.c
>>  
>>  
>>  -include $(top_srcdir)/git.mk
>>
Alex Hung Aug. 21, 2020, 7:17 p.m. UTC | #3
On 2020-08-21 4:43 a.m., Colin Ian King wrote:
> On 21/08/2020 11:35, ivanhu wrote:
>> Got build error blow, seems kernelscan.c still hasn't used these functions.
>> #include <json.h> in kernelscan.c
> 
> Hrm, it works for me with a clean clone and applying the patches. Did
> you work from a fresh autoconfig. e.g.:
> 
> autoreconf -ivf
> ./configure
> make
> 
> Colin
> 
> 
>>
>> kernelscan.c: In function ‘klog_load’:
>> kernelscan.c:365:2: error: ‘json_object_object_get’ is deprecated
>> [-Werror=deprecated-declarations]
>>   klog_table = json_object_object_get(klog_objs, table);
>>   ^~~~~~~~~~
>> In file included from /usr/include/json-c/linkhash.h:16:0,
>>                  from /usr/include/json-c/json.h:22,
>>                  from kernelscan.c:28:
>> /usr/include/json-c/json_object.h:290:56: note: declared here
>>  THIS_FUNCTION_IS_DEPRECATED(extern struct json_object*
>> json_object_object_get(struct json_object* obj,
>>                                                         ^
>> /usr/include/json-c/json_object.h:17:43: note: in definition of macro
>> ‘THIS_FUNCTION_IS_DEPRECATED’
>>  #define THIS_FUNCTION_IS_DEPRECATED(func) func __attribute__ ((deprecated))
>>                                            ^~~~
>> kernelscan.c:401:3: error: ‘json_object_object_get’ is deprecated
>> [-Werror=deprecated-declarations]
>>    str = (char*)json_object_get_string(json_object_object_get(obj,
>> "compare_mode"));
>>    ^~~
>> In file included from /usr/include/json-c/linkhash.h:16:0,
>>                  from /usr/include/json-c/json.h:22,
>>                  from kernelscan.c:28:
>> /usr/include/json-c/json_object.h:290:56: note: declared here
>>  THIS_FUNCTION_IS_DEPRECATED(extern struct json_object*
>> json_object_object_get(struct json_object* obj,
>>                                                         ^
>> /usr/include/json-c/json_object.h:17:43: note: in definition of macro
>> ‘THIS_FUNCTION_IS_DEPRECATED’
>>  #define THIS_FUNCTION_IS_DEPRECATED(func) func __attribute__ ((deprecated))
>>                                            ^~~~
>> kernelscan.c:416:3: error: ‘json_object_object_get’ is deprecated
>> [-Werror=deprecated-declarations]
>>    str = (char*)json_object_get_string(json_object_object_get(obj,
>> "pattern"));
>>    ^~~
>> In file included from /usr/include/json-c/linkhash.h:16:0,
>>                  from /usr/include/json-c/json.h:22,
>>                  from kernelscan.c:28:
>> /usr/include/json-c/json_object.h:290:56: note: declared here
>>  THIS_FUNCTION_IS_DEPRECATED(extern struct json_object*
>> json_object_object_get(struct json_object* obj,
>>                                                         ^
>> /usr/include/json-c/json_object.h:17:43: note: in definition of macro
>> ‘THIS_FUNCTION_IS_DEPRECATED’
>>  #define THIS_FUNCTION_IS_DEPRECATED(func) func __attribute__ ((deprecated))
>>                                            ^~~~
>>
>> Ivan
>>
>> On 8/17/20 6:22 PM, Colin King wrote:
>>> From: Colin Ian King <colin.king@canonical.com>
>>>
>>> FWTS uses a subset of json-c functionality, so replace it with
>>> our own implementation that supports this subset. This also
>>> removes the dependency of two flavours of json libraries that
>>> fwts has been using and also allows us to perform deeper memory
>>> allocation and leaking tracking with static analysis tools.
>>>
>>> Signed-off-by: Colin Ian King <colin.king@canonical.com>
>>> ---
>>>  configure.ac                |   3 -
>>>  src/lib/include/fwts.h      |   2 +
>>>  src/lib/include/fwts_json.h |  61 ++-
>>>  src/lib/src/Makefile.am     |   1 +
>>>  src/lib/src/fwts_json.c     | 917 ++++++++++++++++++++++++++++++++++++
>>>  src/utilities/Makefile.am   |   5 +-
>>>  6 files changed, 969 insertions(+), 20 deletions(-)
>>>  create mode 100644 src/lib/src/fwts_json.c
>>>
>>> diff --git a/configure.ac b/configure.ac
>>> index 39a445cd..f40c3678 100644
>>> --- a/configure.ac
>>> +++ b/configure.ac
>>> @@ -9,8 +9,6 @@
>>>  	  AC_PROG_LIBTOOL
>>>  	  AC_C_INLINE
>>>  	  AM_PROG_CC_C_O
>>> -	  AC_SEARCH_LIBS([json_object_from_file], [json json-c], [], [ AC_MSG_ERROR([no available json library]) ])
>>> -	  AC_SEARCH_LIBS([json_object_object_get_ex], [json json-c], [ AC_DEFINE([JSON_HAS_GET_EX], [1], [Define if we have json_object_object_get_ex])], [])
>>>    	  AC_CHECK_FUNCS([localtime_r])
>>>  	  AC_CHECK_FUNCS([dup2])
>>>  	  AC_CHECK_FUNCS([getcwd])
>>> @@ -61,7 +59,6 @@
>>>  	  AC_CHECK_HEADERS([time.h])
>>>  	  AC_CHECK_HEADERS([sys/ioctl.h])
>>>  	  AC_CHECK_HEADERS([sys/time.h])
>>> -	  AC_CHECK_HEADERS([json/json.h])
>>>  	  AC_CHECK_HEADERS([glib.h])
>>>  	  AC_CHECK_HEADERS([gio/gio.h])
>>>  	  AC_CHECK_HEADERS([asm/opal-prd.h])
>>> diff --git a/src/lib/include/fwts.h b/src/lib/include/fwts.h
>>> index 1e0d5870..6f13d262 100644
>>> --- a/src/lib/include/fwts.h
>>> +++ b/src/lib/include/fwts.h
>>> @@ -153,6 +153,8 @@
>>>  
>>>  #define FWTS_JSON_DATA_PATH	DATAROOTDIR "/fwts"
>>>  
>>> +#include <inttypes.h>
>>> +
>>>  #include "fwts_version.h"
>>>  #include "fwts_backtrace.h"
>>>  #include "fwts_types.h"
>>> diff --git a/src/lib/include/fwts_json.h b/src/lib/include/fwts_json.h
>>> index ad51bc45..0c316e02 100644
>>> --- a/src/lib/include/fwts_json.h
>>> +++ b/src/lib/include/fwts_json.h
>>> @@ -1,5 +1,5 @@
>>>  /*
>>> - * Copyright (C) 2012-2020 Canonical
>>> + * Copyright (C) 2010-2020 Canonical
>>>   *
>>>   * This program is free software; you can redistribute it and/or
>>>   * modify it under the terms of the GNU General Public License
>>> @@ -16,26 +16,15 @@
>>>   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
>>>   *
>>>   */
>>> -
>>>  #ifndef __FWTS_JSON_H__
>>>  #define __FWTS_JSON_H__
>>>  
>>> -#include <json.h>
>>> -
>>> -#define __FWTS_JSON_ERR_PTR__ ((json_object*) -1)
>>>  /*
>>> - *  Older versions of json-c may return an error in an
>>> - *  object as a ((json_object*)-1), where as newer
>>> - *  versions return NULL, so check for these. Sigh.
>>> + *  Minimal subset of json for fwts
>>>   */
>>> -#define FWTS_JSON_ERROR(ptr) \
>>> -	( (ptr == NULL) || ((const json_object *)ptr == __FWTS_JSON_ERR_PTR__) )
>>>  
>>> -/*
>>> - * json-c 0.13.99 does not define TRUE/FALSE anymore
>>> - * the json-c maintainers replaced them with pure 1/0
>>> - * https://github.com/json-c/json-c/commit/0992aac61f8b
>>> - */
>>> +#define FWTS_JSON_ERROR(ptr) 	(!ptr)
>>> +
>>>  #ifndef FALSE
>>>  #define FALSE 0
>>>  #endif
>>> @@ -44,4 +33,46 @@
>>>  #define TRUE  1
>>>  #endif
>>>  
>>> +/*
>>> + *  json types supported
>>> + */
>>> +typedef enum {
>>> +	type_null,
>>> +	type_int,
>>> +	type_string,
>>> +	type_object,
>>> +	type_array,
>>> +} json_type;
>>> +
>>> +/*
>>> + *  json object information
>>> + */
>>> +typedef struct json_object {
>>> +	char *key;		/* Null if undefined */
>>> +	int length;		/* Length of a collection of objects */
>>> +	json_type type;		/* Object type */
>>> +        union {
>>> +                void *ptr;	/* string or object array pointer */
>>> +                int  intval;	/* integer value */
>>> +        } u;
>>> +} json_object;
>>> +
>>> +/*
>>> + *  minimal json c library functions as required by fwts
>>> + */
>>> +json_object *json_object_from_file(const char *filename);
>>> +json_object *json_object_object_get(json_object *obj, const char *key);
>>> +int json_object_array_length(json_object *obj);
>>> +json_object *json_object_array_get_idx(json_object *obj, int index);
>>> +const char *json_object_get_string(json_object *obj);
>>> +json_object *json_object_new_int(int);
>>> +void json_object_object_add(json_object *obj, const char *key, json_object *value);
>>> +
>>> +json_object *json_object_new_object(void);
>>> +json_object *json_object_new_array(void);
>>> +char *json_object_to_json_string(json_object *obj);
>>> +void json_object_put(json_object *obj);
>>> +json_object *json_object_new_string(const char *str);
>>> +int json_object_array_add(json_object *obj, json_object *item);
>>> +
>>>  #endif
>>> diff --git a/src/lib/src/Makefile.am b/src/lib/src/Makefile.am
>>> index ecc4136b..4593bb82 100644
>>> --- a/src/lib/src/Makefile.am
>>> +++ b/src/lib/src/Makefile.am
>>> @@ -82,6 +82,7 @@ libfwts_la_SOURCES = 		\
>>>  	fwts_interactive.c 	\
>>>  	fwts_ioport.c		\
>>>  	fwts_ipmi.c		\
>>> +	fwts_json.c		\
>>>  	fwts_keymap.c 		\
>>>  	fwts_klog.c 		\
>>>  	fwts_olog.c		\
>>> diff --git a/src/lib/src/fwts_json.c b/src/lib/src/fwts_json.c
>>> new file mode 100644
>>> index 00000000..b92a241a
>>> --- /dev/null
>>> +++ b/src/lib/src/fwts_json.c
>>> @@ -0,0 +1,917 @@
>>> +/*
>>> + * Copyright (C) 2010-2020 Canonical
>>> + *
>>> + * This program is free software; you can redistribute it and/or
>>> + * modify it under the terms of the GNU General Public License
>>> + * as published by the Free Software Foundation; either version 2
>>> + * of the License, or (at your option) any later version.
>>> + *
>>> + * This program is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> + * GNU General Public License for more details.
>>> + *
>>> + * You should have received a copy of the GNU General Public License
>>> + * along with this program; if not, write to the Free Software
>>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
>>> + *
>>> + * This is a simplified json parser and json object store
>>> + * based on json but does not support keywords and is designed
>>> + * just for the fwts json data files. It is not a full json
>>> + * implementation and should not be used as such.
>>> + *
>>> + */
>>> +#include <stdlib.h>
>>> +#include <stdio.h>
>>> +#include <stdarg.h>
>>> +#include <stdbool.h>
>>> +#include <string.h>
>>> +#include <unistd.h>
>>> +#include <ctype.h>
>>> +
>>> +#include "fwts.h"
>>> +
>>> +/*
>>> + *  json file information
>>> + */
>>> +typedef struct {
>>> +	FILE *fp;		/* File pointer */
>>> +	const char *filename;	/* Name of file */
>>> +	int linenum;		/* Parser line number */
>>> +	int charnum;		/* Parser char position */
>>> +	int error_reported;	/* Error count */
>>> +} json_file;
>>> +
>>> +/*
>>> + *  json tokens, subset of full json token set as used
>>> + *  for fwts requirements
>>> + */
>>> +typedef enum {
>>> +	token_lbrace,
>>> +	token_rbrace,
>>> +	token_lbracket,
>>> +	token_rbracket,
>>> +	token_colon,
>>> +	token_comma,
>>> +	token_int,
>>> +	token_string,
>>> +	token_true,
>>> +	token_false,
>>> +	token_null,
>>> +	token_error,
>>> +	token_eof,
>>> +} json_token_type;
>>> +
>>> +/*
>>> + *  json parser token
>>> + */
>>> +typedef struct {
>>> +	json_token_type type;	/* token type */
>>> +	long offset;		/* offset in file for re-winding */
>>> +	union {
>>> +		char *str;	/* token string value */
>>> +		int  intval;	/* token integer value */
>>> +	} u;
>>> +} json_token;
>>> +
>>> +/*
>>> + *  json_token_string()
>>> + *	convert json token to a human readable string
>>> + */
>>> +char *json_token_string(json_token *jtoken)
>>> +{
>>> +	static char tmp[64];
>>> +
>>> +	switch (jtoken->type) {
>>> +	case token_lbrace:
>>> +		return "{";
>>> +	case token_rbrace:
>>> +		return "}";
>>> +	case token_lbracket:
>>> +		return "[";
>>> +	case token_rbracket:
>>> +		return "]";
>>> +	case token_colon:
>>> +		return ":";
>>> +	case token_comma:
>>> +		return ",";
>>> +	case token_int:
>>> +		(void)snprintf(tmp, sizeof(tmp), "%d", jtoken->u.intval);
>>> +		return tmp;
>>> +	case token_string:
>>> +		return jtoken->u.str;
>>> +	case token_error:
>>> +		return "<error>";
>>> +	case token_eof:
>>> +		return "end of file";
>>> +	default:
>>> +		break;
>>> +	}
>>> +	return "<illegal token>";
>>> +}
>>> +
>>> +/*
>>> + *  json_get_string()
>>> + *	parse a literal string
>>> + */
>>> +json_token_type json_get_string(json_file *jfile, json_token *token)
>>> +{
>>> +	char buffer[4096];
>>> +	size_t i = 0;
>>> +
>>> +	for (;;) {
>>> +		int ch;
>>> +
>>> +		ch = fgetc(jfile->fp);
>>> +		jfile->charnum++;
>>> +		if (ch == EOF) {
>>> +			fprintf(stderr, "json_parser: unexpected EOF in literal string\n");
>>> +			token->u.str = NULL;
>>> +			return token_error;
>>> +		}
>>> +
>>> +		if (ch == '\\') {
>>> +			ch = fgetc(jfile->fp);
>>> +			switch (ch) {
>>> +			case '\\':
>>> +			case '"':
>>> +			case '/':
>>> +				break;
>>> +			case 'b':
>>> +				ch = '\b';
>>> +				break;
>>> +			case 'f':
>>> +				ch = '\f';
>>> +				break;
>>> +			case 'n':
>>> +				ch = '\n';
>>> +				break;
>>> +			case 'r':
>>> +				ch = '\r';
>>> +				break;
>>> +			case 't':
>>> +				ch = '\t';
>>> +				break;
>>> +			case 'u':
>>> +				fprintf(stderr, "json parser: escaped hex values not supported\n");
>>> +				ch = '?';
>>> +				break;
>>> +			}
>>> +			jfile->charnum++;
>>> +		} else if (ch == '"') {
>>> +			buffer[i] = '\0';
>>> +			token->u.str = strdup(buffer);
>>> +			if (!token->u.str) {
>>> +				fprintf(stderr, "json parser: out of memory allocating %zd byte string\n", i);
>>> +				break;
>>> +			}
>>> +			return token_string;
>>> +		}
>>> +		buffer[i] = ch;
>>> +		i++;
>>> +		if (i >= sizeof(buffer)) {
>>> +			fprintf(stderr, "json parser: string too long, maximum size %zd bytes\n", sizeof(buffer) - 1);
>>> +			break;
>>> +		}
>>> +	}
>>> +
>>> +	token->u.str = NULL;
>>> +	return token_error;
>>> +}
>>> +
>>> +/*
>>> + *  json_get_int()
>>> + *	parse a simple integer
>>> + */
>>> +json_token_type json_get_int(json_file *jfile, json_token *token)
>>> +{
>>> +	char buffer[64];
>>> +	size_t i = 0;
>>> +
>>> +	for (;;) {
>>> +		int ch;
>>> +
>>> +		ch = fgetc(jfile->fp);
>>> +		if (!isdigit(ch)) {
>>> +			(void)ungetc(ch, jfile->fp);
>>> +			buffer[i] = '\0';
>>> +			token->u.intval = atoi(buffer);
>>> +			return token_int;
>>> +		}
>>> +		jfile->charnum++;
>>> +		buffer[i] = ch;
>>> +		i++;
>>> +		if (i >= sizeof(buffer)) {
>>> +			fprintf(stderr, "json parser: integer too long, maximum size %zd bytes\n", sizeof(buffer) - 1);
>>> +			break;
>>> +		}
>>> +	}
>>> +
>>> +	token->u.str = NULL;
>>> +	return token_error;
>>> +}
>>> +
>>> +/*
>>> + *  json_unget_token()
>>> + *  	push file pointer back to point before the token
>>> + *	to unpush the token
>>> + */
>>> +int json_unget_token(json_file *jfile, json_token *token)
>>> +{
>>> +	return fseek(jfile->fp, token->offset, SEEK_SET);
>>> +}
>>> +
>>> +/*
>>> + *  json_get_keyword()
>>> + *	get a keyword
>>> + */
>>> +int json_get_keyword(json_file *jfile, json_token *token)
>>> +{
>>> +	char buffer[32];
>>> +	size_t i = 0;
>>> +
>>> +	token->u.str = NULL;
>>> +	*buffer = '\0';
>>> +
>>> +	for (;;) {
>>> +		int ch;
>>> +
>>> +		ch = fgetc(jfile->fp);
>>> +		jfile->charnum++;
>>> +		if (ch == EOF) {
>>> +			fprintf(stderr, "json_parser: unexpected EOF in keyword string\n");
>>> +			return token_error;
>>> +		}
>>> +		if (ch < 'a' || ch > 'z')
>>> +			break;
>>> +
>>> +		buffer[i] = ch;
>>> +		i++;
>>> +		if (i >= sizeof(buffer)) {
>>> +			fprintf(stderr, "json parser: keyword too long, maximum size %zd bytes\n", sizeof(buffer) - 1);
>>> +			return token_error;
>>> +		}
>>> +	}
>>> +	if (!strcmp(buffer, "true"))
>>> +		return token_true;
>>> +	if (!strcmp(buffer, "false"))
>>> +		return token_false;
>>> +	if (!strcmp(buffer, "null"))
>>> +		return token_null;
>>> +	return token_error;
>>> +}
>>> +
>>> +/*
>>> + *  json_get_token()
>>> + *	read next input character(s) and return a matching token
>>> + */
>>> +json_token_type json_get_token(json_file *jfile, json_token *token)
>>> +{
>>> +	(void)memset(token, 0, sizeof(*token));
>>> +
>>> +	token->offset = ftell(jfile->fp);
>>> +	for (;;) {
>>> +		int ch;
>>> +
>>> +		ch = fgetc(jfile->fp);
>>> +		jfile->charnum++;
>>> +
>>> +		switch (ch) {
>>> +		case '\n':
>>> +			jfile->linenum++;
>>> +			continue;
>>> +		case ' ':
>>> +		case '\r':
>>> +		case '\t':
>>> +			continue;
>>> +		case EOF:
>>> +			token->type = token_eof;
>>> +			return token->type;
>>> +		case '{':
>>> +			token->type = token_lbrace;
>>> +			return token->type;
>>> +		case '}':
>>> +			token->type = token_rbrace;
>>> +			return token->type;
>>> +		case '[':
>>> +			token->type = token_lbracket;
>>> +			return token->type;
>>> +		case ']':
>>> +			token->type = token_rbracket;
>>> +			return token->type;
>>> +		case ':':
>>> +			token->type = token_colon;
>>> +			return token->type;
>>> +		case ',':
>>> +			token->type = token_comma;
>>> +			return token->type;
>>> +		case '"':
>>> +			token->type = json_get_string(jfile, token);
>>> +			return token->type;
>>> +		case '0'...'9':
>>> +			token->type = json_get_int(jfile, token);
>>> +			return token->type;
>>> +		case 'a'...'z':
>>> +			fprintf(stderr, "json_parser: keywords not supported\n");
>>> +			token->type = token_error;
>>> +			return token->type;
>>> +		default:
>>> +			token->type = token_error;
>>> +			return token->type;
>>> +		}
>>> +	}
>>> +
>>> +	/* Should never reach here */
>>> +	token->type = token_error;
>>> +	return token->type;
>>> +}
>>> +
>>> +/*
>>> + *  json_parse_error_where()
>>> + *	very simple parser error message, report where in the file
>>> + *	the parsing error occurred.
>>> + */
>>> +void json_parse_error_where(json_file *jfile)
>>> +{
>>> +	if (jfile->error_reported == 0)
>>> +		fprintf(stderr, "json_parser: aborted at line %d, char %d of file %s\n",
>>> +			jfile->linenum, jfile->charnum, jfile->filename);
>>> +	jfile->error_reported++;
>>> +}
>>> +
>>> +json_object *json_parse_object(json_file *jfile);
>>> +
>>> +/*
>>> + *  json_parse_array()
>>> + *	parse a json array
>>> + */
>>> +json_object *json_parse_array(json_file *jfile)
>>> +{
>>> +	json_object *array_obj;
>>> +
>>> +	array_obj = json_object_new_array();
>>> +	if (!array_obj) {
>>> +		fprintf(stderr, "json_parser: out of memory allocating a json array object\n");
>>> +		json_parse_error_where(jfile);
>>> +		return NULL;
>>> +	}
>>> +
>>> +	for (;;) {
>>> +		json_object *obj;
>>> +		json_token token;
>>> +
>>> +		obj = json_parse_object(jfile);
>>> +		if (!obj) {
>>> +			json_parse_error_where(jfile);
>>> +			free(array_obj);
>>> +			return NULL;
>>> +		}
>>> +		json_object_array_add(array_obj, obj);
>>> +
>>> +		switch (json_get_token(jfile, &token)) {
>>> +		case token_rbracket:
>>> +			return array_obj;
>>> +		case token_comma:
>>> +			continue;
>>> +		default:
>>> +			if (json_unget_token(jfile, &token) != 0) {
>>> +				fprintf(stderr, "json_parser: failed to unget a token\n");
>>> +				free(array_obj);
>>> +				return NULL;
>>> +			}
>>> +			break;
>>> +		}
>>> +	}
>>> +	return array_obj;
>>> +}
>>> +
>>> +/*
>>> + *  json_parse_object()
>>> + *	parse a json object (simplified fwts json format only)
>>> + */
>>> +json_object *json_parse_object(json_file *jfile)
>>> +{
>>> +	json_token token;
>>> +	json_object *obj, *val_obj;
>>> +	char *key = NULL;
>>> +
>>> +	if (json_get_token(jfile, &token) != token_lbrace) {
>>> +		fprintf(stderr, "json_parser: expecting '{', got %s instead\n", json_token_string(&token));
>>> +		return NULL;
>>> +	}
>>> +
>>> +	obj = json_object_new_object();
>>> +	if (!obj)
>>> +		goto err_nomem;
>>> +
>>> +	for (;;) {
>>> +		switch (json_get_token(jfile, &token)) {
>>> +		case token_rbrace:
>>> +			return obj;
>>> +		case token_string:
>>> +			key = token.u.str;
>>> +			if (!key)
>>> +				goto err_nomem;
>>> +			token.u.str = NULL;
>>> +			break;
>>> +		default:
>>> +			fprintf(stderr, "json_parser: expecting } or key literal string, got %s instead\n", json_token_string(&token));
>>> +			goto err_free;
>>> +		}
>>> +		if (json_get_token(jfile, &token) != token_colon) {
>>> +			fprintf(stderr, "json_parser: expecting ':', got %s instead\n", json_token_string(&token));
>>> +			goto err_free;
>>> +		}
>>> +		switch (json_get_token(jfile, &token)) {
>>> +		case token_string:
>>> +			val_obj = json_object_new_string(token.u.str);
>>> +			if (!val_obj)
>>> +				goto err_nomem;
>>> +			json_object_object_add(obj, key, val_obj);
>>> +			free(key);
>>> +			break;
>>> +		case token_int:
>>> +			val_obj = json_object_new_int(token.u.intval);
>>> +			if (!val_obj)
>>> +				goto err_nomem;
>>> +			json_object_object_add(obj, key, val_obj);
>>> +			free(key);
>>> +			break;
>>> +		case token_lbracket:
>>> +			val_obj = json_parse_array(jfile);
>>> +			if (!val_obj)
>>> +				goto err_nomem;
>>> +			json_object_object_add(obj, key, val_obj);
>>> +			break;
>>> +		case token_lbrace:
>>> +			fprintf(stderr, "json_parser: nested objects not supported\n");
>>> +			goto err_free;
>>> +		case token_true:
>>> +		case token_false:
>>> +		case token_null:
>>> +			fprintf(stderr, "json_parser: tokens %s not supported\n", json_token_string(&token));
>>> +			goto err_free;
>>> +		default:
>>> +			fprintf(stderr, "json_parser: unexpected token %s\n", json_token_string(&token));
>>> +		}
>>> +		switch (json_get_token(jfile, &token)) {
>>> +		case token_comma:
>>> +			continue;
>>> +		case token_rbrace:
>>> +			return obj;
>>> +		default:
>>> +			fprintf(stderr, "json_parser: expected , or }, got %s instead\n", json_token_string(&token));
>>> +			goto err_free;
>>> +		}
>>> +	}
>>> +
>>> +err_nomem:
>>> +	fprintf(stderr, "json_parser: out of memory allocating a json object\n");
>>> +	json_parse_error_where(jfile);
>>> +err_free:
>>> +	free(obj);
>>> +	return NULL;
>>> +}
>>> +
>>> +/*
>>> + *  json_object_from_file()
>>> + *	parse a simplified fwts json file and convert it into
>>> + *	a json object, return NULL if parsing failed or ran
>>> + *	out of memory
>>> + */
>>> +json_object *json_object_from_file(const char *filename)
>>> +{
>>> +	json_object *obj;
>>> +	json_file jfile;
>>> +
>>> +	jfile.filename = filename;
>>> +	jfile.linenum = 1;
>>> +	jfile.charnum = 0;
>>> +	jfile.error_reported = 0;
>>> +
>>> +	jfile.fp = fopen(filename, "r");
>>> +	if (!jfile.fp)
>>> +		return NULL;
>>> +
>>> +	obj = json_parse_object(&jfile);
>>> +
>>> +	fclose(jfile.fp);
>>> +	return obj;
>>> +}
>>> +
>>> +/*
>>> + *  json_object_new_object()
>>> + *	return a new json object, NULL if failed
>>> + */
>>> +json_object *json_object_new_object(void)
>>> +{
>>> +	json_object *obj;
>>> +
>>> +	obj = calloc(1, sizeof(*obj));
>>> +	if (!obj)
>>> +		return NULL;
>>> +	obj->type = type_object;
>>> +	obj->u.ptr = NULL;
>>> +
>>> +	return obj;
>>> +}
>>> +
>>> +/*
>>> + *  json_object_new_object()
>>> + *	return a new json object, NULL if failed
>>> + */
>>> +int json_object_array_length(json_object *obj)
>>> +{
>>> +	if (!obj)
>>> +		return 0;
>>> +	if (obj->type != type_array)
>>> +		return 0;
>>> +	return obj->length;
>>> +}
>>> +
>>> +/*
>>> + *  json_object_new_int()
>>> + *	return a new json integer object, NULL if failed
>>> + */
>>> +json_object *json_object_new_int(int val)
>>> +{
>>> +	json_object *obj;
>>> +
>>> +	obj = calloc(1, sizeof(*obj));
>>> +	if (!obj)
>>> +		return NULL;
>>> +	obj->type = type_int;
>>> +	obj->u.intval = val;
>>> +
>>> +	return obj;
>>> +}
>>> +
>>> +/*
>>> + *  json_object_new_string()
>>> + *	return a new json string object, NULL if failed
>>> + */
>>> +json_object *json_object_new_string(const char *str)
>>> +{
>>> +	json_object *obj;
>>> +
>>> +	obj = calloc(1, sizeof(*obj));
>>> +	if (!obj)
>>> +		return NULL;
>>> +	obj->type = type_string;
>>> +	obj->u.ptr = strdup(str);
>>> +	if (!obj->u.ptr) {
>>> +		free(obj);
>>> +		return NULL;
>>> +	}
>>> +	return obj;
>>> +}
>>> +
>>> +/*
>>> + *  json_object_new_array()
>>> + *	return a new json array object, NULL if failed
>>> + */
>>> +json_object *json_object_new_array(void)
>>> +{
>>> +	json_object *obj;
>>> +
>>> +	obj = calloc(1, sizeof(*obj));
>>> +	if (!obj)
>>> +		return NULL;
>>> +	obj->type = type_array;
>>> +	obj->length = 0;
>>> +	obj->u.ptr = NULL;
>>> +
>>> +	return obj;
>>> +}
>>> +
>>> +/*
>>> + *  json_object_array_add_item()
>>> + *	add an object to another object, return 0 if succeeded,
>>> + *	non-zero if failed
>>> + */
>>> +static int json_object_array_add_item(json_object *obj, json_object *item)
>>> +{
>>> +	json_object **obj_ptr;
>>> +
>>> +	if (obj->length < 0)
>>> +		return -1;
>>> +	obj_ptr = realloc(obj->u.ptr, sizeof(json_object *) * (obj->length + 1));
>>> +	if (!obj_ptr)
>>> +		return -1;
>>> +	obj->u.ptr = (void *)obj_ptr;
>>> +	obj_ptr[obj->length] = item;
>>> +	obj->length++;
>>> +	return 0;
>>> +}
>>> +
>>> +/*
>>> + *  json_object_array_add()
>>> + *	add a object to a json array object, return NULL if failed
>>> + */
>>> +int json_object_array_add(json_object *obj, json_object *item)
>>> +{
>>> +	if (!obj || !item)
>>> +		return -1;
>>> +	if (obj->type != type_array)
>>> +		return -1;
>>> +	return json_object_array_add_item(obj, item);
>>> +}
>>> +
>>> +
>>> +/*
>>> + *  json_object_object_add()
>>> + *	add a key/valyue object to a json object, return NULL if failed
>>> + */
>>> +void json_object_object_add(json_object *obj, const char *key, json_object *value)
>>> +{
>>> +	if (!obj || !key || !value)
>>> +		return;
>>> +	if (obj->type != type_object)
>>> +		return;
>>> +	value->key = strdup(key);
>>> +	if (!value->key)
>>> +		return;
>>> +	json_object_array_add_item(obj, value);
>>> +}
>>> +
>>> +/*
>>> + *  json_object_array_get_idx()
>>> + *	get an object at position index from a json array object,
>>> + *	return NULL if failed
>>> + */
>>> +json_object *json_object_array_get_idx(json_object *obj, int index)
>>> +{
>>> +	json_object **obj_array;
>>> +
>>> +	if (!obj)
>>> +		return NULL;
>>> +	if (obj->type != type_array)
>>> +		return NULL;
>>> +	if (index >= obj->length)
>>> +		return NULL;
>>> +	obj_array = (json_object **)obj->u.ptr;
>>> +	if (obj_array == NULL)
>>> +		return NULL;
>>> +	return obj_array[index];
>>> +}
>>> +
>>> +/*
>>> + *  json_object_get_string()
>>> + *	return a C string from a json string object
>>> + */
>>> +const char *json_object_get_string(json_object *obj)
>>> +{
>>> +	if (!obj)
>>> +		return NULL;
>>> +	if (obj->type != type_string)
>>> +		return NULL;
>>> +	return (const char *)obj->u.ptr;
>>> +}
>>> +
>>> +/*
>>> + *  json_object_put()
>>> + *	free a json object and all sub-objects
>>> + */
>>> +void json_object_put(json_object *obj)
>>> +{
>>> +	int i;
>>> +	json_object **obj_ptr;
>>> +
>>> +	if (!obj)
>>> +		return;
>>> +
>>> +	if (obj->key)
>>> +		free(obj->key);
>>> +
>>> +	switch (obj->type) {
>>> +	case type_array:
>>> +	case type_object:
>>> +		obj_ptr = (json_object **)obj->u.ptr;
>>> +
>>> +		for (i = 0; i < obj->length; i++) {
>>> +			json_object_put(obj_ptr[i]);
>>> +		}
>>> +		free(obj->u.ptr);
>>> +		break;
>>> +	case type_string:
>>> +		free(obj->u.ptr);
>>> +		break;
>>> +	case type_null:
>>> +	case type_int:
>>> +	default:
>>> +		break;
>>> +	}
>>> +	free(obj);
>>> +}
>>> +
>>> +/*
>>> + *  str_append()
>>> + *	append a string to a string, return NULL if failed
>>> + */
>>> +static char *str_append(char *str, char *append)
>>> +{
>>> +	char *new_str;
>>> +	size_t len;
>>> +
>>> +	if (!append)
>>> +		return NULL;
>>> +
>>> +	if (str) {
>>> +		len = strlen(append) + strlen(str) + 1;
>>> +		new_str = realloc(str, len);
>>> +		if (!new_str) {
>>> +			free(str);
>>> +			return NULL;
>>> +		}
>>> +		strcat(new_str, append);
>>> +	} else {
>>> +		len = strlen(append) + 1;
>>> +		new_str = malloc(len);
>>> +		if (!new_str)
>>> +			return NULL;
>>> +		strcpy(new_str, append);
>>> +	}
>>> +	return new_str;
>>> +}
>>> +
>>> +/*
>>> + *  str_indent()
>>> + *	add 2 spaces per indent level to a string, returns
>>> + *	NULL if failed
>>> + */
>>> +static char *str_indent(char *str, int indent)
>>> +{
>>> +	char buf[81];
>>> +	int i;
>>> +
>>> +	indent = indent + indent;
>>> +	if (indent > 80)
>>> +		indent = 80;
>>> +
>>> +	for (i = 0; i < indent; i++)
>>> +		buf[i] = ' ';
>>> +	buf[i] = '\0';
>>> +
>>> +	return str_append(str, buf);
>>> +}
>>> +
>>> +/*
>>> + *  json_object_to_json_string_indent()
>>> + *	turn a simplified fwts json object into a C string, returns
>>> + *	the stringified object or NULL if failed. Will traverse object
>>> + *	tree and add indentation based on recursion depth.
>>> + */
>>> +static char *json_object_to_json_string_indent(json_object *obj, int indent)
>>> +{
>>> +	int i;
>>> +	json_object **obj_ptr;
>>> +	char *str = NULL;
>>> +	char buf[64];
>>> +
>>> +	if (!obj)
>>> +		return NULL;
>>> +
>>> +	if (obj->type == type_object) {
>>> +		str = str_indent(str, indent);
>>> +		if (!str)
>>> +			return NULL;
>>> +		str = str_append(str, "{\n");
>>> +		if (!str)
>>> +			return NULL;
>>> +	}
>>> +
>>> +        if (obj->key) {
>>> +		str = str_indent(str, indent);
>>> +		if (!str)
>>> +			return NULL;
>>> +		str = str_append(str, "\"");
>>> +		if (!str)
>>> +			return NULL;
>>> +		str = str_append(str, obj->key);
>>> +		if (!str)
>>> +			return NULL;
>>> +		str = str_append(str, "\":");
>>> +		if (!str)
>>> +			return NULL;
>>> +        }
>>> +
>>> +	switch (obj->type) {
>>> +	case type_array:
>>> +		str = str_append(str, "[\n");
>>> +		if (!str)
>>> +			return NULL;
>>> +
>>> +		obj_ptr = (json_object **)obj->u.ptr;
>>> +		if (obj_ptr) {
>>> +			for (i = 0; i < obj->length; i++) {
>>> +				char *obj_str = json_object_to_json_string_indent(obj_ptr[i], indent + 1);
>>> +
>>> +				if (!obj_str) {
>>> +					free(str);
>>> +					return NULL;
>>> +				}
>>> +				str = str_append(str, obj_str);
>>> +				if (!str)
>>> +					return NULL;
>>> +			}
>>> +		}
>>> +		str = str_append(str, "\n");
>>> +		if (!str)
>>> +			return NULL;
>>> +		str = str_indent(str, indent);
>>> +		if (!str)
>>> +			return NULL;
>>> +		str = str_append(str, "]\n");
>>> +		if (!str)
>>> +			return NULL;
>>> +		break;
>>> +
>>> +	case type_object:
>>> +		obj_ptr = (json_object **)obj->u.ptr;
>>> +		if (obj_ptr) {
>>> +			for (i = 0; i < obj->length; i++) {
>>> +				char *obj_str = json_object_to_json_string_indent(obj_ptr[i], indent + 1);
>>> +
>>> +				if (!obj_str)
>>> +					return NULL;
>>> +				str = str_append(str, obj_str);
>>> +				if (!str)
>>> +					return NULL;
>>> +			}
>>> +		}
>>> +		if (!str)
>>> +			return NULL;
>>> +		break;
>>> +
>>> +	case type_string:
>>> +		str = str_append(str, "\"");
>>> +		if (!str)
>>> +			return NULL;
>>> +		str = str_append(str, (char *)obj->u.ptr);
>>> +		if (!str)
>>> +			return NULL;
>>> +		str = str_append(str, "\",\n");
>>> +		if (!str)
>>> +			return NULL;
>>> +		break;
>>> +
>>> +	case type_null:
>>> +		str = str_append(str, "(null)\n");
>>> +		if (!str)
>>> +			return NULL;
>>> +		break;
>>> +
>>> +	case type_int:
>>> +		snprintf(buf, sizeof(buf), "%d,\n", obj->u.intval);
>>> +		str = str_append(str, buf);
>>> +		if (!str)
>>> +			return NULL;
>>> +		break;
>>> +	default:
>>> +		return NULL;
>>> +	}
>>> +
>>> +	if (obj->type == type_object) {
>>> +		str = str_indent(str, indent);
>>> +		if (!str)
>>> +			return NULL;
>>> +		str = str_append(str, "},\n");
>>> +		if (!str)
>>> +			return NULL;
>>> +	}
>>> +	return str;
>>> +}
>>> +
>>> +/*
>>> + *  json_object_to_json_string
>>> + *	convert simplified fwts object to a C string, returns
>>> + *	NULL if failed
>>> + */
>>> +char *json_object_to_json_string(json_object *obj)
>>> +{
>>> +	return json_object_to_json_string_indent(obj, 0);
>>> +}
>>> +
>>> +/*
>>> + *  json_object_object_get()
>>> + *	return value from key/value pair from an object, returns
>>> + *	NULL if it can't be found
>>> + */
>>> +json_object *json_object_object_get(json_object *obj, const char *key)
>>> +{
>>> +	int i;
>>> +	json_object **obj_ptr;
>>> +
>>> +	if (!obj || !key)
>>> +		return NULL;
>>> +	if (obj->type != type_object)
>>> +		return NULL;
>>> +
>>> +	obj_ptr = (json_object **)obj->u.ptr;
>>> +	for (i = 0; i < obj->length; i++) {
>>> +		if (obj_ptr[i]->key && !strcmp(obj_ptr[i]->key, key))
>>> +			return obj_ptr[i];
>>> +	}
>>> +	return NULL;
>>> +}
>>> +
>>> diff --git a/src/utilities/Makefile.am b/src/utilities/Makefile.am
>>> index 98d6ebaa..2ae86038 100644
>>> --- a/src/utilities/Makefile.am
>>> +++ b/src/utilities/Makefile.am
>>> @@ -18,10 +18,11 @@
>>>  
>>>  AM_CPPFLAGS = -Wall -Werror -Wextra -DDATAROOTDIR=\"$(datarootdir)\" \
>>>  	`pkg-config --silence-errors --cflags json` \
>>> -	`pkg-config --silence-errors --cflags json-c`
>>> +	`pkg-config --silence-errors --cflags json-c` \
>>> +	-I../lib/include
>>>  
>>>  bin_PROGRAMS = kernelscan
>>> -kernelscan_SOURCES = kernelscan.c
>>> +kernelscan_SOURCES = kernelscan.c ../lib/src/fwts_json.c
>>>  
>>>  
>>>  -include $(top_srcdir)/git.mk
>>>
> 
> 

I did a test build on PPA but got failures, ex.
https://launchpad.net/~firmware-testing-team/+archive/ubuntu/scratch/+build/19860987
Colin Ian King Aug. 21, 2020, 7:20 p.m. UTC | #4
On 21/08/2020 20:17, Alex Hung wrote:
> On 2020-08-21 4:43 a.m., Colin Ian King wrote:
>> On 21/08/2020 11:35, ivanhu wrote:
>>> Got build error blow, seems kernelscan.c still hasn't used these functions.
>>> #include <json.h> in kernelscan.c
>>
>> Hrm, it works for me with a clean clone and applying the patches. Did
>> you work from a fresh autoconfig. e.g.:
>>
>> autoreconf -ivf
>> ./configure
>> make
>>
>> Colin
>>
>>
>>>
>>> kernelscan.c: In function ‘klog_load’:
>>> kernelscan.c:365:2: error: ‘json_object_object_get’ is deprecated
>>> [-Werror=deprecated-declarations]
>>>   klog_table = json_object_object_get(klog_objs, table);
>>>   ^~~~~~~~~~
>>> In file included from /usr/include/json-c/linkhash.h:16:0,
>>>                  from /usr/include/json-c/json.h:22,
>>>                  from kernelscan.c:28:
>>> /usr/include/json-c/json_object.h:290:56: note: declared here
>>>  THIS_FUNCTION_IS_DEPRECATED(extern struct json_object*
>>> json_object_object_get(struct json_object* obj,
>>>                                                         ^
>>> /usr/include/json-c/json_object.h:17:43: note: in definition of macro
>>> ‘THIS_FUNCTION_IS_DEPRECATED’
>>>  #define THIS_FUNCTION_IS_DEPRECATED(func) func __attribute__ ((deprecated))
>>>                                            ^~~~
>>> kernelscan.c:401:3: error: ‘json_object_object_get’ is deprecated
>>> [-Werror=deprecated-declarations]
>>>    str = (char*)json_object_get_string(json_object_object_get(obj,
>>> "compare_mode"));
>>>    ^~~
>>> In file included from /usr/include/json-c/linkhash.h:16:0,
>>>                  from /usr/include/json-c/json.h:22,
>>>                  from kernelscan.c:28:
>>> /usr/include/json-c/json_object.h:290:56: note: declared here
>>>  THIS_FUNCTION_IS_DEPRECATED(extern struct json_object*
>>> json_object_object_get(struct json_object* obj,
>>>                                                         ^
>>> /usr/include/json-c/json_object.h:17:43: note: in definition of macro
>>> ‘THIS_FUNCTION_IS_DEPRECATED’
>>>  #define THIS_FUNCTION_IS_DEPRECATED(func) func __attribute__ ((deprecated))
>>>                                            ^~~~
>>> kernelscan.c:416:3: error: ‘json_object_object_get’ is deprecated
>>> [-Werror=deprecated-declarations]
>>>    str = (char*)json_object_get_string(json_object_object_get(obj,
>>> "pattern"));
>>>    ^~~
>>> In file included from /usr/include/json-c/linkhash.h:16:0,
>>>                  from /usr/include/json-c/json.h:22,
>>>                  from kernelscan.c:28:
>>> /usr/include/json-c/json_object.h:290:56: note: declared here
>>>  THIS_FUNCTION_IS_DEPRECATED(extern struct json_object*
>>> json_object_object_get(struct json_object* obj,
>>>                                                         ^
>>> /usr/include/json-c/json_object.h:17:43: note: in definition of macro
>>> ‘THIS_FUNCTION_IS_DEPRECATED’
>>>  #define THIS_FUNCTION_IS_DEPRECATED(func) func __attribute__ ((deprecated))
>>>                                            ^~~~
>>>
>>> Ivan
>>>
>>> On 8/17/20 6:22 PM, Colin King wrote:
>>>> From: Colin Ian King <colin.king@canonical.com>
>>>>
>>>> FWTS uses a subset of json-c functionality, so replace it with
>>>> our own implementation that supports this subset. This also
>>>> removes the dependency of two flavours of json libraries that
>>>> fwts has been using and also allows us to perform deeper memory
>>>> allocation and leaking tracking with static analysis tools.
>>>>
>>>> Signed-off-by: Colin Ian King <colin.king@canonical.com>
>>>> ---
>>>>  configure.ac                |   3 -
>>>>  src/lib/include/fwts.h      |   2 +
>>>>  src/lib/include/fwts_json.h |  61 ++-
>>>>  src/lib/src/Makefile.am     |   1 +
>>>>  src/lib/src/fwts_json.c     | 917 ++++++++++++++++++++++++++++++++++++
>>>>  src/utilities/Makefile.am   |   5 +-
>>>>  6 files changed, 969 insertions(+), 20 deletions(-)
>>>>  create mode 100644 src/lib/src/fwts_json.c
>>>>
>>>> diff --git a/configure.ac b/configure.ac
>>>> index 39a445cd..f40c3678 100644
>>>> --- a/configure.ac
>>>> +++ b/configure.ac
>>>> @@ -9,8 +9,6 @@
>>>>  	  AC_PROG_LIBTOOL
>>>>  	  AC_C_INLINE
>>>>  	  AM_PROG_CC_C_O
>>>> -	  AC_SEARCH_LIBS([json_object_from_file], [json json-c], [], [ AC_MSG_ERROR([no available json library]) ])
>>>> -	  AC_SEARCH_LIBS([json_object_object_get_ex], [json json-c], [ AC_DEFINE([JSON_HAS_GET_EX], [1], [Define if we have json_object_object_get_ex])], [])
>>>>    	  AC_CHECK_FUNCS([localtime_r])
>>>>  	  AC_CHECK_FUNCS([dup2])
>>>>  	  AC_CHECK_FUNCS([getcwd])
>>>> @@ -61,7 +59,6 @@
>>>>  	  AC_CHECK_HEADERS([time.h])
>>>>  	  AC_CHECK_HEADERS([sys/ioctl.h])
>>>>  	  AC_CHECK_HEADERS([sys/time.h])
>>>> -	  AC_CHECK_HEADERS([json/json.h])
>>>>  	  AC_CHECK_HEADERS([glib.h])
>>>>  	  AC_CHECK_HEADERS([gio/gio.h])
>>>>  	  AC_CHECK_HEADERS([asm/opal-prd.h])
>>>> diff --git a/src/lib/include/fwts.h b/src/lib/include/fwts.h
>>>> index 1e0d5870..6f13d262 100644
>>>> --- a/src/lib/include/fwts.h
>>>> +++ b/src/lib/include/fwts.h
>>>> @@ -153,6 +153,8 @@
>>>>  
>>>>  #define FWTS_JSON_DATA_PATH	DATAROOTDIR "/fwts"
>>>>  
>>>> +#include <inttypes.h>
>>>> +
>>>>  #include "fwts_version.h"
>>>>  #include "fwts_backtrace.h"
>>>>  #include "fwts_types.h"
>>>> diff --git a/src/lib/include/fwts_json.h b/src/lib/include/fwts_json.h
>>>> index ad51bc45..0c316e02 100644
>>>> --- a/src/lib/include/fwts_json.h
>>>> +++ b/src/lib/include/fwts_json.h
>>>> @@ -1,5 +1,5 @@
>>>>  /*
>>>> - * Copyright (C) 2012-2020 Canonical
>>>> + * Copyright (C) 2010-2020 Canonical
>>>>   *
>>>>   * This program is free software; you can redistribute it and/or
>>>>   * modify it under the terms of the GNU General Public License
>>>> @@ -16,26 +16,15 @@
>>>>   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
>>>>   *
>>>>   */
>>>> -
>>>>  #ifndef __FWTS_JSON_H__
>>>>  #define __FWTS_JSON_H__
>>>>  
>>>> -#include <json.h>
>>>> -
>>>> -#define __FWTS_JSON_ERR_PTR__ ((json_object*) -1)
>>>>  /*
>>>> - *  Older versions of json-c may return an error in an
>>>> - *  object as a ((json_object*)-1), where as newer
>>>> - *  versions return NULL, so check for these. Sigh.
>>>> + *  Minimal subset of json for fwts
>>>>   */
>>>> -#define FWTS_JSON_ERROR(ptr) \
>>>> -	( (ptr == NULL) || ((const json_object *)ptr == __FWTS_JSON_ERR_PTR__) )
>>>>  
>>>> -/*
>>>> - * json-c 0.13.99 does not define TRUE/FALSE anymore
>>>> - * the json-c maintainers replaced them with pure 1/0
>>>> - * https://github.com/json-c/json-c/commit/0992aac61f8b
>>>> - */
>>>> +#define FWTS_JSON_ERROR(ptr) 	(!ptr)
>>>> +
>>>>  #ifndef FALSE
>>>>  #define FALSE 0
>>>>  #endif
>>>> @@ -44,4 +33,46 @@
>>>>  #define TRUE  1
>>>>  #endif
>>>>  
>>>> +/*
>>>> + *  json types supported
>>>> + */
>>>> +typedef enum {
>>>> +	type_null,
>>>> +	type_int,
>>>> +	type_string,
>>>> +	type_object,
>>>> +	type_array,
>>>> +} json_type;
>>>> +
>>>> +/*
>>>> + *  json object information
>>>> + */
>>>> +typedef struct json_object {
>>>> +	char *key;		/* Null if undefined */
>>>> +	int length;		/* Length of a collection of objects */
>>>> +	json_type type;		/* Object type */
>>>> +        union {
>>>> +                void *ptr;	/* string or object array pointer */
>>>> +                int  intval;	/* integer value */
>>>> +        } u;
>>>> +} json_object;
>>>> +
>>>> +/*
>>>> + *  minimal json c library functions as required by fwts
>>>> + */
>>>> +json_object *json_object_from_file(const char *filename);
>>>> +json_object *json_object_object_get(json_object *obj, const char *key);
>>>> +int json_object_array_length(json_object *obj);
>>>> +json_object *json_object_array_get_idx(json_object *obj, int index);
>>>> +const char *json_object_get_string(json_object *obj);
>>>> +json_object *json_object_new_int(int);
>>>> +void json_object_object_add(json_object *obj, const char *key, json_object *value);
>>>> +
>>>> +json_object *json_object_new_object(void);
>>>> +json_object *json_object_new_array(void);
>>>> +char *json_object_to_json_string(json_object *obj);
>>>> +void json_object_put(json_object *obj);
>>>> +json_object *json_object_new_string(const char *str);
>>>> +int json_object_array_add(json_object *obj, json_object *item);
>>>> +
>>>>  #endif
>>>> diff --git a/src/lib/src/Makefile.am b/src/lib/src/Makefile.am
>>>> index ecc4136b..4593bb82 100644
>>>> --- a/src/lib/src/Makefile.am
>>>> +++ b/src/lib/src/Makefile.am
>>>> @@ -82,6 +82,7 @@ libfwts_la_SOURCES = 		\
>>>>  	fwts_interactive.c 	\
>>>>  	fwts_ioport.c		\
>>>>  	fwts_ipmi.c		\
>>>> +	fwts_json.c		\
>>>>  	fwts_keymap.c 		\
>>>>  	fwts_klog.c 		\
>>>>  	fwts_olog.c		\
>>>> diff --git a/src/lib/src/fwts_json.c b/src/lib/src/fwts_json.c
>>>> new file mode 100644
>>>> index 00000000..b92a241a
>>>> --- /dev/null
>>>> +++ b/src/lib/src/fwts_json.c
>>>> @@ -0,0 +1,917 @@
>>>> +/*
>>>> + * Copyright (C) 2010-2020 Canonical
>>>> + *
>>>> + * This program is free software; you can redistribute it and/or
>>>> + * modify it under the terms of the GNU General Public License
>>>> + * as published by the Free Software Foundation; either version 2
>>>> + * of the License, or (at your option) any later version.
>>>> + *
>>>> + * This program is distributed in the hope that it will be useful,
>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>> + * GNU General Public License for more details.
>>>> + *
>>>> + * You should have received a copy of the GNU General Public License
>>>> + * along with this program; if not, write to the Free Software
>>>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
>>>> + *
>>>> + * This is a simplified json parser and json object store
>>>> + * based on json but does not support keywords and is designed
>>>> + * just for the fwts json data files. It is not a full json
>>>> + * implementation and should not be used as such.
>>>> + *
>>>> + */
>>>> +#include <stdlib.h>
>>>> +#include <stdio.h>
>>>> +#include <stdarg.h>
>>>> +#include <stdbool.h>
>>>> +#include <string.h>
>>>> +#include <unistd.h>
>>>> +#include <ctype.h>
>>>> +
>>>> +#include "fwts.h"
>>>> +
>>>> +/*
>>>> + *  json file information
>>>> + */
>>>> +typedef struct {
>>>> +	FILE *fp;		/* File pointer */
>>>> +	const char *filename;	/* Name of file */
>>>> +	int linenum;		/* Parser line number */
>>>> +	int charnum;		/* Parser char position */
>>>> +	int error_reported;	/* Error count */
>>>> +} json_file;
>>>> +
>>>> +/*
>>>> + *  json tokens, subset of full json token set as used
>>>> + *  for fwts requirements
>>>> + */
>>>> +typedef enum {
>>>> +	token_lbrace,
>>>> +	token_rbrace,
>>>> +	token_lbracket,
>>>> +	token_rbracket,
>>>> +	token_colon,
>>>> +	token_comma,
>>>> +	token_int,
>>>> +	token_string,
>>>> +	token_true,
>>>> +	token_false,
>>>> +	token_null,
>>>> +	token_error,
>>>> +	token_eof,
>>>> +} json_token_type;
>>>> +
>>>> +/*
>>>> + *  json parser token
>>>> + */
>>>> +typedef struct {
>>>> +	json_token_type type;	/* token type */
>>>> +	long offset;		/* offset in file for re-winding */
>>>> +	union {
>>>> +		char *str;	/* token string value */
>>>> +		int  intval;	/* token integer value */
>>>> +	} u;
>>>> +} json_token;
>>>> +
>>>> +/*
>>>> + *  json_token_string()
>>>> + *	convert json token to a human readable string
>>>> + */
>>>> +char *json_token_string(json_token *jtoken)
>>>> +{
>>>> +	static char tmp[64];
>>>> +
>>>> +	switch (jtoken->type) {
>>>> +	case token_lbrace:
>>>> +		return "{";
>>>> +	case token_rbrace:
>>>> +		return "}";
>>>> +	case token_lbracket:
>>>> +		return "[";
>>>> +	case token_rbracket:
>>>> +		return "]";
>>>> +	case token_colon:
>>>> +		return ":";
>>>> +	case token_comma:
>>>> +		return ",";
>>>> +	case token_int:
>>>> +		(void)snprintf(tmp, sizeof(tmp), "%d", jtoken->u.intval);
>>>> +		return tmp;
>>>> +	case token_string:
>>>> +		return jtoken->u.str;
>>>> +	case token_error:
>>>> +		return "<error>";
>>>> +	case token_eof:
>>>> +		return "end of file";
>>>> +	default:
>>>> +		break;
>>>> +	}
>>>> +	return "<illegal token>";
>>>> +}
>>>> +
>>>> +/*
>>>> + *  json_get_string()
>>>> + *	parse a literal string
>>>> + */
>>>> +json_token_type json_get_string(json_file *jfile, json_token *token)
>>>> +{
>>>> +	char buffer[4096];
>>>> +	size_t i = 0;
>>>> +
>>>> +	for (;;) {
>>>> +		int ch;
>>>> +
>>>> +		ch = fgetc(jfile->fp);
>>>> +		jfile->charnum++;
>>>> +		if (ch == EOF) {
>>>> +			fprintf(stderr, "json_parser: unexpected EOF in literal string\n");
>>>> +			token->u.str = NULL;
>>>> +			return token_error;
>>>> +		}
>>>> +
>>>> +		if (ch == '\\') {
>>>> +			ch = fgetc(jfile->fp);
>>>> +			switch (ch) {
>>>> +			case '\\':
>>>> +			case '"':
>>>> +			case '/':
>>>> +				break;
>>>> +			case 'b':
>>>> +				ch = '\b';
>>>> +				break;
>>>> +			case 'f':
>>>> +				ch = '\f';
>>>> +				break;
>>>> +			case 'n':
>>>> +				ch = '\n';
>>>> +				break;
>>>> +			case 'r':
>>>> +				ch = '\r';
>>>> +				break;
>>>> +			case 't':
>>>> +				ch = '\t';
>>>> +				break;
>>>> +			case 'u':
>>>> +				fprintf(stderr, "json parser: escaped hex values not supported\n");
>>>> +				ch = '?';
>>>> +				break;
>>>> +			}
>>>> +			jfile->charnum++;
>>>> +		} else if (ch == '"') {
>>>> +			buffer[i] = '\0';
>>>> +			token->u.str = strdup(buffer);
>>>> +			if (!token->u.str) {
>>>> +				fprintf(stderr, "json parser: out of memory allocating %zd byte string\n", i);
>>>> +				break;
>>>> +			}
>>>> +			return token_string;
>>>> +		}
>>>> +		buffer[i] = ch;
>>>> +		i++;
>>>> +		if (i >= sizeof(buffer)) {
>>>> +			fprintf(stderr, "json parser: string too long, maximum size %zd bytes\n", sizeof(buffer) - 1);
>>>> +			break;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	token->u.str = NULL;
>>>> +	return token_error;
>>>> +}
>>>> +
>>>> +/*
>>>> + *  json_get_int()
>>>> + *	parse a simple integer
>>>> + */
>>>> +json_token_type json_get_int(json_file *jfile, json_token *token)
>>>> +{
>>>> +	char buffer[64];
>>>> +	size_t i = 0;
>>>> +
>>>> +	for (;;) {
>>>> +		int ch;
>>>> +
>>>> +		ch = fgetc(jfile->fp);
>>>> +		if (!isdigit(ch)) {
>>>> +			(void)ungetc(ch, jfile->fp);
>>>> +			buffer[i] = '\0';
>>>> +			token->u.intval = atoi(buffer);
>>>> +			return token_int;
>>>> +		}
>>>> +		jfile->charnum++;
>>>> +		buffer[i] = ch;
>>>> +		i++;
>>>> +		if (i >= sizeof(buffer)) {
>>>> +			fprintf(stderr, "json parser: integer too long, maximum size %zd bytes\n", sizeof(buffer) - 1);
>>>> +			break;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	token->u.str = NULL;
>>>> +	return token_error;
>>>> +}
>>>> +
>>>> +/*
>>>> + *  json_unget_token()
>>>> + *  	push file pointer back to point before the token
>>>> + *	to unpush the token
>>>> + */
>>>> +int json_unget_token(json_file *jfile, json_token *token)
>>>> +{
>>>> +	return fseek(jfile->fp, token->offset, SEEK_SET);
>>>> +}
>>>> +
>>>> +/*
>>>> + *  json_get_keyword()
>>>> + *	get a keyword
>>>> + */
>>>> +int json_get_keyword(json_file *jfile, json_token *token)
>>>> +{
>>>> +	char buffer[32];
>>>> +	size_t i = 0;
>>>> +
>>>> +	token->u.str = NULL;
>>>> +	*buffer = '\0';
>>>> +
>>>> +	for (;;) {
>>>> +		int ch;
>>>> +
>>>> +		ch = fgetc(jfile->fp);
>>>> +		jfile->charnum++;
>>>> +		if (ch == EOF) {
>>>> +			fprintf(stderr, "json_parser: unexpected EOF in keyword string\n");
>>>> +			return token_error;
>>>> +		}
>>>> +		if (ch < 'a' || ch > 'z')
>>>> +			break;
>>>> +
>>>> +		buffer[i] = ch;
>>>> +		i++;
>>>> +		if (i >= sizeof(buffer)) {
>>>> +			fprintf(stderr, "json parser: keyword too long, maximum size %zd bytes\n", sizeof(buffer) - 1);
>>>> +			return token_error;
>>>> +		}
>>>> +	}
>>>> +	if (!strcmp(buffer, "true"))
>>>> +		return token_true;
>>>> +	if (!strcmp(buffer, "false"))
>>>> +		return token_false;
>>>> +	if (!strcmp(buffer, "null"))
>>>> +		return token_null;
>>>> +	return token_error;
>>>> +}
>>>> +
>>>> +/*
>>>> + *  json_get_token()
>>>> + *	read next input character(s) and return a matching token
>>>> + */
>>>> +json_token_type json_get_token(json_file *jfile, json_token *token)
>>>> +{
>>>> +	(void)memset(token, 0, sizeof(*token));
>>>> +
>>>> +	token->offset = ftell(jfile->fp);
>>>> +	for (;;) {
>>>> +		int ch;
>>>> +
>>>> +		ch = fgetc(jfile->fp);
>>>> +		jfile->charnum++;
>>>> +
>>>> +		switch (ch) {
>>>> +		case '\n':
>>>> +			jfile->linenum++;
>>>> +			continue;
>>>> +		case ' ':
>>>> +		case '\r':
>>>> +		case '\t':
>>>> +			continue;
>>>> +		case EOF:
>>>> +			token->type = token_eof;
>>>> +			return token->type;
>>>> +		case '{':
>>>> +			token->type = token_lbrace;
>>>> +			return token->type;
>>>> +		case '}':
>>>> +			token->type = token_rbrace;
>>>> +			return token->type;
>>>> +		case '[':
>>>> +			token->type = token_lbracket;
>>>> +			return token->type;
>>>> +		case ']':
>>>> +			token->type = token_rbracket;
>>>> +			return token->type;
>>>> +		case ':':
>>>> +			token->type = token_colon;
>>>> +			return token->type;
>>>> +		case ',':
>>>> +			token->type = token_comma;
>>>> +			return token->type;
>>>> +		case '"':
>>>> +			token->type = json_get_string(jfile, token);
>>>> +			return token->type;
>>>> +		case '0'...'9':
>>>> +			token->type = json_get_int(jfile, token);
>>>> +			return token->type;
>>>> +		case 'a'...'z':
>>>> +			fprintf(stderr, "json_parser: keywords not supported\n");
>>>> +			token->type = token_error;
>>>> +			return token->type;
>>>> +		default:
>>>> +			token->type = token_error;
>>>> +			return token->type;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	/* Should never reach here */
>>>> +	token->type = token_error;
>>>> +	return token->type;
>>>> +}
>>>> +
>>>> +/*
>>>> + *  json_parse_error_where()
>>>> + *	very simple parser error message, report where in the file
>>>> + *	the parsing error occurred.
>>>> + */
>>>> +void json_parse_error_where(json_file *jfile)
>>>> +{
>>>> +	if (jfile->error_reported == 0)
>>>> +		fprintf(stderr, "json_parser: aborted at line %d, char %d of file %s\n",
>>>> +			jfile->linenum, jfile->charnum, jfile->filename);
>>>> +	jfile->error_reported++;
>>>> +}
>>>> +
>>>> +json_object *json_parse_object(json_file *jfile);
>>>> +
>>>> +/*
>>>> + *  json_parse_array()
>>>> + *	parse a json array
>>>> + */
>>>> +json_object *json_parse_array(json_file *jfile)
>>>> +{
>>>> +	json_object *array_obj;
>>>> +
>>>> +	array_obj = json_object_new_array();
>>>> +	if (!array_obj) {
>>>> +		fprintf(stderr, "json_parser: out of memory allocating a json array object\n");
>>>> +		json_parse_error_where(jfile);
>>>> +		return NULL;
>>>> +	}
>>>> +
>>>> +	for (;;) {
>>>> +		json_object *obj;
>>>> +		json_token token;
>>>> +
>>>> +		obj = json_parse_object(jfile);
>>>> +		if (!obj) {
>>>> +			json_parse_error_where(jfile);
>>>> +			free(array_obj);
>>>> +			return NULL;
>>>> +		}
>>>> +		json_object_array_add(array_obj, obj);
>>>> +
>>>> +		switch (json_get_token(jfile, &token)) {
>>>> +		case token_rbracket:
>>>> +			return array_obj;
>>>> +		case token_comma:
>>>> +			continue;
>>>> +		default:
>>>> +			if (json_unget_token(jfile, &token) != 0) {
>>>> +				fprintf(stderr, "json_parser: failed to unget a token\n");
>>>> +				free(array_obj);
>>>> +				return NULL;
>>>> +			}
>>>> +			break;
>>>> +		}
>>>> +	}
>>>> +	return array_obj;
>>>> +}
>>>> +
>>>> +/*
>>>> + *  json_parse_object()
>>>> + *	parse a json object (simplified fwts json format only)
>>>> + */
>>>> +json_object *json_parse_object(json_file *jfile)
>>>> +{
>>>> +	json_token token;
>>>> +	json_object *obj, *val_obj;
>>>> +	char *key = NULL;
>>>> +
>>>> +	if (json_get_token(jfile, &token) != token_lbrace) {
>>>> +		fprintf(stderr, "json_parser: expecting '{', got %s instead\n", json_token_string(&token));
>>>> +		return NULL;
>>>> +	}
>>>> +
>>>> +	obj = json_object_new_object();
>>>> +	if (!obj)
>>>> +		goto err_nomem;
>>>> +
>>>> +	for (;;) {
>>>> +		switch (json_get_token(jfile, &token)) {
>>>> +		case token_rbrace:
>>>> +			return obj;
>>>> +		case token_string:
>>>> +			key = token.u.str;
>>>> +			if (!key)
>>>> +				goto err_nomem;
>>>> +			token.u.str = NULL;
>>>> +			break;
>>>> +		default:
>>>> +			fprintf(stderr, "json_parser: expecting } or key literal string, got %s instead\n", json_token_string(&token));
>>>> +			goto err_free;
>>>> +		}
>>>> +		if (json_get_token(jfile, &token) != token_colon) {
>>>> +			fprintf(stderr, "json_parser: expecting ':', got %s instead\n", json_token_string(&token));
>>>> +			goto err_free;
>>>> +		}
>>>> +		switch (json_get_token(jfile, &token)) {
>>>> +		case token_string:
>>>> +			val_obj = json_object_new_string(token.u.str);
>>>> +			if (!val_obj)
>>>> +				goto err_nomem;
>>>> +			json_object_object_add(obj, key, val_obj);
>>>> +			free(key);
>>>> +			break;
>>>> +		case token_int:
>>>> +			val_obj = json_object_new_int(token.u.intval);
>>>> +			if (!val_obj)
>>>> +				goto err_nomem;
>>>> +			json_object_object_add(obj, key, val_obj);
>>>> +			free(key);
>>>> +			break;
>>>> +		case token_lbracket:
>>>> +			val_obj = json_parse_array(jfile);
>>>> +			if (!val_obj)
>>>> +				goto err_nomem;
>>>> +			json_object_object_add(obj, key, val_obj);
>>>> +			break;
>>>> +		case token_lbrace:
>>>> +			fprintf(stderr, "json_parser: nested objects not supported\n");
>>>> +			goto err_free;
>>>> +		case token_true:
>>>> +		case token_false:
>>>> +		case token_null:
>>>> +			fprintf(stderr, "json_parser: tokens %s not supported\n", json_token_string(&token));
>>>> +			goto err_free;
>>>> +		default:
>>>> +			fprintf(stderr, "json_parser: unexpected token %s\n", json_token_string(&token));
>>>> +		}
>>>> +		switch (json_get_token(jfile, &token)) {
>>>> +		case token_comma:
>>>> +			continue;
>>>> +		case token_rbrace:
>>>> +			return obj;
>>>> +		default:
>>>> +			fprintf(stderr, "json_parser: expected , or }, got %s instead\n", json_token_string(&token));
>>>> +			goto err_free;
>>>> +		}
>>>> +	}
>>>> +
>>>> +err_nomem:
>>>> +	fprintf(stderr, "json_parser: out of memory allocating a json object\n");
>>>> +	json_parse_error_where(jfile);
>>>> +err_free:
>>>> +	free(obj);
>>>> +	return NULL;
>>>> +}
>>>> +
>>>> +/*
>>>> + *  json_object_from_file()
>>>> + *	parse a simplified fwts json file and convert it into
>>>> + *	a json object, return NULL if parsing failed or ran
>>>> + *	out of memory
>>>> + */
>>>> +json_object *json_object_from_file(const char *filename)
>>>> +{
>>>> +	json_object *obj;
>>>> +	json_file jfile;
>>>> +
>>>> +	jfile.filename = filename;
>>>> +	jfile.linenum = 1;
>>>> +	jfile.charnum = 0;
>>>> +	jfile.error_reported = 0;
>>>> +
>>>> +	jfile.fp = fopen(filename, "r");
>>>> +	if (!jfile.fp)
>>>> +		return NULL;
>>>> +
>>>> +	obj = json_parse_object(&jfile);
>>>> +
>>>> +	fclose(jfile.fp);
>>>> +	return obj;
>>>> +}
>>>> +
>>>> +/*
>>>> + *  json_object_new_object()
>>>> + *	return a new json object, NULL if failed
>>>> + */
>>>> +json_object *json_object_new_object(void)
>>>> +{
>>>> +	json_object *obj;
>>>> +
>>>> +	obj = calloc(1, sizeof(*obj));
>>>> +	if (!obj)
>>>> +		return NULL;
>>>> +	obj->type = type_object;
>>>> +	obj->u.ptr = NULL;
>>>> +
>>>> +	return obj;
>>>> +}
>>>> +
>>>> +/*
>>>> + *  json_object_new_object()
>>>> + *	return a new json object, NULL if failed
>>>> + */
>>>> +int json_object_array_length(json_object *obj)
>>>> +{
>>>> +	if (!obj)
>>>> +		return 0;
>>>> +	if (obj->type != type_array)
>>>> +		return 0;
>>>> +	return obj->length;
>>>> +}
>>>> +
>>>> +/*
>>>> + *  json_object_new_int()
>>>> + *	return a new json integer object, NULL if failed
>>>> + */
>>>> +json_object *json_object_new_int(int val)
>>>> +{
>>>> +	json_object *obj;
>>>> +
>>>> +	obj = calloc(1, sizeof(*obj));
>>>> +	if (!obj)
>>>> +		return NULL;
>>>> +	obj->type = type_int;
>>>> +	obj->u.intval = val;
>>>> +
>>>> +	return obj;
>>>> +}
>>>> +
>>>> +/*
>>>> + *  json_object_new_string()
>>>> + *	return a new json string object, NULL if failed
>>>> + */
>>>> +json_object *json_object_new_string(const char *str)
>>>> +{
>>>> +	json_object *obj;
>>>> +
>>>> +	obj = calloc(1, sizeof(*obj));
>>>> +	if (!obj)
>>>> +		return NULL;
>>>> +	obj->type = type_string;
>>>> +	obj->u.ptr = strdup(str);
>>>> +	if (!obj->u.ptr) {
>>>> +		free(obj);
>>>> +		return NULL;
>>>> +	}
>>>> +	return obj;
>>>> +}
>>>> +
>>>> +/*
>>>> + *  json_object_new_array()
>>>> + *	return a new json array object, NULL if failed
>>>> + */
>>>> +json_object *json_object_new_array(void)
>>>> +{
>>>> +	json_object *obj;
>>>> +
>>>> +	obj = calloc(1, sizeof(*obj));
>>>> +	if (!obj)
>>>> +		return NULL;
>>>> +	obj->type = type_array;
>>>> +	obj->length = 0;
>>>> +	obj->u.ptr = NULL;
>>>> +
>>>> +	return obj;
>>>> +}
>>>> +
>>>> +/*
>>>> + *  json_object_array_add_item()
>>>> + *	add an object to another object, return 0 if succeeded,
>>>> + *	non-zero if failed
>>>> + */
>>>> +static int json_object_array_add_item(json_object *obj, json_object *item)
>>>> +{
>>>> +	json_object **obj_ptr;
>>>> +
>>>> +	if (obj->length < 0)
>>>> +		return -1;
>>>> +	obj_ptr = realloc(obj->u.ptr, sizeof(json_object *) * (obj->length + 1));
>>>> +	if (!obj_ptr)
>>>> +		return -1;
>>>> +	obj->u.ptr = (void *)obj_ptr;
>>>> +	obj_ptr[obj->length] = item;
>>>> +	obj->length++;
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +/*
>>>> + *  json_object_array_add()
>>>> + *	add a object to a json array object, return NULL if failed
>>>> + */
>>>> +int json_object_array_add(json_object *obj, json_object *item)
>>>> +{
>>>> +	if (!obj || !item)
>>>> +		return -1;
>>>> +	if (obj->type != type_array)
>>>> +		return -1;
>>>> +	return json_object_array_add_item(obj, item);
>>>> +}
>>>> +
>>>> +
>>>> +/*
>>>> + *  json_object_object_add()
>>>> + *	add a key/valyue object to a json object, return NULL if failed
>>>> + */
>>>> +void json_object_object_add(json_object *obj, const char *key, json_object *value)
>>>> +{
>>>> +	if (!obj || !key || !value)
>>>> +		return;
>>>> +	if (obj->type != type_object)
>>>> +		return;
>>>> +	value->key = strdup(key);
>>>> +	if (!value->key)
>>>> +		return;
>>>> +	json_object_array_add_item(obj, value);
>>>> +}
>>>> +
>>>> +/*
>>>> + *  json_object_array_get_idx()
>>>> + *	get an object at position index from a json array object,
>>>> + *	return NULL if failed
>>>> + */
>>>> +json_object *json_object_array_get_idx(json_object *obj, int index)
>>>> +{
>>>> +	json_object **obj_array;
>>>> +
>>>> +	if (!obj)
>>>> +		return NULL;
>>>> +	if (obj->type != type_array)
>>>> +		return NULL;
>>>> +	if (index >= obj->length)
>>>> +		return NULL;
>>>> +	obj_array = (json_object **)obj->u.ptr;
>>>> +	if (obj_array == NULL)
>>>> +		return NULL;
>>>> +	return obj_array[index];
>>>> +}
>>>> +
>>>> +/*
>>>> + *  json_object_get_string()
>>>> + *	return a C string from a json string object
>>>> + */
>>>> +const char *json_object_get_string(json_object *obj)
>>>> +{
>>>> +	if (!obj)
>>>> +		return NULL;
>>>> +	if (obj->type != type_string)
>>>> +		return NULL;
>>>> +	return (const char *)obj->u.ptr;
>>>> +}
>>>> +
>>>> +/*
>>>> + *  json_object_put()
>>>> + *	free a json object and all sub-objects
>>>> + */
>>>> +void json_object_put(json_object *obj)
>>>> +{
>>>> +	int i;
>>>> +	json_object **obj_ptr;
>>>> +
>>>> +	if (!obj)
>>>> +		return;
>>>> +
>>>> +	if (obj->key)
>>>> +		free(obj->key);
>>>> +
>>>> +	switch (obj->type) {
>>>> +	case type_array:
>>>> +	case type_object:
>>>> +		obj_ptr = (json_object **)obj->u.ptr;
>>>> +
>>>> +		for (i = 0; i < obj->length; i++) {
>>>> +			json_object_put(obj_ptr[i]);
>>>> +		}
>>>> +		free(obj->u.ptr);
>>>> +		break;
>>>> +	case type_string:
>>>> +		free(obj->u.ptr);
>>>> +		break;
>>>> +	case type_null:
>>>> +	case type_int:
>>>> +	default:
>>>> +		break;
>>>> +	}
>>>> +	free(obj);
>>>> +}
>>>> +
>>>> +/*
>>>> + *  str_append()
>>>> + *	append a string to a string, return NULL if failed
>>>> + */
>>>> +static char *str_append(char *str, char *append)
>>>> +{
>>>> +	char *new_str;
>>>> +	size_t len;
>>>> +
>>>> +	if (!append)
>>>> +		return NULL;
>>>> +
>>>> +	if (str) {
>>>> +		len = strlen(append) + strlen(str) + 1;
>>>> +		new_str = realloc(str, len);
>>>> +		if (!new_str) {
>>>> +			free(str);
>>>> +			return NULL;
>>>> +		}
>>>> +		strcat(new_str, append);
>>>> +	} else {
>>>> +		len = strlen(append) + 1;
>>>> +		new_str = malloc(len);
>>>> +		if (!new_str)
>>>> +			return NULL;
>>>> +		strcpy(new_str, append);
>>>> +	}
>>>> +	return new_str;
>>>> +}
>>>> +
>>>> +/*
>>>> + *  str_indent()
>>>> + *	add 2 spaces per indent level to a string, returns
>>>> + *	NULL if failed
>>>> + */
>>>> +static char *str_indent(char *str, int indent)
>>>> +{
>>>> +	char buf[81];
>>>> +	int i;
>>>> +
>>>> +	indent = indent + indent;
>>>> +	if (indent > 80)
>>>> +		indent = 80;
>>>> +
>>>> +	for (i = 0; i < indent; i++)
>>>> +		buf[i] = ' ';
>>>> +	buf[i] = '\0';
>>>> +
>>>> +	return str_append(str, buf);
>>>> +}
>>>> +
>>>> +/*
>>>> + *  json_object_to_json_string_indent()
>>>> + *	turn a simplified fwts json object into a C string, returns
>>>> + *	the stringified object or NULL if failed. Will traverse object
>>>> + *	tree and add indentation based on recursion depth.
>>>> + */
>>>> +static char *json_object_to_json_string_indent(json_object *obj, int indent)
>>>> +{
>>>> +	int i;
>>>> +	json_object **obj_ptr;
>>>> +	char *str = NULL;
>>>> +	char buf[64];
>>>> +
>>>> +	if (!obj)
>>>> +		return NULL;
>>>> +
>>>> +	if (obj->type == type_object) {
>>>> +		str = str_indent(str, indent);
>>>> +		if (!str)
>>>> +			return NULL;
>>>> +		str = str_append(str, "{\n");
>>>> +		if (!str)
>>>> +			return NULL;
>>>> +	}
>>>> +
>>>> +        if (obj->key) {
>>>> +		str = str_indent(str, indent);
>>>> +		if (!str)
>>>> +			return NULL;
>>>> +		str = str_append(str, "\"");
>>>> +		if (!str)
>>>> +			return NULL;
>>>> +		str = str_append(str, obj->key);
>>>> +		if (!str)
>>>> +			return NULL;
>>>> +		str = str_append(str, "\":");
>>>> +		if (!str)
>>>> +			return NULL;
>>>> +        }
>>>> +
>>>> +	switch (obj->type) {
>>>> +	case type_array:
>>>> +		str = str_append(str, "[\n");
>>>> +		if (!str)
>>>> +			return NULL;
>>>> +
>>>> +		obj_ptr = (json_object **)obj->u.ptr;
>>>> +		if (obj_ptr) {
>>>> +			for (i = 0; i < obj->length; i++) {
>>>> +				char *obj_str = json_object_to_json_string_indent(obj_ptr[i], indent + 1);
>>>> +
>>>> +				if (!obj_str) {
>>>> +					free(str);
>>>> +					return NULL;
>>>> +				}
>>>> +				str = str_append(str, obj_str);
>>>> +				if (!str)
>>>> +					return NULL;
>>>> +			}
>>>> +		}
>>>> +		str = str_append(str, "\n");
>>>> +		if (!str)
>>>> +			return NULL;
>>>> +		str = str_indent(str, indent);
>>>> +		if (!str)
>>>> +			return NULL;
>>>> +		str = str_append(str, "]\n");
>>>> +		if (!str)
>>>> +			return NULL;
>>>> +		break;
>>>> +
>>>> +	case type_object:
>>>> +		obj_ptr = (json_object **)obj->u.ptr;
>>>> +		if (obj_ptr) {
>>>> +			for (i = 0; i < obj->length; i++) {
>>>> +				char *obj_str = json_object_to_json_string_indent(obj_ptr[i], indent + 1);
>>>> +
>>>> +				if (!obj_str)
>>>> +					return NULL;
>>>> +				str = str_append(str, obj_str);
>>>> +				if (!str)
>>>> +					return NULL;
>>>> +			}
>>>> +		}
>>>> +		if (!str)
>>>> +			return NULL;
>>>> +		break;
>>>> +
>>>> +	case type_string:
>>>> +		str = str_append(str, "\"");
>>>> +		if (!str)
>>>> +			return NULL;
>>>> +		str = str_append(str, (char *)obj->u.ptr);
>>>> +		if (!str)
>>>> +			return NULL;
>>>> +		str = str_append(str, "\",\n");
>>>> +		if (!str)
>>>> +			return NULL;
>>>> +		break;
>>>> +
>>>> +	case type_null:
>>>> +		str = str_append(str, "(null)\n");
>>>> +		if (!str)
>>>> +			return NULL;
>>>> +		break;
>>>> +
>>>> +	case type_int:
>>>> +		snprintf(buf, sizeof(buf), "%d,\n", obj->u.intval);
>>>> +		str = str_append(str, buf);
>>>> +		if (!str)
>>>> +			return NULL;
>>>> +		break;
>>>> +	default:
>>>> +		return NULL;
>>>> +	}
>>>> +
>>>> +	if (obj->type == type_object) {
>>>> +		str = str_indent(str, indent);
>>>> +		if (!str)
>>>> +			return NULL;
>>>> +		str = str_append(str, "},\n");
>>>> +		if (!str)
>>>> +			return NULL;
>>>> +	}
>>>> +	return str;
>>>> +}
>>>> +
>>>> +/*
>>>> + *  json_object_to_json_string
>>>> + *	convert simplified fwts object to a C string, returns
>>>> + *	NULL if failed
>>>> + */
>>>> +char *json_object_to_json_string(json_object *obj)
>>>> +{
>>>> +	return json_object_to_json_string_indent(obj, 0);
>>>> +}
>>>> +
>>>> +/*
>>>> + *  json_object_object_get()
>>>> + *	return value from key/value pair from an object, returns
>>>> + *	NULL if it can't be found
>>>> + */
>>>> +json_object *json_object_object_get(json_object *obj, const char *key)
>>>> +{
>>>> +	int i;
>>>> +	json_object **obj_ptr;
>>>> +
>>>> +	if (!obj || !key)
>>>> +		return NULL;
>>>> +	if (obj->type != type_object)
>>>> +		return NULL;
>>>> +
>>>> +	obj_ptr = (json_object **)obj->u.ptr;
>>>> +	for (i = 0; i < obj->length; i++) {
>>>> +		if (obj_ptr[i]->key && !strcmp(obj_ptr[i]->key, key))
>>>> +			return obj_ptr[i];
>>>> +	}
>>>> +	return NULL;
>>>> +}
>>>> +
>>>> diff --git a/src/utilities/Makefile.am b/src/utilities/Makefile.am
>>>> index 98d6ebaa..2ae86038 100644
>>>> --- a/src/utilities/Makefile.am
>>>> +++ b/src/utilities/Makefile.am
>>>> @@ -18,10 +18,11 @@
>>>>  
>>>>  AM_CPPFLAGS = -Wall -Werror -Wextra -DDATAROOTDIR=\"$(datarootdir)\" \
>>>>  	`pkg-config --silence-errors --cflags json` \
>>>> -	`pkg-config --silence-errors --cflags json-c`
>>>> +	`pkg-config --silence-errors --cflags json-c` \
>>>> +	-I../lib/include
>>>>  
>>>>  bin_PROGRAMS = kernelscan
>>>> -kernelscan_SOURCES = kernelscan.c
>>>> +kernelscan_SOURCES = kernelscan.c ../lib/src/fwts_json.c
>>>>  
>>>>  
>>>>  -include $(top_srcdir)/git.mk
>>>>
>>
>>
> 
> I did a test build on PPA but got failures, ex.
> https://launchpad.net/~firmware-testing-team/+archive/ubuntu/scratch/+build/19860987
> 

OK, I'll send a V2 this weekend when I can find some time

Colin
diff mbox series

Patch

diff --git a/configure.ac b/configure.ac
index 39a445cd..f40c3678 100644
--- a/configure.ac
+++ b/configure.ac
@@ -9,8 +9,6 @@ 
 	  AC_PROG_LIBTOOL
 	  AC_C_INLINE
 	  AM_PROG_CC_C_O
-	  AC_SEARCH_LIBS([json_object_from_file], [json json-c], [], [ AC_MSG_ERROR([no available json library]) ])
-	  AC_SEARCH_LIBS([json_object_object_get_ex], [json json-c], [ AC_DEFINE([JSON_HAS_GET_EX], [1], [Define if we have json_object_object_get_ex])], [])
   	  AC_CHECK_FUNCS([localtime_r])
 	  AC_CHECK_FUNCS([dup2])
 	  AC_CHECK_FUNCS([getcwd])
@@ -61,7 +59,6 @@ 
 	  AC_CHECK_HEADERS([time.h])
 	  AC_CHECK_HEADERS([sys/ioctl.h])
 	  AC_CHECK_HEADERS([sys/time.h])
-	  AC_CHECK_HEADERS([json/json.h])
 	  AC_CHECK_HEADERS([glib.h])
 	  AC_CHECK_HEADERS([gio/gio.h])
 	  AC_CHECK_HEADERS([asm/opal-prd.h])
diff --git a/src/lib/include/fwts.h b/src/lib/include/fwts.h
index 1e0d5870..6f13d262 100644
--- a/src/lib/include/fwts.h
+++ b/src/lib/include/fwts.h
@@ -153,6 +153,8 @@ 
 
 #define FWTS_JSON_DATA_PATH	DATAROOTDIR "/fwts"
 
+#include <inttypes.h>
+
 #include "fwts_version.h"
 #include "fwts_backtrace.h"
 #include "fwts_types.h"
diff --git a/src/lib/include/fwts_json.h b/src/lib/include/fwts_json.h
index ad51bc45..0c316e02 100644
--- a/src/lib/include/fwts_json.h
+++ b/src/lib/include/fwts_json.h
@@ -1,5 +1,5 @@ 
 /*
- * Copyright (C) 2012-2020 Canonical
+ * Copyright (C) 2010-2020 Canonical
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -16,26 +16,15 @@ 
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
  */
-
 #ifndef __FWTS_JSON_H__
 #define __FWTS_JSON_H__
 
-#include <json.h>
-
-#define __FWTS_JSON_ERR_PTR__ ((json_object*) -1)
 /*
- *  Older versions of json-c may return an error in an
- *  object as a ((json_object*)-1), where as newer
- *  versions return NULL, so check for these. Sigh.
+ *  Minimal subset of json for fwts
  */
-#define FWTS_JSON_ERROR(ptr) \
-	( (ptr == NULL) || ((const json_object *)ptr == __FWTS_JSON_ERR_PTR__) )
 
-/*
- * json-c 0.13.99 does not define TRUE/FALSE anymore
- * the json-c maintainers replaced them with pure 1/0
- * https://github.com/json-c/json-c/commit/0992aac61f8b
- */
+#define FWTS_JSON_ERROR(ptr) 	(!ptr)
+
 #ifndef FALSE
 #define FALSE 0
 #endif
@@ -44,4 +33,46 @@ 
 #define TRUE  1
 #endif
 
+/*
+ *  json types supported
+ */
+typedef enum {
+	type_null,
+	type_int,
+	type_string,
+	type_object,
+	type_array,
+} json_type;
+
+/*
+ *  json object information
+ */
+typedef struct json_object {
+	char *key;		/* Null if undefined */
+	int length;		/* Length of a collection of objects */
+	json_type type;		/* Object type */
+        union {
+                void *ptr;	/* string or object array pointer */
+                int  intval;	/* integer value */
+        } u;
+} json_object;
+
+/*
+ *  minimal json c library functions as required by fwts
+ */
+json_object *json_object_from_file(const char *filename);
+json_object *json_object_object_get(json_object *obj, const char *key);
+int json_object_array_length(json_object *obj);
+json_object *json_object_array_get_idx(json_object *obj, int index);
+const char *json_object_get_string(json_object *obj);
+json_object *json_object_new_int(int);
+void json_object_object_add(json_object *obj, const char *key, json_object *value);
+
+json_object *json_object_new_object(void);
+json_object *json_object_new_array(void);
+char *json_object_to_json_string(json_object *obj);
+void json_object_put(json_object *obj);
+json_object *json_object_new_string(const char *str);
+int json_object_array_add(json_object *obj, json_object *item);
+
 #endif
diff --git a/src/lib/src/Makefile.am b/src/lib/src/Makefile.am
index ecc4136b..4593bb82 100644
--- a/src/lib/src/Makefile.am
+++ b/src/lib/src/Makefile.am
@@ -82,6 +82,7 @@  libfwts_la_SOURCES = 		\
 	fwts_interactive.c 	\
 	fwts_ioport.c		\
 	fwts_ipmi.c		\
+	fwts_json.c		\
 	fwts_keymap.c 		\
 	fwts_klog.c 		\
 	fwts_olog.c		\
diff --git a/src/lib/src/fwts_json.c b/src/lib/src/fwts_json.c
new file mode 100644
index 00000000..b92a241a
--- /dev/null
+++ b/src/lib/src/fwts_json.c
@@ -0,0 +1,917 @@ 
+/*
+ * Copyright (C) 2010-2020 Canonical
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * This is a simplified json parser and json object store
+ * based on json but does not support keywords and is designed
+ * just for the fwts json data files. It is not a full json
+ * implementation and should not be used as such.
+ *
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include "fwts.h"
+
+/*
+ *  json file information
+ */
+typedef struct {
+	FILE *fp;		/* File pointer */
+	const char *filename;	/* Name of file */
+	int linenum;		/* Parser line number */
+	int charnum;		/* Parser char position */
+	int error_reported;	/* Error count */
+} json_file;
+
+/*
+ *  json tokens, subset of full json token set as used
+ *  for fwts requirements
+ */
+typedef enum {
+	token_lbrace,
+	token_rbrace,
+	token_lbracket,
+	token_rbracket,
+	token_colon,
+	token_comma,
+	token_int,
+	token_string,
+	token_true,
+	token_false,
+	token_null,
+	token_error,
+	token_eof,
+} json_token_type;
+
+/*
+ *  json parser token
+ */
+typedef struct {
+	json_token_type type;	/* token type */
+	long offset;		/* offset in file for re-winding */
+	union {
+		char *str;	/* token string value */
+		int  intval;	/* token integer value */
+	} u;
+} json_token;
+
+/*
+ *  json_token_string()
+ *	convert json token to a human readable string
+ */
+char *json_token_string(json_token *jtoken)
+{
+	static char tmp[64];
+
+	switch (jtoken->type) {
+	case token_lbrace:
+		return "{";
+	case token_rbrace:
+		return "}";
+	case token_lbracket:
+		return "[";
+	case token_rbracket:
+		return "]";
+	case token_colon:
+		return ":";
+	case token_comma:
+		return ",";
+	case token_int:
+		(void)snprintf(tmp, sizeof(tmp), "%d", jtoken->u.intval);
+		return tmp;
+	case token_string:
+		return jtoken->u.str;
+	case token_error:
+		return "<error>";
+	case token_eof:
+		return "end of file";
+	default:
+		break;
+	}
+	return "<illegal token>";
+}
+
+/*
+ *  json_get_string()
+ *	parse a literal string
+ */
+json_token_type json_get_string(json_file *jfile, json_token *token)
+{
+	char buffer[4096];
+	size_t i = 0;
+
+	for (;;) {
+		int ch;
+
+		ch = fgetc(jfile->fp);
+		jfile->charnum++;
+		if (ch == EOF) {
+			fprintf(stderr, "json_parser: unexpected EOF in literal string\n");
+			token->u.str = NULL;
+			return token_error;
+		}
+
+		if (ch == '\\') {
+			ch = fgetc(jfile->fp);
+			switch (ch) {
+			case '\\':
+			case '"':
+			case '/':
+				break;
+			case 'b':
+				ch = '\b';
+				break;
+			case 'f':
+				ch = '\f';
+				break;
+			case 'n':
+				ch = '\n';
+				break;
+			case 'r':
+				ch = '\r';
+				break;
+			case 't':
+				ch = '\t';
+				break;
+			case 'u':
+				fprintf(stderr, "json parser: escaped hex values not supported\n");
+				ch = '?';
+				break;
+			}
+			jfile->charnum++;
+		} else if (ch == '"') {
+			buffer[i] = '\0';
+			token->u.str = strdup(buffer);
+			if (!token->u.str) {
+				fprintf(stderr, "json parser: out of memory allocating %zd byte string\n", i);
+				break;
+			}
+			return token_string;
+		}
+		buffer[i] = ch;
+		i++;
+		if (i >= sizeof(buffer)) {
+			fprintf(stderr, "json parser: string too long, maximum size %zd bytes\n", sizeof(buffer) - 1);
+			break;
+		}
+	}
+
+	token->u.str = NULL;
+	return token_error;
+}
+
+/*
+ *  json_get_int()
+ *	parse a simple integer
+ */
+json_token_type json_get_int(json_file *jfile, json_token *token)
+{
+	char buffer[64];
+	size_t i = 0;
+
+	for (;;) {
+		int ch;
+
+		ch = fgetc(jfile->fp);
+		if (!isdigit(ch)) {
+			(void)ungetc(ch, jfile->fp);
+			buffer[i] = '\0';
+			token->u.intval = atoi(buffer);
+			return token_int;
+		}
+		jfile->charnum++;
+		buffer[i] = ch;
+		i++;
+		if (i >= sizeof(buffer)) {
+			fprintf(stderr, "json parser: integer too long, maximum size %zd bytes\n", sizeof(buffer) - 1);
+			break;
+		}
+	}
+
+	token->u.str = NULL;
+	return token_error;
+}
+
+/*
+ *  json_unget_token()
+ *  	push file pointer back to point before the token
+ *	to unpush the token
+ */
+int json_unget_token(json_file *jfile, json_token *token)
+{
+	return fseek(jfile->fp, token->offset, SEEK_SET);
+}
+
+/*
+ *  json_get_keyword()
+ *	get a keyword
+ */
+int json_get_keyword(json_file *jfile, json_token *token)
+{
+	char buffer[32];
+	size_t i = 0;
+
+	token->u.str = NULL;
+	*buffer = '\0';
+
+	for (;;) {
+		int ch;
+
+		ch = fgetc(jfile->fp);
+		jfile->charnum++;
+		if (ch == EOF) {
+			fprintf(stderr, "json_parser: unexpected EOF in keyword string\n");
+			return token_error;
+		}
+		if (ch < 'a' || ch > 'z')
+			break;
+
+		buffer[i] = ch;
+		i++;
+		if (i >= sizeof(buffer)) {
+			fprintf(stderr, "json parser: keyword too long, maximum size %zd bytes\n", sizeof(buffer) - 1);
+			return token_error;
+		}
+	}
+	if (!strcmp(buffer, "true"))
+		return token_true;
+	if (!strcmp(buffer, "false"))
+		return token_false;
+	if (!strcmp(buffer, "null"))
+		return token_null;
+	return token_error;
+}
+
+/*
+ *  json_get_token()
+ *	read next input character(s) and return a matching token
+ */
+json_token_type json_get_token(json_file *jfile, json_token *token)
+{
+	(void)memset(token, 0, sizeof(*token));
+
+	token->offset = ftell(jfile->fp);
+	for (;;) {
+		int ch;
+
+		ch = fgetc(jfile->fp);
+		jfile->charnum++;
+
+		switch (ch) {
+		case '\n':
+			jfile->linenum++;
+			continue;
+		case ' ':
+		case '\r':
+		case '\t':
+			continue;
+		case EOF:
+			token->type = token_eof;
+			return token->type;
+		case '{':
+			token->type = token_lbrace;
+			return token->type;
+		case '}':
+			token->type = token_rbrace;
+			return token->type;
+		case '[':
+			token->type = token_lbracket;
+			return token->type;
+		case ']':
+			token->type = token_rbracket;
+			return token->type;
+		case ':':
+			token->type = token_colon;
+			return token->type;
+		case ',':
+			token->type = token_comma;
+			return token->type;
+		case '"':
+			token->type = json_get_string(jfile, token);
+			return token->type;
+		case '0'...'9':
+			token->type = json_get_int(jfile, token);
+			return token->type;
+		case 'a'...'z':
+			fprintf(stderr, "json_parser: keywords not supported\n");
+			token->type = token_error;
+			return token->type;
+		default:
+			token->type = token_error;
+			return token->type;
+		}
+	}
+
+	/* Should never reach here */
+	token->type = token_error;
+	return token->type;
+}
+
+/*
+ *  json_parse_error_where()
+ *	very simple parser error message, report where in the file
+ *	the parsing error occurred.
+ */
+void json_parse_error_where(json_file *jfile)
+{
+	if (jfile->error_reported == 0)
+		fprintf(stderr, "json_parser: aborted at line %d, char %d of file %s\n",
+			jfile->linenum, jfile->charnum, jfile->filename);
+	jfile->error_reported++;
+}
+
+json_object *json_parse_object(json_file *jfile);
+
+/*
+ *  json_parse_array()
+ *	parse a json array
+ */
+json_object *json_parse_array(json_file *jfile)
+{
+	json_object *array_obj;
+
+	array_obj = json_object_new_array();
+	if (!array_obj) {
+		fprintf(stderr, "json_parser: out of memory allocating a json array object\n");
+		json_parse_error_where(jfile);
+		return NULL;
+	}
+
+	for (;;) {
+		json_object *obj;
+		json_token token;
+
+		obj = json_parse_object(jfile);
+		if (!obj) {
+			json_parse_error_where(jfile);
+			free(array_obj);
+			return NULL;
+		}
+		json_object_array_add(array_obj, obj);
+
+		switch (json_get_token(jfile, &token)) {
+		case token_rbracket:
+			return array_obj;
+		case token_comma:
+			continue;
+		default:
+			if (json_unget_token(jfile, &token) != 0) {
+				fprintf(stderr, "json_parser: failed to unget a token\n");
+				free(array_obj);
+				return NULL;
+			}
+			break;
+		}
+	}
+	return array_obj;
+}
+
+/*
+ *  json_parse_object()
+ *	parse a json object (simplified fwts json format only)
+ */
+json_object *json_parse_object(json_file *jfile)
+{
+	json_token token;
+	json_object *obj, *val_obj;
+	char *key = NULL;
+
+	if (json_get_token(jfile, &token) != token_lbrace) {
+		fprintf(stderr, "json_parser: expecting '{', got %s instead\n", json_token_string(&token));
+		return NULL;
+	}
+
+	obj = json_object_new_object();
+	if (!obj)
+		goto err_nomem;
+
+	for (;;) {
+		switch (json_get_token(jfile, &token)) {
+		case token_rbrace:
+			return obj;
+		case token_string:
+			key = token.u.str;
+			if (!key)
+				goto err_nomem;
+			token.u.str = NULL;
+			break;
+		default:
+			fprintf(stderr, "json_parser: expecting } or key literal string, got %s instead\n", json_token_string(&token));
+			goto err_free;
+		}
+		if (json_get_token(jfile, &token) != token_colon) {
+			fprintf(stderr, "json_parser: expecting ':', got %s instead\n", json_token_string(&token));
+			goto err_free;
+		}
+		switch (json_get_token(jfile, &token)) {
+		case token_string:
+			val_obj = json_object_new_string(token.u.str);
+			if (!val_obj)
+				goto err_nomem;
+			json_object_object_add(obj, key, val_obj);
+			free(key);
+			break;
+		case token_int:
+			val_obj = json_object_new_int(token.u.intval);
+			if (!val_obj)
+				goto err_nomem;
+			json_object_object_add(obj, key, val_obj);
+			free(key);
+			break;
+		case token_lbracket:
+			val_obj = json_parse_array(jfile);
+			if (!val_obj)
+				goto err_nomem;
+			json_object_object_add(obj, key, val_obj);
+			break;
+		case token_lbrace:
+			fprintf(stderr, "json_parser: nested objects not supported\n");
+			goto err_free;
+		case token_true:
+		case token_false:
+		case token_null:
+			fprintf(stderr, "json_parser: tokens %s not supported\n", json_token_string(&token));
+			goto err_free;
+		default:
+			fprintf(stderr, "json_parser: unexpected token %s\n", json_token_string(&token));
+		}
+		switch (json_get_token(jfile, &token)) {
+		case token_comma:
+			continue;
+		case token_rbrace:
+			return obj;
+		default:
+			fprintf(stderr, "json_parser: expected , or }, got %s instead\n", json_token_string(&token));
+			goto err_free;
+		}
+	}
+
+err_nomem:
+	fprintf(stderr, "json_parser: out of memory allocating a json object\n");
+	json_parse_error_where(jfile);
+err_free:
+	free(obj);
+	return NULL;
+}
+
+/*
+ *  json_object_from_file()
+ *	parse a simplified fwts json file and convert it into
+ *	a json object, return NULL if parsing failed or ran
+ *	out of memory
+ */
+json_object *json_object_from_file(const char *filename)
+{
+	json_object *obj;
+	json_file jfile;
+
+	jfile.filename = filename;
+	jfile.linenum = 1;
+	jfile.charnum = 0;
+	jfile.error_reported = 0;
+
+	jfile.fp = fopen(filename, "r");
+	if (!jfile.fp)
+		return NULL;
+
+	obj = json_parse_object(&jfile);
+
+	fclose(jfile.fp);
+	return obj;
+}
+
+/*
+ *  json_object_new_object()
+ *	return a new json object, NULL if failed
+ */
+json_object *json_object_new_object(void)
+{
+	json_object *obj;
+
+	obj = calloc(1, sizeof(*obj));
+	if (!obj)
+		return NULL;
+	obj->type = type_object;
+	obj->u.ptr = NULL;
+
+	return obj;
+}
+
+/*
+ *  json_object_new_object()
+ *	return a new json object, NULL if failed
+ */
+int json_object_array_length(json_object *obj)
+{
+	if (!obj)
+		return 0;
+	if (obj->type != type_array)
+		return 0;
+	return obj->length;
+}
+
+/*
+ *  json_object_new_int()
+ *	return a new json integer object, NULL if failed
+ */
+json_object *json_object_new_int(int val)
+{
+	json_object *obj;
+
+	obj = calloc(1, sizeof(*obj));
+	if (!obj)
+		return NULL;
+	obj->type = type_int;
+	obj->u.intval = val;
+
+	return obj;
+}
+
+/*
+ *  json_object_new_string()
+ *	return a new json string object, NULL if failed
+ */
+json_object *json_object_new_string(const char *str)
+{
+	json_object *obj;
+
+	obj = calloc(1, sizeof(*obj));
+	if (!obj)
+		return NULL;
+	obj->type = type_string;
+	obj->u.ptr = strdup(str);
+	if (!obj->u.ptr) {
+		free(obj);
+		return NULL;
+	}
+	return obj;
+}
+
+/*
+ *  json_object_new_array()
+ *	return a new json array object, NULL if failed
+ */
+json_object *json_object_new_array(void)
+{
+	json_object *obj;
+
+	obj = calloc(1, sizeof(*obj));
+	if (!obj)
+		return NULL;
+	obj->type = type_array;
+	obj->length = 0;
+	obj->u.ptr = NULL;
+
+	return obj;
+}
+
+/*
+ *  json_object_array_add_item()
+ *	add an object to another object, return 0 if succeeded,
+ *	non-zero if failed
+ */
+static int json_object_array_add_item(json_object *obj, json_object *item)
+{
+	json_object **obj_ptr;
+
+	if (obj->length < 0)
+		return -1;
+	obj_ptr = realloc(obj->u.ptr, sizeof(json_object *) * (obj->length + 1));
+	if (!obj_ptr)
+		return -1;
+	obj->u.ptr = (void *)obj_ptr;
+	obj_ptr[obj->length] = item;
+	obj->length++;
+	return 0;
+}
+
+/*
+ *  json_object_array_add()
+ *	add a object to a json array object, return NULL if failed
+ */
+int json_object_array_add(json_object *obj, json_object *item)
+{
+	if (!obj || !item)
+		return -1;
+	if (obj->type != type_array)
+		return -1;
+	return json_object_array_add_item(obj, item);
+}
+
+
+/*
+ *  json_object_object_add()
+ *	add a key/valyue object to a json object, return NULL if failed
+ */
+void json_object_object_add(json_object *obj, const char *key, json_object *value)
+{
+	if (!obj || !key || !value)
+		return;
+	if (obj->type != type_object)
+		return;
+	value->key = strdup(key);
+	if (!value->key)
+		return;
+	json_object_array_add_item(obj, value);
+}
+
+/*
+ *  json_object_array_get_idx()
+ *	get an object at position index from a json array object,
+ *	return NULL if failed
+ */
+json_object *json_object_array_get_idx(json_object *obj, int index)
+{
+	json_object **obj_array;
+
+	if (!obj)
+		return NULL;
+	if (obj->type != type_array)
+		return NULL;
+	if (index >= obj->length)
+		return NULL;
+	obj_array = (json_object **)obj->u.ptr;
+	if (obj_array == NULL)
+		return NULL;
+	return obj_array[index];
+}
+
+/*
+ *  json_object_get_string()
+ *	return a C string from a json string object
+ */
+const char *json_object_get_string(json_object *obj)
+{
+	if (!obj)
+		return NULL;
+	if (obj->type != type_string)
+		return NULL;
+	return (const char *)obj->u.ptr;
+}
+
+/*
+ *  json_object_put()
+ *	free a json object and all sub-objects
+ */
+void json_object_put(json_object *obj)
+{
+	int i;
+	json_object **obj_ptr;
+
+	if (!obj)
+		return;
+
+	if (obj->key)
+		free(obj->key);
+
+	switch (obj->type) {
+	case type_array:
+	case type_object:
+		obj_ptr = (json_object **)obj->u.ptr;
+
+		for (i = 0; i < obj->length; i++) {
+			json_object_put(obj_ptr[i]);
+		}
+		free(obj->u.ptr);
+		break;
+	case type_string:
+		free(obj->u.ptr);
+		break;
+	case type_null:
+	case type_int:
+	default:
+		break;
+	}
+	free(obj);
+}
+
+/*
+ *  str_append()
+ *	append a string to a string, return NULL if failed
+ */
+static char *str_append(char *str, char *append)
+{
+	char *new_str;
+	size_t len;
+
+	if (!append)
+		return NULL;
+
+	if (str) {
+		len = strlen(append) + strlen(str) + 1;
+		new_str = realloc(str, len);
+		if (!new_str) {
+			free(str);
+			return NULL;
+		}
+		strcat(new_str, append);
+	} else {
+		len = strlen(append) + 1;
+		new_str = malloc(len);
+		if (!new_str)
+			return NULL;
+		strcpy(new_str, append);
+	}
+	return new_str;
+}
+
+/*
+ *  str_indent()
+ *	add 2 spaces per indent level to a string, returns
+ *	NULL if failed
+ */
+static char *str_indent(char *str, int indent)
+{
+	char buf[81];
+	int i;
+
+	indent = indent + indent;
+	if (indent > 80)
+		indent = 80;
+
+	for (i = 0; i < indent; i++)
+		buf[i] = ' ';
+	buf[i] = '\0';
+
+	return str_append(str, buf);
+}
+
+/*
+ *  json_object_to_json_string_indent()
+ *	turn a simplified fwts json object into a C string, returns
+ *	the stringified object or NULL if failed. Will traverse object
+ *	tree and add indentation based on recursion depth.
+ */
+static char *json_object_to_json_string_indent(json_object *obj, int indent)
+{
+	int i;
+	json_object **obj_ptr;
+	char *str = NULL;
+	char buf[64];
+
+	if (!obj)
+		return NULL;
+
+	if (obj->type == type_object) {
+		str = str_indent(str, indent);
+		if (!str)
+			return NULL;
+		str = str_append(str, "{\n");
+		if (!str)
+			return NULL;
+	}
+
+        if (obj->key) {
+		str = str_indent(str, indent);
+		if (!str)
+			return NULL;
+		str = str_append(str, "\"");
+		if (!str)
+			return NULL;
+		str = str_append(str, obj->key);
+		if (!str)
+			return NULL;
+		str = str_append(str, "\":");
+		if (!str)
+			return NULL;
+        }
+
+	switch (obj->type) {
+	case type_array:
+		str = str_append(str, "[\n");
+		if (!str)
+			return NULL;
+
+		obj_ptr = (json_object **)obj->u.ptr;
+		if (obj_ptr) {
+			for (i = 0; i < obj->length; i++) {
+				char *obj_str = json_object_to_json_string_indent(obj_ptr[i], indent + 1);
+
+				if (!obj_str) {
+					free(str);
+					return NULL;
+				}
+				str = str_append(str, obj_str);
+				if (!str)
+					return NULL;
+			}
+		}
+		str = str_append(str, "\n");
+		if (!str)
+			return NULL;
+		str = str_indent(str, indent);
+		if (!str)
+			return NULL;
+		str = str_append(str, "]\n");
+		if (!str)
+			return NULL;
+		break;
+
+	case type_object:
+		obj_ptr = (json_object **)obj->u.ptr;
+		if (obj_ptr) {
+			for (i = 0; i < obj->length; i++) {
+				char *obj_str = json_object_to_json_string_indent(obj_ptr[i], indent + 1);
+
+				if (!obj_str)
+					return NULL;
+				str = str_append(str, obj_str);
+				if (!str)
+					return NULL;
+			}
+		}
+		if (!str)
+			return NULL;
+		break;
+
+	case type_string:
+		str = str_append(str, "\"");
+		if (!str)
+			return NULL;
+		str = str_append(str, (char *)obj->u.ptr);
+		if (!str)
+			return NULL;
+		str = str_append(str, "\",\n");
+		if (!str)
+			return NULL;
+		break;
+
+	case type_null:
+		str = str_append(str, "(null)\n");
+		if (!str)
+			return NULL;
+		break;
+
+	case type_int:
+		snprintf(buf, sizeof(buf), "%d,\n", obj->u.intval);
+		str = str_append(str, buf);
+		if (!str)
+			return NULL;
+		break;
+	default:
+		return NULL;
+	}
+
+	if (obj->type == type_object) {
+		str = str_indent(str, indent);
+		if (!str)
+			return NULL;
+		str = str_append(str, "},\n");
+		if (!str)
+			return NULL;
+	}
+	return str;
+}
+
+/*
+ *  json_object_to_json_string
+ *	convert simplified fwts object to a C string, returns
+ *	NULL if failed
+ */
+char *json_object_to_json_string(json_object *obj)
+{
+	return json_object_to_json_string_indent(obj, 0);
+}
+
+/*
+ *  json_object_object_get()
+ *	return value from key/value pair from an object, returns
+ *	NULL if it can't be found
+ */
+json_object *json_object_object_get(json_object *obj, const char *key)
+{
+	int i;
+	json_object **obj_ptr;
+
+	if (!obj || !key)
+		return NULL;
+	if (obj->type != type_object)
+		return NULL;
+
+	obj_ptr = (json_object **)obj->u.ptr;
+	for (i = 0; i < obj->length; i++) {
+		if (obj_ptr[i]->key && !strcmp(obj_ptr[i]->key, key))
+			return obj_ptr[i];
+	}
+	return NULL;
+}
+
diff --git a/src/utilities/Makefile.am b/src/utilities/Makefile.am
index 98d6ebaa..2ae86038 100644
--- a/src/utilities/Makefile.am
+++ b/src/utilities/Makefile.am
@@ -18,10 +18,11 @@ 
 
 AM_CPPFLAGS = -Wall -Werror -Wextra -DDATAROOTDIR=\"$(datarootdir)\" \
 	`pkg-config --silence-errors --cflags json` \
-	`pkg-config --silence-errors --cflags json-c`
+	`pkg-config --silence-errors --cflags json-c` \
+	-I../lib/include
 
 bin_PROGRAMS = kernelscan
-kernelscan_SOURCES = kernelscan.c
+kernelscan_SOURCES = kernelscan.c ../lib/src/fwts_json.c
 
 
 -include $(top_srcdir)/git.mk