add json_parser.[hc] for parse json array and map
parent
94741c51c2
commit
827fc115e2
3
HISTORY
3
HISTORY
|
|
@ -1,9 +1,10 @@
|
|||
|
||||
Version 1.40 2018-08-20
|
||||
Version 1.40 2018-08-22
|
||||
* add function conn_pool_parse_server_info and conn_pool_load_server_info
|
||||
* support directive: #@add_annotation, for example:
|
||||
#@add_annotation CONFIG_GET /usr/lib/libshmcache.so /etc/libshmcache.conf
|
||||
* add function fc_split_string and fc_match_delim
|
||||
* add json_parser.[hc] for parse json array and map
|
||||
|
||||
Version 1.39 2018-07-31
|
||||
* add #@function REPLACE_VARS
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ FAST_SHARED_OBJS = hash.lo chain.lo shared_func.lo ini_file_reader.lo \
|
|||
fast_buffer.lo multi_skiplist.lo flat_skiplist.lo \
|
||||
system_info.lo fast_blocked_queue.lo id_generator.lo \
|
||||
char_converter.lo char_convert_loader.lo common_blocked_queue.lo \
|
||||
multi_socket_client.lo skiplist_set.lo
|
||||
multi_socket_client.lo skiplist_set.lo json_parser.lo
|
||||
|
||||
FAST_STATIC_OBJS = hash.o chain.o shared_func.o ini_file_reader.o \
|
||||
logger.o sockopt.o base64.o sched_thread.o \
|
||||
|
|
@ -25,7 +25,7 @@ FAST_STATIC_OBJS = hash.o chain.o shared_func.o ini_file_reader.o \
|
|||
fast_buffer.o multi_skiplist.o flat_skiplist.o \
|
||||
system_info.o fast_blocked_queue.o id_generator.o \
|
||||
char_converter.o char_convert_loader.o common_blocked_queue.o \
|
||||
multi_socket_client.o skiplist_set.o
|
||||
multi_socket_client.o skiplist_set.o json_parser.o
|
||||
|
||||
HEADER_FILES = common_define.h hash.h chain.h logger.h base64.h \
|
||||
shared_func.h pthread_func.h ini_file_reader.h _os_define.h \
|
||||
|
|
@ -37,7 +37,8 @@ HEADER_FILES = common_define.h hash.h chain.h logger.h base64.h \
|
|||
skiplist_common.h system_info.h fast_blocked_queue.h \
|
||||
php7_ext_wrapper.h id_generator.h char_converter.h \
|
||||
char_convert_loader.h common_blocked_queue.h \
|
||||
multi_socket_client.h skiplist_set.h fc_list.h
|
||||
multi_socket_client.h skiplist_set.h fc_list.h \
|
||||
json_parser.h
|
||||
|
||||
ALL_OBJS = $(FAST_STATIC_OBJS) $(FAST_SHARED_OBJS)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,270 @@
|
|||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include "shared_func.h"
|
||||
#include "json_parser.h"
|
||||
|
||||
#define JSON_SPACE(ch) \
|
||||
(ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
|
||||
|
||||
int detect_json_type(const string_t *input)
|
||||
{
|
||||
if (input->len < 2) {
|
||||
return FC_JSON_TYPE_STRING;
|
||||
}
|
||||
|
||||
if (input->str[0] == '[' && input->str[input->len - 1] == ']') {
|
||||
return FC_JSON_TYPE_ARRAY;
|
||||
}
|
||||
if (input->str[0] == '{' && input->str[input->len - 1] == '}') {
|
||||
return FC_JSON_TYPE_MAP;
|
||||
}
|
||||
|
||||
return FC_JSON_TYPE_STRING;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char *p;
|
||||
const char *end;
|
||||
string_t element;
|
||||
char *error_info;
|
||||
int error_size;
|
||||
} ParseContext;
|
||||
|
||||
static int next_json_element(ParseContext *context, const char delim)
|
||||
{
|
||||
char *dest;
|
||||
char quote_ch;
|
||||
|
||||
dest = context->element.str;
|
||||
quote_ch = *context->p;
|
||||
if (quote_ch == '\"' || quote_ch == '\'') {
|
||||
context->p++;
|
||||
while (context->p < context->end && *context->p != quote_ch) {
|
||||
if (*context->p == '\\') {
|
||||
if (++context->p == context->end) {
|
||||
snprintf(context->error_info, context->error_size,
|
||||
"expect a character after \\");
|
||||
return EINVAL;
|
||||
}
|
||||
switch (*context->p) {
|
||||
case '\\':
|
||||
*dest++ = '\\';
|
||||
break;
|
||||
case '/':
|
||||
*dest++ = '/';
|
||||
break;
|
||||
case 't':
|
||||
*dest++ = '\t';
|
||||
break;
|
||||
case 'r':
|
||||
*dest++ = '\r';
|
||||
break;
|
||||
case 'n':
|
||||
*dest++ = '\n';
|
||||
break;
|
||||
case 'b':
|
||||
*dest++ = '\f';
|
||||
break;
|
||||
case '"':
|
||||
*dest++ = '\"';
|
||||
break;
|
||||
case '\'':
|
||||
*dest++ = '\'';
|
||||
break;
|
||||
default:
|
||||
snprintf(context->error_info, context->error_size,
|
||||
"invalid escaped character: %c(0x%x)",
|
||||
*context->p, (unsigned char)*context->p);
|
||||
return EINVAL;
|
||||
}
|
||||
context->p++;
|
||||
} else {
|
||||
*dest++ = *context->p++;
|
||||
}
|
||||
}
|
||||
|
||||
if (context->p == context->end) {
|
||||
snprintf(context->error_info, context->error_size,
|
||||
"expect closed character: %c", quote_ch);
|
||||
return EINVAL;
|
||||
}
|
||||
context->p++; //skip quote char
|
||||
} else {
|
||||
while (context->p < context->end && *context->p != delim) {
|
||||
*dest++ = *context->p++;
|
||||
}
|
||||
}
|
||||
|
||||
*dest = '\0';
|
||||
context->element.len = dest - context->element.str;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_alloc_json_array(string_array_t *array,
|
||||
char *error_info, const int error_size)
|
||||
{
|
||||
int bytes;
|
||||
if (array->count < array->alloc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (array->alloc == 0) {
|
||||
array->alloc = 32;
|
||||
} else {
|
||||
array->alloc *= 2;
|
||||
}
|
||||
|
||||
bytes = sizeof(string_t) * array->alloc;
|
||||
array->elements = (string_t *)realloc(array->elements, bytes);
|
||||
if (array->elements == NULL) {
|
||||
snprintf(error_info, error_size, "malloc %d bytes fail", bytes);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int decode_json_array(const string_t *input, string_array_t *array,
|
||||
char *error_info, const int error_size)
|
||||
{
|
||||
ParseContext context;
|
||||
int buff_len;
|
||||
int result;
|
||||
|
||||
array->elements = NULL;
|
||||
array->count = array->alloc = 0;
|
||||
array->buff = NULL;
|
||||
|
||||
if (input->len < 2) {
|
||||
snprintf(error_info, error_size, "invalid json array, "
|
||||
"correct format: [e1, e2, ...]");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (input->str[0] != '[') {
|
||||
snprintf(error_info, error_size, "json array must start with [");
|
||||
return EINVAL;
|
||||
}
|
||||
if (input->str[input->len - 1] != ']') {
|
||||
snprintf(error_info, error_size, "json array must end with ]");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
buff_len = input->len - 2;
|
||||
array->buff = (char *)malloc(buff_len + 1);
|
||||
if (array->buff == NULL) {
|
||||
snprintf(error_info, error_size, "malloc %d bytes fail", buff_len + 1);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
context.error_info = error_info;
|
||||
context.error_size = error_size;
|
||||
context.element.str = array->buff;
|
||||
context.element.len = 0;
|
||||
context.p = input->str + 1;
|
||||
context.end = input->str + input->len - 1;
|
||||
result = 0;
|
||||
while (context.p < context.end) {
|
||||
while (context.p < context.end && JSON_SPACE(*context.p)) {
|
||||
context.p++;
|
||||
}
|
||||
|
||||
if (context.p == context.end) {
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(stderr, "start: %s\n", context.p);
|
||||
|
||||
if (*context.p == ',') {
|
||||
context.p++;
|
||||
while (context.p < context.end && JSON_SPACE(*context.p)) {
|
||||
context.p++;
|
||||
}
|
||||
if (context.p < context.end) { //ignore last comma
|
||||
snprintf(error_info, error_size, "unexpect comma");
|
||||
result = EINVAL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ((result=next_json_element(&context, ',')) != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
while (context.p < context.end && JSON_SPACE(*context.p)) {
|
||||
context.p++;
|
||||
}
|
||||
if (context.p < context.end && *context.p == ',') {
|
||||
context.p++; //skip comma
|
||||
}
|
||||
fprintf(stderr, "end: %s\n", context.p);
|
||||
|
||||
if ((result=check_alloc_json_array(array, error_info, error_size)) != 0) {
|
||||
array->count = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
array->elements[array->count++] = context.element;
|
||||
context.element.str += context.element.len + 1;
|
||||
}
|
||||
|
||||
if (result != 0) {
|
||||
free_json_array(array);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void free_json_array(string_array_t *array)
|
||||
{
|
||||
if (array->elements != NULL) {
|
||||
free(array->elements);
|
||||
array->elements = NULL;
|
||||
array->count = 0;
|
||||
}
|
||||
|
||||
if (array->buff != NULL) {
|
||||
free(array->buff);
|
||||
array->buff = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int encode_json_array(string_array_t *array, string_t *output,
|
||||
char *error_info, const int error_size)
|
||||
{
|
||||
string_t *el;
|
||||
string_t *end;
|
||||
char *p;
|
||||
int size;
|
||||
|
||||
end = array->elements + array->count;
|
||||
size = 3;
|
||||
for (el=array->elements; el<end; el++) {
|
||||
size += el->len + 3;
|
||||
}
|
||||
|
||||
output->str = (char *)malloc(size);
|
||||
if (output->str == NULL) {
|
||||
snprintf(error_info, error_size, "malloc %d bytes fail", size);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
p = output->str;
|
||||
*p++ = '[';
|
||||
output->len = 1;
|
||||
for (el=array->elements; el<end; el++) {
|
||||
if (el > array->elements) {
|
||||
*p++ = ',';
|
||||
output->len++;
|
||||
}
|
||||
|
||||
*p++ = '"';
|
||||
memcpy(p, el->str, el->len);
|
||||
p += el->len;
|
||||
*p++ = '"';
|
||||
output->len += el->len + 2;
|
||||
}
|
||||
|
||||
*p++ = ']';
|
||||
*p = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
//json_parser.h
|
||||
|
||||
#ifndef _JSON_PARSER_H
|
||||
#define _JSON_PARSER_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "common_define.h"
|
||||
|
||||
#define FC_JSON_TYPE_STRING 1
|
||||
#define FC_JSON_TYPE_ARRAY 2
|
||||
#define FC_JSON_TYPE_MAP 3
|
||||
|
||||
typedef struct
|
||||
{
|
||||
string_t *elements;
|
||||
int count;
|
||||
|
||||
int alloc; //for internal use
|
||||
char *buff; //for internal use
|
||||
} string_array_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int detect_json_type(const string_t *input);
|
||||
|
||||
int decode_json_array(const string_t *input, string_array_t *array,
|
||||
char *error_info, const int error_size);
|
||||
|
||||
int encode_json_array(string_array_t *array, string_t *output,
|
||||
char *error_info, const int error_size);
|
||||
|
||||
void free_json_array(string_array_t *array);
|
||||
|
||||
static inline void free_json_string(string_t *buffer)
|
||||
{
|
||||
if (buffer->str != NULL) {
|
||||
free(buffer->str);
|
||||
buffer->str = NULL;
|
||||
buffer->len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -6,7 +6,8 @@ LIB_PATH = -lfastcommon -lpthread
|
|||
|
||||
ALL_PRGS = test_allocator test_skiplist test_multi_skiplist test_mblock test_blocked_queue \
|
||||
test_id_generator test_ini_parser test_char_convert test_char_convert_loader \
|
||||
test_logger test_skiplist_set test_crc32 test_thourands_seperator test_sched_thread
|
||||
test_logger test_skiplist_set test_crc32 test_thourands_seperator test_sched_thread \
|
||||
test_json_parser
|
||||
|
||||
all: $(ALL_PRGS)
|
||||
.c:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include "fastcommon/logger.h"
|
||||
#include "fastcommon/shared_func.h"
|
||||
#include "fastcommon/json_parser.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int result;
|
||||
int json_type;
|
||||
char error_info[256];
|
||||
string_t input;
|
||||
string_t output;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage: %s <json_string | json_array | json_map>\n",
|
||||
argv[0]);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
log_init();
|
||||
|
||||
input.str = argv[1];
|
||||
input.len = strlen(input.str);
|
||||
json_type = detect_json_type(&input);
|
||||
if (json_type == FC_JSON_TYPE_ARRAY) {
|
||||
string_array_t array;
|
||||
|
||||
if ((result=decode_json_array(&input, &array, error_info,
|
||||
sizeof(error_info))) != 0)
|
||||
{
|
||||
fprintf(stderr, "decode json array fail, %s\n", error_info);
|
||||
return result;
|
||||
}
|
||||
|
||||
if ((result=encode_json_array(&array, &output,
|
||||
error_info, sizeof(error_info))) != 0)
|
||||
{
|
||||
fprintf(stderr, "encode json array fail, %s\n", error_info);
|
||||
return result;
|
||||
}
|
||||
|
||||
printf("%s\n", output.str);
|
||||
free_json_string(&output);
|
||||
free_json_array(&array);
|
||||
} else if (json_type == FC_JSON_TYPE_MAP) {
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue