From 1bbc726f7549692ad09bd6056bd27b8a0df1efaf Mon Sep 17 00:00:00 2001 From: "Ryan M. Lederman" Date: Tue, 5 Jun 2018 20:10:09 -0600 Subject: [PATCH 1/7] add json_strerror, json_perror. disable with JSON_NO_ERRORMSG --- README.md | 10 ++++++++-- json.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ json.h | 18 ++++++++++++++++-- 3 files changed, 69 insertions(+), 4 deletions(-) mode change 100644 => 100755 README.md mode change 100644 => 100755 json.c mode change 100644 => 100755 json.h diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 4b356fa..c7a88fa --- a/README.md +++ b/README.md @@ -76,15 +76,17 @@ The parser API is really simple, totaling only 5 API calls: * json\_parser\_string * json\_parser\_is\_done * json\_parser\_free + * json\_strerror + * json\_perror json\_parser\_init initializes a new parser context from a parser config and takes a callback + userdata. This callback function is used everything the parser need to communicate a type and value to the client side of the library. json\_parser\_char take one character and inject it in the parser. on parsing -success it will return a 0 value, but on parsing error it returns a parsing +success it will return a 0 value (JSON\_SUCCESS), but on parsing error it returns a parsing error that represents the type of the error encounters. see JSON\_ERROR\_\* -for the full set of return values. +for the full set of return values and json\_strerror for message retrieval. json\_parser\_string is similar to json\_parser\_char except that it takes a string and a length. it also returns the number of character processed, which is @@ -95,6 +97,10 @@ terminated state. it involves not beeing into any structure. json\_parser\_free is the opposite of init, it just free the allocated structure. +json\_strerror gives an error message if any other function returns non-zero. + +json\_perror prints an error message to stderr. + The Printer API --------------- diff --git a/json.c b/json.c old mode 100644 new mode 100755 index dca52bb..53e37ed --- a/json.c +++ b/json.c @@ -19,6 +19,7 @@ */ #include +#include #include #include #include "json.h" @@ -974,6 +975,50 @@ int json_print_args(json_printer *printer, return ret; } +#ifndef JSON_NO_ERRORMSG +const char* json_strerror(int err) +{ + switch (err) + { + case JSON_SUCCESS: + return "the operation completed successfully"; + case JSON_ERROR_NO_MEMORY: + return "out of memory"; + case JSON_ERROR_BAD_CHAR: + return "non-printable character encountered"; + case JSON_ERROR_POP_EMPTY: + return "stack is empty; can't pop"; + case JSON_ERROR_POP_UNEXPECTED_MODE: + return "bad type requested for stack pop"; + case JSON_ERROR_NESTING_LIMIT: + return "stack nesting limit reached"; + case JSON_ERROR_DATA_LIMIT: + return "buffer is full"; + case JSON_ERROR_COMMENT_NOT_ALLOWED: + return "comments not supported by the configuration"; + case JSON_ERROR_UNEXPECTED_CHAR: + return "unexpected character encountered"; + case JSON_ERROR_UNICODE_MISSING_LOW_SURROGATE: + return "UTF low surrogate missing after high surrogate"; + case JSON_ERROR_UNICODE_UNEXPECTED_LOW_SURROGATE: + return "unexpected UTF low surrogate without preceding high surrogate"; + case JSON_ERROR_COMMA_OUT_OF_STRUCTURE: + return "unexpected comma encountered"; + case JSON_ERROR_CALLBACK: + return "callback returned an error code"; + case JSON_ERROR_UTF8: + return "invalid UTF stream encountered"; + default: + return ""; + } +} + +void json_perror(int err) +{ + fputs(json_strerror(err), stderr); +} +#endif /* !JSON_NO_ERRORMSG */ + static int dom_push(struct json_parser_dom *ctx, void *val) { if (ctx->stack_offset == ctx->stack_size) { diff --git a/json.h b/json.h old mode 100644 new mode 100755 index 077d35b..03c7cfa --- a/json.h +++ b/json.h @@ -33,7 +33,11 @@ typedef unsigned __int32 uint32_t; #define JSON_MINOR 0 #define JSON_VERSION (JSON_MAJOR * 100 + JSON_MINOR) -typedef enum +// Uncomment to skip inclusion of error message functions +// (json_strerror, json_perror) and string resources. +//#define JSON_NO_ERRORMSG + +typedef enum { JSON_NONE, JSON_ARRAY_BEGIN, @@ -52,7 +56,8 @@ typedef enum typedef enum { - /* SUCCESS = 0 */ + /* no error*/ + JSON_SUCCESS = 0, /* running out of memory */ JSON_ERROR_NO_MEMORY = 1, /* character < 32, except space newline tab */ @@ -177,6 +182,15 @@ int json_print_raw(json_printer *printer, int type, const char *data, uint32_t l * the function call should always be terminated by -1 */ int json_print_args(json_printer *, int (*f)(json_printer *, int, const char *, uint32_t), ...); +#ifndef JSON_NO_ERRORMSG +/** json_strerror returns a human-readable message that corresponds to an error code + * (json_error) returned from any other json_ function. */ +const char* json_strerror(int err); + +/** json_perror prints the message generated by json_strerror to stderr. */ +void json_perror(int err); +#endif /* !JSON_NO_ERRORMSG */ + /** callback from the parser_dom callback to create object and array */ typedef void * (*json_parser_dom_create_structure)(int, int); From 3d0cc724876d7819267faa1a9386d822d73737d5 Mon Sep 17 00:00:00 2001 From: "Ryan M. Lederman" Date: Wed, 6 Jun 2018 09:48:49 -0600 Subject: [PATCH 2/7] tab indentation & permissions --- json.c | 84 +++++++++++++++++++++++++++++----------------------------- json.h | 12 ++++----- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/json.c b/json.c index 53e37ed..401a4d9 100755 --- a/json.c +++ b/json.c @@ -469,7 +469,7 @@ static int decode_unicode_char(json_parser *parser) int offset = parser->buffer_offset; uval = (hex(b[offset - 4]) << 12) | (hex(b[offset - 3]) << 8) - | (hex(b[offset - 2]) << 4) | hex(b[offset - 1]); + | (hex(b[offset - 2]) << 4) | hex(b[offset - 1]); parser->buffer_offset -= 4; @@ -667,7 +667,7 @@ static int do_action(json_parser *parser, int next_state) * return JSON_ERROR_NO_MEMORY if memory allocation failed or SUCCESS. */ int json_parser_init(json_parser *parser, json_config *config, - json_parser_callback callback, void *userdata) + json_parser_callback callback, void *userdata) { memset(parser, 0, sizeof(*parser)); @@ -729,7 +729,7 @@ int json_parser_is_done(json_parser *parser) * the user can supplied a valid processed pointer that will * be fill with the number of processed characters before returning */ int json_parser_string(json_parser *parser, const char *s, - uint32_t length, uint32_t *processed) + uint32_t length, uint32_t *processed) { int ret; int next_class, next_state; @@ -936,8 +936,8 @@ int json_print_raw(json_printer *printer, int type, const char *data, uint32_t l /** json_print_args takes multiple types and pass them to the printer function */ int json_print_args(json_printer *printer, - int (*f)(json_printer *, int, const char *, uint32_t), - ...) + int (*f)(json_printer *, int, const char *, uint32_t), + ...) { va_list ap; char *data; @@ -978,44 +978,44 @@ int json_print_args(json_printer *printer, #ifndef JSON_NO_ERRORMSG const char* json_strerror(int err) { - switch (err) - { - case JSON_SUCCESS: - return "the operation completed successfully"; - case JSON_ERROR_NO_MEMORY: - return "out of memory"; - case JSON_ERROR_BAD_CHAR: - return "non-printable character encountered"; - case JSON_ERROR_POP_EMPTY: - return "stack is empty; can't pop"; - case JSON_ERROR_POP_UNEXPECTED_MODE: - return "bad type requested for stack pop"; - case JSON_ERROR_NESTING_LIMIT: - return "stack nesting limit reached"; - case JSON_ERROR_DATA_LIMIT: - return "buffer is full"; - case JSON_ERROR_COMMENT_NOT_ALLOWED: - return "comments not supported by the configuration"; - case JSON_ERROR_UNEXPECTED_CHAR: - return "unexpected character encountered"; - case JSON_ERROR_UNICODE_MISSING_LOW_SURROGATE: - return "UTF low surrogate missing after high surrogate"; - case JSON_ERROR_UNICODE_UNEXPECTED_LOW_SURROGATE: - return "unexpected UTF low surrogate without preceding high surrogate"; - case JSON_ERROR_COMMA_OUT_OF_STRUCTURE: - return "unexpected comma encountered"; - case JSON_ERROR_CALLBACK: - return "callback returned an error code"; - case JSON_ERROR_UTF8: - return "invalid UTF stream encountered"; - default: - return ""; - } + switch (err) + { + case JSON_SUCCESS: + return "the operation completed successfully"; + case JSON_ERROR_NO_MEMORY: + return "out of memory"; + case JSON_ERROR_BAD_CHAR: + return "non-printable character encountered"; + case JSON_ERROR_POP_EMPTY: + return "stack is empty; can't pop"; + case JSON_ERROR_POP_UNEXPECTED_MODE: + return "bad type requested for stack pop"; + case JSON_ERROR_NESTING_LIMIT: + return "stack nesting limit reached"; + case JSON_ERROR_DATA_LIMIT: + return "buffer is full"; + case JSON_ERROR_COMMENT_NOT_ALLOWED: + return "comments not supported by the configuration"; + case JSON_ERROR_UNEXPECTED_CHAR: + return "unexpected character encountered"; + case JSON_ERROR_UNICODE_MISSING_LOW_SURROGATE: + return "UTF low surrogate missing after high surrogate"; + case JSON_ERROR_UNICODE_UNEXPECTED_LOW_SURROGATE: + return "unexpected UTF low surrogate without preceding high surrogate"; + case JSON_ERROR_COMMA_OUT_OF_STRUCTURE: + return "unexpected comma encountered"; + case JSON_ERROR_CALLBACK: + return "callback returned an error code"; + case JSON_ERROR_UTF8: + return "invalid UTF stream encountered"; + default: + return ""; + } } void json_perror(int err) { - fputs(json_strerror(err), stderr); + fputs(json_strerror(err), stderr); } #endif /* !JSON_NO_ERRORMSG */ @@ -1045,9 +1045,9 @@ static int dom_pop(struct json_parser_dom *ctx, void **val) } int json_parser_dom_init(json_parser_dom *dom, - json_parser_dom_create_structure create_structure, - json_parser_dom_create_data create_data, - json_parser_dom_append append) + json_parser_dom_create_structure create_structure, + json_parser_dom_create_data create_data, + json_parser_dom_append append) { memset(dom, 0, sizeof(*dom)); dom->stack_size = 1024; diff --git a/json.h b/json.h index 03c7cfa..c2ae591 100755 --- a/json.h +++ b/json.h @@ -57,7 +57,7 @@ typedef enum typedef enum { /* no error*/ - JSON_SUCCESS = 0, + JSON_SUCCESS = 0, /* running out of memory */ JSON_ERROR_NO_MEMORY = 1, /* character < 32, except space newline tab */ @@ -143,7 +143,7 @@ typedef struct json_printer { * a config and its userdata. * return JSON_ERROR_NO_MEMORY if memory allocation failed or SUCCESS. */ int json_parser_init(json_parser *parser, json_config *cfg, - json_parser_callback callback, void *userdata); + json_parser_callback callback, void *userdata); /** json_parser_free freed memory structure allocated by the parser */ int json_parser_free(json_parser *parser); @@ -153,7 +153,7 @@ int json_parser_free(json_parser *parser); * the user can supplied a valid processed pointer that will * be fill with the number of processed characters before returning */ int json_parser_string(json_parser *parser, const char *string, - uint32_t length, uint32_t *processed); + uint32_t length, uint32_t *processed); /** json_parser_char append one single char to the parser * return 0 if everything went ok, a JSON_ERROR_* otherwise */ @@ -225,9 +225,9 @@ typedef struct json_parser_dom /** initialize a parser dom structure with the necessary callbacks */ int json_parser_dom_init(json_parser_dom *helper, - json_parser_dom_create_structure create_structure, - json_parser_dom_create_data create_data, - json_parser_dom_append append); + json_parser_dom_create_structure create_structure, + json_parser_dom_create_data create_data, + json_parser_dom_append append); /** free memory allocated by the DOM callback helper */ int json_parser_dom_free(json_parser_dom *ctx); From b6c5c0137edbcd881b045942a16b1fa9dab5719a Mon Sep 17 00:00:00 2001 From: "Ryan M. Lederman" Date: Wed, 6 Jun 2018 10:43:39 -0600 Subject: [PATCH 3/7] don't use vscode for indentation; you'll have a bad time. --- json.c | 66 +++++++++++++++++++++++++++++----------------------------- json.h | 2 +- 2 files changed, 34 insertions(+), 34 deletions(-) mode change 100755 => 100644 json.c mode change 100755 => 100644 json.h diff --git a/json.c b/json.c old mode 100755 new mode 100644 index 53e37ed..c59bc62 --- a/json.c +++ b/json.c @@ -978,44 +978,44 @@ int json_print_args(json_printer *printer, #ifndef JSON_NO_ERRORMSG const char* json_strerror(int err) { - switch (err) - { - case JSON_SUCCESS: - return "the operation completed successfully"; - case JSON_ERROR_NO_MEMORY: - return "out of memory"; - case JSON_ERROR_BAD_CHAR: - return "non-printable character encountered"; - case JSON_ERROR_POP_EMPTY: - return "stack is empty; can't pop"; - case JSON_ERROR_POP_UNEXPECTED_MODE: - return "bad type requested for stack pop"; - case JSON_ERROR_NESTING_LIMIT: - return "stack nesting limit reached"; - case JSON_ERROR_DATA_LIMIT: - return "buffer is full"; - case JSON_ERROR_COMMENT_NOT_ALLOWED: - return "comments not supported by the configuration"; - case JSON_ERROR_UNEXPECTED_CHAR: - return "unexpected character encountered"; - case JSON_ERROR_UNICODE_MISSING_LOW_SURROGATE: - return "UTF low surrogate missing after high surrogate"; - case JSON_ERROR_UNICODE_UNEXPECTED_LOW_SURROGATE: - return "unexpected UTF low surrogate without preceding high surrogate"; - case JSON_ERROR_COMMA_OUT_OF_STRUCTURE: - return "unexpected comma encountered"; - case JSON_ERROR_CALLBACK: - return "callback returned an error code"; - case JSON_ERROR_UTF8: - return "invalid UTF stream encountered"; - default: - return ""; + switch (err) + { + case JSON_SUCCESS: + return "the operation completed successfully"; + case JSON_ERROR_NO_MEMORY: + return "out of memory"; + case JSON_ERROR_BAD_CHAR: + return "non-printable character encountered"; + case JSON_ERROR_POP_EMPTY: + return "stack is empty; can't pop"; + case JSON_ERROR_POP_UNEXPECTED_MODE: + return "bad type requested for stack pop"; + case JSON_ERROR_NESTING_LIMIT: + return "stack nesting limit reached"; + case JSON_ERROR_DATA_LIMIT: + return "buffer is full"; + case JSON_ERROR_COMMENT_NOT_ALLOWED: + return "comments not supported by the configuration"; + case JSON_ERROR_UNEXPECTED_CHAR: + return "unexpected character encountered"; + case JSON_ERROR_UNICODE_MISSING_LOW_SURROGATE: + return "UTF low surrogate missing after high surrogate"; + case JSON_ERROR_UNICODE_UNEXPECTED_LOW_SURROGATE: + return "unexpected UTF low surrogate without preceding high surrogate"; + case JSON_ERROR_COMMA_OUT_OF_STRUCTURE: + return "unexpected comma encountered"; + case JSON_ERROR_CALLBACK: + return "callback returned an error code"; + case JSON_ERROR_UTF8: + return "invalid UTF stream encountered"; + default: + return ""; } } void json_perror(int err) { - fputs(json_strerror(err), stderr); + fputs(json_strerror(err), stderr); } #endif /* !JSON_NO_ERRORMSG */ diff --git a/json.h b/json.h old mode 100755 new mode 100644 index 03c7cfa..f040289 --- a/json.h +++ b/json.h @@ -57,7 +57,7 @@ typedef enum typedef enum { /* no error*/ - JSON_SUCCESS = 0, + JSON_SUCCESS = 0, /* running out of memory */ JSON_ERROR_NO_MEMORY = 1, /* character < 32, except space newline tab */ From b5d8a02910f1333e8ca64f21f6087d5affa0ccb7 Mon Sep 17 00:00:00 2001 From: "Ryan M. Lederman" Date: Wed, 6 Jun 2018 11:05:52 -0600 Subject: [PATCH 4/7] le sigh. --- json.c | 16 ++++++++-------- json.h | 18 ++---------------- 2 files changed, 10 insertions(+), 24 deletions(-) diff --git a/json.c b/json.c index 7f9c201..6e41758 100644 --- a/json.c +++ b/json.c @@ -469,7 +469,7 @@ static int decode_unicode_char(json_parser *parser) int offset = parser->buffer_offset; uval = (hex(b[offset - 4]) << 12) | (hex(b[offset - 3]) << 8) - | (hex(b[offset - 2]) << 4) | hex(b[offset - 1]); + | (hex(b[offset - 2]) << 4) | hex(b[offset - 1]); parser->buffer_offset -= 4; @@ -667,7 +667,7 @@ static int do_action(json_parser *parser, int next_state) * return JSON_ERROR_NO_MEMORY if memory allocation failed or SUCCESS. */ int json_parser_init(json_parser *parser, json_config *config, - json_parser_callback callback, void *userdata) + json_parser_callback callback, void *userdata) { memset(parser, 0, sizeof(*parser)); @@ -729,7 +729,7 @@ int json_parser_is_done(json_parser *parser) * the user can supplied a valid processed pointer that will * be fill with the number of processed characters before returning */ int json_parser_string(json_parser *parser, const char *s, - uint32_t length, uint32_t *processed) + uint32_t length, uint32_t *processed) { int ret; int next_class, next_state; @@ -936,8 +936,8 @@ int json_print_raw(json_printer *printer, int type, const char *data, uint32_t l /** json_print_args takes multiple types and pass them to the printer function */ int json_print_args(json_printer *printer, - int (*f)(json_printer *, int, const char *, uint32_t), - ...) + int (*f)(json_printer *, int, const char *, uint32_t), + ...) { va_list ap; char *data; @@ -1044,9 +1044,9 @@ static int dom_pop(struct json_parser_dom *ctx, void **val) } int json_parser_dom_init(json_parser_dom *dom, - json_parser_dom_create_structure create_structure, - json_parser_dom_create_data create_data, - json_parser_dom_append append) + json_parser_dom_create_structure create_structure, + json_parser_dom_create_data create_data, + json_parser_dom_append append) { memset(dom, 0, sizeof(*dom)); dom->stack_size = 1024; diff --git a/json.h b/json.h index c2ae591..17bfc08 100644 --- a/json.h +++ b/json.h @@ -33,11 +33,7 @@ typedef unsigned __int32 uint32_t; #define JSON_MINOR 0 #define JSON_VERSION (JSON_MAJOR * 100 + JSON_MINOR) -// Uncomment to skip inclusion of error message functions -// (json_strerror, json_perror) and string resources. -//#define JSON_NO_ERRORMSG - -typedef enum +typedef enum { JSON_NONE, JSON_ARRAY_BEGIN, @@ -56,8 +52,7 @@ typedef enum typedef enum { - /* no error*/ - JSON_SUCCESS = 0, + /* SUCCESS = 0 */ /* running out of memory */ JSON_ERROR_NO_MEMORY = 1, /* character < 32, except space newline tab */ @@ -182,15 +177,6 @@ int json_print_raw(json_printer *printer, int type, const char *data, uint32_t l * the function call should always be terminated by -1 */ int json_print_args(json_printer *, int (*f)(json_printer *, int, const char *, uint32_t), ...); -#ifndef JSON_NO_ERRORMSG -/** json_strerror returns a human-readable message that corresponds to an error code - * (json_error) returned from any other json_ function. */ -const char* json_strerror(int err); - -/** json_perror prints the message generated by json_strerror to stderr. */ -void json_perror(int err); -#endif /* !JSON_NO_ERRORMSG */ - /** callback from the parser_dom callback to create object and array */ typedef void * (*json_parser_dom_create_structure)(int, int); From 47b2d4366cd9baab441b60483d6a9f0f2f0204b2 Mon Sep 17 00:00:00 2001 From: "Ryan M. Lederman" Date: Wed, 6 Jun 2018 11:13:37 -0600 Subject: [PATCH 5/7] some indentation was with spaces, not tabs --- json.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/json.h b/json.h index 17bfc08..077d35b 100644 --- a/json.h +++ b/json.h @@ -138,7 +138,7 @@ typedef struct json_printer { * a config and its userdata. * return JSON_ERROR_NO_MEMORY if memory allocation failed or SUCCESS. */ int json_parser_init(json_parser *parser, json_config *cfg, - json_parser_callback callback, void *userdata); + json_parser_callback callback, void *userdata); /** json_parser_free freed memory structure allocated by the parser */ int json_parser_free(json_parser *parser); @@ -148,7 +148,7 @@ int json_parser_free(json_parser *parser); * the user can supplied a valid processed pointer that will * be fill with the number of processed characters before returning */ int json_parser_string(json_parser *parser, const char *string, - uint32_t length, uint32_t *processed); + uint32_t length, uint32_t *processed); /** json_parser_char append one single char to the parser * return 0 if everything went ok, a JSON_ERROR_* otherwise */ @@ -211,9 +211,9 @@ typedef struct json_parser_dom /** initialize a parser dom structure with the necessary callbacks */ int json_parser_dom_init(json_parser_dom *helper, - json_parser_dom_create_structure create_structure, - json_parser_dom_create_data create_data, - json_parser_dom_append append); + json_parser_dom_create_structure create_structure, + json_parser_dom_create_data create_data, + json_parser_dom_append append); /** free memory allocated by the DOM callback helper */ int json_parser_dom_free(json_parser_dom *ctx); From 9f67468d955ebc43f5645b10568989e3968d621c Mon Sep 17 00:00:00 2001 From: "Ryan M. Lederman" Date: Wed, 6 Jun 2018 11:18:19 -0600 Subject: [PATCH 6/7] re-add changes --- json.c | 1 + json.h | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/json.c b/json.c index 6e41758..d4c8897 100644 --- a/json.c +++ b/json.c @@ -1010,6 +1010,7 @@ const char* json_strerror(int err) return "invalid UTF stream encountered"; default: return ""; + } } void json_perror(int err) diff --git a/json.h b/json.h index 077d35b..f040289 100644 --- a/json.h +++ b/json.h @@ -33,7 +33,11 @@ typedef unsigned __int32 uint32_t; #define JSON_MINOR 0 #define JSON_VERSION (JSON_MAJOR * 100 + JSON_MINOR) -typedef enum +// Uncomment to skip inclusion of error message functions +// (json_strerror, json_perror) and string resources. +//#define JSON_NO_ERRORMSG + +typedef enum { JSON_NONE, JSON_ARRAY_BEGIN, @@ -52,7 +56,8 @@ typedef enum typedef enum { - /* SUCCESS = 0 */ + /* no error*/ + JSON_SUCCESS = 0, /* running out of memory */ JSON_ERROR_NO_MEMORY = 1, /* character < 32, except space newline tab */ @@ -177,6 +182,15 @@ int json_print_raw(json_printer *printer, int type, const char *data, uint32_t l * the function call should always be terminated by -1 */ int json_print_args(json_printer *, int (*f)(json_printer *, int, const char *, uint32_t), ...); +#ifndef JSON_NO_ERRORMSG +/** json_strerror returns a human-readable message that corresponds to an error code + * (json_error) returned from any other json_ function. */ +const char* json_strerror(int err); + +/** json_perror prints the message generated by json_strerror to stderr. */ +void json_perror(int err); +#endif /* !JSON_NO_ERRORMSG */ + /** callback from the parser_dom callback to create object and array */ typedef void * (*json_parser_dom_create_structure)(int, int); From 4cca5df826d442c67624ca8bf737450a34018aaf Mon Sep 17 00:00:00 2001 From: "Ryan M. Lederman" Date: Wed, 6 Jun 2018 11:22:29 -0600 Subject: [PATCH 7/7] fix permissions on README --- README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 README.md diff --git a/README.md b/README.md old mode 100755 new mode 100644