mirror of
https://github.com/kgabis/parson.git
synced 2025-01-14 06:12:54 +08:00
1.5.0: Using memcpy instead of sprintf for string literals, adds json_set_number_serialization_function
This commit is contained in:
parent
29db75d970
commit
1314bf8ad6
@ -3,7 +3,7 @@ project(parson C)
|
|||||||
|
|
||||||
include (GNUInstallDirs)
|
include (GNUInstallDirs)
|
||||||
|
|
||||||
set(PARSON_VERSION 1.4.0)
|
set(PARSON_VERSION 1.5.0)
|
||||||
add_library(parson parson.c)
|
add_library(parson parson.c)
|
||||||
target_include_directories(parson PUBLIC $<INSTALL_INTERFACE:include>)
|
target_include_directories(parson PUBLIC $<INSTALL_INTERFACE:include>)
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
project('parson', 'c',
|
project('parson', 'c',
|
||||||
version : '1.4.0', # !!! also increment lib_so_version !!!
|
version : '1.5.0',
|
||||||
license : 'MIT',
|
license : 'MIT',
|
||||||
meson_version : '>=0.46.0',
|
meson_version : '>=0.46.0',
|
||||||
default_options : [
|
default_options : [
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "parson",
|
"name": "parson",
|
||||||
"version": "1.4.0",
|
"version": "1.5.0",
|
||||||
"repo": "kgabis/parson",
|
"repo": "kgabis/parson",
|
||||||
"description": "Small json parser and reader",
|
"description": "Small json parser and reader",
|
||||||
"keywords": [ "json", "parser" ],
|
"keywords": [ "json", "parser" ],
|
||||||
|
64
parson.c
64
parson.c
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
SPDX-License-Identifier: MIT
|
SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
Parson 1.4.0 (https://github.com/kgabis/parson)
|
Parson 1.5.0 (https://github.com/kgabis/parson)
|
||||||
Copyright (c) 2012 - 2022 Krzysztof Gabis
|
Copyright (c) 2012 - 2022 Krzysztof Gabis
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
@ -31,7 +31,7 @@
|
|||||||
#include "parson.h"
|
#include "parson.h"
|
||||||
|
|
||||||
#define PARSON_IMPL_VERSION_MAJOR 1
|
#define PARSON_IMPL_VERSION_MAJOR 1
|
||||||
#define PARSON_IMPL_VERSION_MINOR 4
|
#define PARSON_IMPL_VERSION_MINOR 5
|
||||||
#define PARSON_IMPL_VERSION_PATCH 0
|
#define PARSON_IMPL_VERSION_PATCH 0
|
||||||
|
|
||||||
#if (PARSON_VERSION_MAJOR != PARSON_IMPL_VERSION_MAJOR)\
|
#if (PARSON_VERSION_MAJOR != PARSON_IMPL_VERSION_MAJOR)\
|
||||||
@ -71,6 +71,10 @@
|
|||||||
#define PARSON_NUM_BUF_SIZE 64 /* double printed with "%1.17g" shouldn't be longer than 25 bytes so let's be paranoid and use 64 */
|
#define PARSON_NUM_BUF_SIZE 64 /* double printed with "%1.17g" shouldn't be longer than 25 bytes so let's be paranoid and use 64 */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef PARSON_INDENT_STR
|
||||||
|
#define PARSON_INDENT_STR " "
|
||||||
|
#endif
|
||||||
|
|
||||||
#define SIZEOF_TOKEN(a) (sizeof(a) - 1)
|
#define SIZEOF_TOKEN(a) (sizeof(a) - 1)
|
||||||
#define SKIP_CHAR(str) ((*str)++)
|
#define SKIP_CHAR(str) ((*str)++)
|
||||||
#define SKIP_WHITESPACES(str) while (isspace((unsigned char)(**str))) { SKIP_CHAR(str); }
|
#define SKIP_WHITESPACES(str) while (isspace((unsigned char)(**str))) { SKIP_CHAR(str); }
|
||||||
@ -94,6 +98,8 @@ static int parson_escape_slashes = 1;
|
|||||||
|
|
||||||
static char *parson_float_format = NULL;
|
static char *parson_float_format = NULL;
|
||||||
|
|
||||||
|
static JSON_Number_Serialization_Function parson_number_serialization_function = NULL;
|
||||||
|
|
||||||
#define IS_CONT(b) (((unsigned char)(b) & 0xC0) == 0x80) /* is utf-8 continuation byte */
|
#define IS_CONT(b) (((unsigned char)(b) & 0xC0) == 0x80) /* is utf-8 continuation byte */
|
||||||
|
|
||||||
typedef int parson_bool_t;
|
typedef int parson_bool_t;
|
||||||
@ -192,8 +198,6 @@ static JSON_Value * parse_value(const char **string, size_t nesting);
|
|||||||
/* Serialization */
|
/* Serialization */
|
||||||
static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, parson_bool_t is_pretty, char *num_buf);
|
static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, parson_bool_t is_pretty, char *num_buf);
|
||||||
static int json_serialize_string(const char *string, size_t len, char *buf);
|
static int json_serialize_string(const char *string, size_t len, char *buf);
|
||||||
static int append_indent(char *buf, int level);
|
|
||||||
static int append_string(char *buf, const char *string);
|
|
||||||
|
|
||||||
/* Various */
|
/* Various */
|
||||||
static char * read_file(const char * filename) {
|
static char * read_file(const char * filename) {
|
||||||
@ -1095,15 +1099,27 @@ static JSON_Value * parse_null_value(const char **string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Serialization */
|
/* Serialization */
|
||||||
#define APPEND_STRING(str) do { written = append_string(buf, (str));\
|
|
||||||
if (written < 0) { return -1; }\
|
|
||||||
if (buf != NULL) { buf += written; }\
|
|
||||||
written_total += written; } while(0)
|
|
||||||
|
|
||||||
#define APPEND_INDENT(level) do { written = append_indent(buf, (level));\
|
/* APPEND_STRING() is only called on string literals.
|
||||||
if (written < 0) { return -1; }\
|
It's a bit hacky because it makes plenty of assumptions about the external state
|
||||||
if (buf != NULL) { buf += written; }\
|
and should eventually be tidied up into a function (same goes for APPEND_INDENT)
|
||||||
written_total += written; } while(0)
|
*/
|
||||||
|
#define APPEND_STRING(str) do {\
|
||||||
|
written = SIZEOF_TOKEN((str));\
|
||||||
|
if (buf != NULL) {\
|
||||||
|
memcpy(buf, (str), written);\
|
||||||
|
buf[written] = '\0';\
|
||||||
|
buf += written;\
|
||||||
|
}\
|
||||||
|
written_total += written;\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define APPEND_INDENT(level) do {\
|
||||||
|
int level_i = 0;\
|
||||||
|
for (level_i = 0; level_i < (level); level_i++) {\
|
||||||
|
APPEND_STRING(PARSON_INDENT_STR);\
|
||||||
|
}\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, parson_bool_t is_pretty, char *num_buf)
|
static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, parson_bool_t is_pretty, char *num_buf)
|
||||||
{
|
{
|
||||||
@ -1225,7 +1241,9 @@ static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int le
|
|||||||
if (buf != NULL) {
|
if (buf != NULL) {
|
||||||
num_buf = buf;
|
num_buf = buf;
|
||||||
}
|
}
|
||||||
if (parson_float_format) {
|
if (parson_number_serialization_function) {
|
||||||
|
written = parson_number_serialization_function(num, num_buf);
|
||||||
|
} else if (parson_float_format) {
|
||||||
written = sprintf(num_buf, parson_float_format, num);
|
written = sprintf(num_buf, parson_float_format, num);
|
||||||
} else {
|
} else {
|
||||||
written = sprintf(num_buf, PARSON_DEFAULT_FLOAT_FORMAT, num);
|
written = sprintf(num_buf, PARSON_DEFAULT_FLOAT_FORMAT, num);
|
||||||
@ -1315,22 +1333,6 @@ static int json_serialize_string(const char *string, size_t len, char *buf) {
|
|||||||
return written_total;
|
return written_total;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int append_indent(char *buf, int level) {
|
|
||||||
int i;
|
|
||||||
int written = -1, written_total = 0;
|
|
||||||
for (i = 0; i < level; i++) {
|
|
||||||
APPEND_STRING(" ");
|
|
||||||
}
|
|
||||||
return written_total;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int append_string(char *buf, const char *string) {
|
|
||||||
if (buf == NULL) {
|
|
||||||
return (int)strlen(string);
|
|
||||||
}
|
|
||||||
return sprintf(buf, "%s", string);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef APPEND_STRING
|
#undef APPEND_STRING
|
||||||
#undef APPEND_INDENT
|
#undef APPEND_INDENT
|
||||||
|
|
||||||
@ -2450,3 +2452,7 @@ void json_set_float_serialization_format(const char *format) {
|
|||||||
}
|
}
|
||||||
parson_float_format = parson_strdup(format);
|
parson_float_format = parson_strdup(format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void json_set_number_serialization_function(JSON_Number_Serialization_Function func) {
|
||||||
|
parson_number_serialization_function = func;
|
||||||
|
}
|
||||||
|
16
parson.h
16
parson.h
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
SPDX-License-Identifier: MIT
|
SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
Parson 1.4.0 (https://github.com/kgabis/parson)
|
Parson 1.5.0 (https://github.com/kgabis/parson)
|
||||||
Copyright (c) 2012 - 2022 Krzysztof Gabis
|
Copyright (c) 2012 - 2022 Krzysztof Gabis
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
@ -35,10 +35,10 @@ extern "C"
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define PARSON_VERSION_MAJOR 1
|
#define PARSON_VERSION_MAJOR 1
|
||||||
#define PARSON_VERSION_MINOR 4
|
#define PARSON_VERSION_MINOR 5
|
||||||
#define PARSON_VERSION_PATCH 0
|
#define PARSON_VERSION_PATCH 0
|
||||||
|
|
||||||
#define PARSON_VERSION_STRING "1.4.0"
|
#define PARSON_VERSION_STRING "1.5.0"
|
||||||
|
|
||||||
#include <stddef.h> /* size_t */
|
#include <stddef.h> /* size_t */
|
||||||
|
|
||||||
@ -67,6 +67,12 @@ typedef int JSON_Status;
|
|||||||
typedef void * (*JSON_Malloc_Function)(size_t);
|
typedef void * (*JSON_Malloc_Function)(size_t);
|
||||||
typedef void (*JSON_Free_Function)(void *);
|
typedef void (*JSON_Free_Function)(void *);
|
||||||
|
|
||||||
|
/* A function used for serializing numbers (see json_set_number_serialization_function).
|
||||||
|
If 'buf' is null then it should return number of bytes that would've been written
|
||||||
|
(but not more than PARSON_NUM_BUF_SIZE).
|
||||||
|
*/
|
||||||
|
typedef int (*JSON_Number_Serialization_Function)(double num, char *buf);
|
||||||
|
|
||||||
/* Call only once, before calling any other function from parson API. If not called, malloc and free
|
/* Call only once, before calling any other function from parson API. If not called, malloc and free
|
||||||
from stdlib will be used for all allocations */
|
from stdlib will be used for all allocations */
|
||||||
void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Function free_fun);
|
void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Function free_fun);
|
||||||
@ -80,6 +86,10 @@ void json_set_escape_slashes(int escape_slashes);
|
|||||||
If format is null then the default format is used. */
|
If format is null then the default format is used. */
|
||||||
void json_set_float_serialization_format(const char *format);
|
void json_set_float_serialization_format(const char *format);
|
||||||
|
|
||||||
|
/* Sets a function that will be used for serialization of numbers.
|
||||||
|
If function is null then the default serialization function is used. */
|
||||||
|
void json_set_number_serialization_function(JSON_Number_Serialization_Function fun);
|
||||||
|
|
||||||
/* Parses first JSON value in a file, returns NULL in case of error */
|
/* Parses first JSON value in a file, returns NULL in case of error */
|
||||||
JSON_Value * json_parse_file(const char *filename);
|
JSON_Value * json_parse_file(const char *filename);
|
||||||
|
|
||||||
|
24
tests.c
24
tests.c
@ -63,6 +63,7 @@ void test_suite_11(void); /* Additional things that require testing */
|
|||||||
void test_memory_leaks(void);
|
void test_memory_leaks(void);
|
||||||
void test_failing_allocations(void);
|
void test_failing_allocations(void);
|
||||||
void test_custom_number_format(void);
|
void test_custom_number_format(void);
|
||||||
|
void test_custom_number_serialization_function(void);
|
||||||
|
|
||||||
void print_commits_info(const char *username, const char *repo);
|
void print_commits_info(const char *username, const char *repo);
|
||||||
void persistence_example(void);
|
void persistence_example(void);
|
||||||
@ -132,6 +133,7 @@ int tests_main(int argc, char *argv[]) {
|
|||||||
test_memory_leaks();
|
test_memory_leaks();
|
||||||
test_failing_allocations();
|
test_failing_allocations();
|
||||||
test_custom_number_format();
|
test_custom_number_format();
|
||||||
|
test_custom_number_serialization_function();
|
||||||
|
|
||||||
printf("Tests failed: %d\n", g_tests_failed);
|
printf("Tests failed: %d\n", g_tests_failed);
|
||||||
printf("Tests passed: %d\n", g_tests_passed);
|
printf("Tests passed: %d\n", g_tests_passed);
|
||||||
@ -704,6 +706,28 @@ void test_custom_number_format() {
|
|||||||
json_value_free(val);
|
json_value_free(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int custom_serialization_func_called = 0;
|
||||||
|
static int custom_serialization_func(double num, char *buf) {
|
||||||
|
char num_buf[32];
|
||||||
|
custom_serialization_func_called = 1;
|
||||||
|
if (buf == NULL)
|
||||||
|
buf = num_buf;
|
||||||
|
return sprintf(buf, "%.1f", num);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_custom_number_serialization_function() {
|
||||||
|
/* We just test that custom_serialization_func() gets called, not it's performance */
|
||||||
|
char *serialized = NULL;
|
||||||
|
JSON_Value *val = json_value_init_number(0.6);
|
||||||
|
json_set_number_serialization_function(custom_serialization_func);
|
||||||
|
serialized = json_serialize_to_string(val);
|
||||||
|
TEST(STREQ(serialized, "0.6"));
|
||||||
|
TEST(custom_serialization_func_called);
|
||||||
|
json_set_number_serialization_function(NULL);
|
||||||
|
json_free_serialized_string(serialized);
|
||||||
|
json_value_free(val);
|
||||||
|
}
|
||||||
|
|
||||||
void print_commits_info(const char *username, const char *repo) {
|
void print_commits_info(const char *username, const char *repo) {
|
||||||
JSON_Value *root_value;
|
JSON_Value *root_value;
|
||||||
JSON_Array *commits;
|
JSON_Array *commits;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user