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

Colin Ian King colin.king at canonical.com
Fri Aug 21 19:20:26 UTC 2020


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 at 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 at 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



More information about the fwts-devel mailing list