mirror of
https://github.com/kgabis/parson.git
synced 2024-11-24 06:05:29 +00: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)
|
||||
|
||||
set(PARSON_VERSION 1.4.0)
|
||||
set(PARSON_VERSION 1.5.0)
|
||||
add_library(parson parson.c)
|
||||
target_include_directories(parson PUBLIC $<INSTALL_INTERFACE:include>)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
project('parson', 'c',
|
||||
version : '1.4.0', # !!! also increment lib_so_version !!!
|
||||
version : '1.5.0',
|
||||
license : 'MIT',
|
||||
meson_version : '>=0.46.0',
|
||||
default_options : [
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "parson",
|
||||
"version": "1.4.0",
|
||||
"version": "1.5.0",
|
||||
"repo": "kgabis/parson",
|
||||
"description": "Small json parser and reader",
|
||||
"keywords": [ "json", "parser" ],
|
||||
|
64
parson.c
64
parson.c
@ -1,7 +1,7 @@
|
||||
/*
|
||||
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
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@ -31,7 +31,7 @@
|
||||
#include "parson.h"
|
||||
|
||||
#define PARSON_IMPL_VERSION_MAJOR 1
|
||||
#define PARSON_IMPL_VERSION_MINOR 4
|
||||
#define PARSON_IMPL_VERSION_MINOR 5
|
||||
#define PARSON_IMPL_VERSION_PATCH 0
|
||||
|
||||
#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 */
|
||||
#endif
|
||||
|
||||
#ifndef PARSON_INDENT_STR
|
||||
#define PARSON_INDENT_STR " "
|
||||
#endif
|
||||
|
||||
#define SIZEOF_TOKEN(a) (sizeof(a) - 1)
|
||||
#define SKIP_CHAR(str) ((*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 JSON_Number_Serialization_Function parson_number_serialization_function = NULL;
|
||||
|
||||
#define IS_CONT(b) (((unsigned char)(b) & 0xC0) == 0x80) /* is utf-8 continuation byte */
|
||||
|
||||
typedef int parson_bool_t;
|
||||
@ -192,8 +198,6 @@ static JSON_Value * parse_value(const char **string, size_t nesting);
|
||||
/* 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_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 */
|
||||
static char * read_file(const char * filename) {
|
||||
@ -1095,15 +1099,27 @@ static JSON_Value * parse_null_value(const char **string) {
|
||||
}
|
||||
|
||||
/* 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));\
|
||||
if (written < 0) { return -1; }\
|
||||
if (buf != NULL) { buf += written; }\
|
||||
written_total += written; } while(0)
|
||||
/* APPEND_STRING() is only called on string literals.
|
||||
It's a bit hacky because it makes plenty of assumptions about the external state
|
||||
and should eventually be tidied up into a function (same goes for APPEND_INDENT)
|
||||
*/
|
||||
#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)
|
||||
{
|
||||
@ -1225,7 +1241,9 @@ static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int le
|
||||
if (buf != NULL) {
|
||||
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);
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
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_INDENT
|
||||
|
||||
@ -2450,3 +2452,7 @@ void json_set_float_serialization_format(const char *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
|
||||
|
||||
Parson 1.4.0 (https://github.com/kgabis/parson)
|
||||
Parson 1.5.0 (https://github.com/kgabis/parson)
|
||||
Copyright (c) 2012 - 2022 Krzysztof Gabis
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@ -35,10 +35,10 @@ extern "C"
|
||||
#endif
|
||||
|
||||
#define PARSON_VERSION_MAJOR 1
|
||||
#define PARSON_VERSION_MINOR 4
|
||||
#define PARSON_VERSION_MINOR 5
|
||||
#define PARSON_VERSION_PATCH 0
|
||||
|
||||
#define PARSON_VERSION_STRING "1.4.0"
|
||||
#define PARSON_VERSION_STRING "1.5.0"
|
||||
|
||||
#include <stddef.h> /* size_t */
|
||||
|
||||
@ -67,6 +67,12 @@ typedef int JSON_Status;
|
||||
typedef void * (*JSON_Malloc_Function)(size_t);
|
||||
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
|
||||
from stdlib will be used for all allocations */
|
||||
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. */
|
||||
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 */
|
||||
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_failing_allocations(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 persistence_example(void);
|
||||
@ -132,6 +133,7 @@ int tests_main(int argc, char *argv[]) {
|
||||
test_memory_leaks();
|
||||
test_failing_allocations();
|
||||
test_custom_number_format();
|
||||
test_custom_number_serialization_function();
|
||||
|
||||
printf("Tests failed: %d\n", g_tests_failed);
|
||||
printf("Tests passed: %d\n", g_tests_passed);
|
||||
@ -704,6 +706,28 @@ void test_custom_number_format() {
|
||||
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) {
|
||||
JSON_Value *root_value;
|
||||
JSON_Array *commits;
|
||||
|
Loading…
Reference in New Issue
Block a user