add json_parser.[hc] for parse json array and map

pull/37/head
yuqing 2018-08-22 10:35:33 +08:00
parent 94741c51c2
commit 827fc115e2
6 changed files with 388 additions and 5 deletions

View File

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

View File

@ -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)

270
src/json_parser.c Normal file
View File

@ -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;
}

53
src/json_parser.h Normal file
View File

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

View File

@ -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:

View File

@ -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;
}