9191#define DEFAULT_DECODE_ARRAY_WITH_ARRAY_MT 0
9292#define DEFAULT_ENCODE_ESCAPE_FORWARD_SLASH 1
9393#define DEFAULT_ENCODE_SKIP_UNSUPPORTED_VALUE_TYPES 0
94+ #define DEFAULT_ENCODE_INDENT NULL
9495
9596#ifdef DISABLE_INVALID_NUMBERS
9697#undef DEFAULT_DECODE_INVALID_NUMBERS
@@ -172,6 +173,7 @@ typedef struct {
172173 int encode_keep_buffer ;
173174 int encode_empty_table_as_object ;
174175 int encode_escape_forward_slash ;
176+ const char * encode_indent ;
175177
176178 int decode_invalid_numbers ;
177179 int decode_max_depth ;
@@ -310,6 +312,18 @@ static int json_enum_option(lua_State *l, int optindex, int *setting,
310312 return 1 ;
311313}
312314
315+ /* Process string option for a configuration function */
316+ static int json_string_option (lua_State * l , int optindex , const char * * setting )
317+ {
318+ if (!lua_isnil (l , optindex )) {
319+ const char * value = luaL_checkstring (l , optindex );
320+ * setting = value ;
321+ }
322+
323+ lua_pushstring (l , * setting ? * setting : "" );
324+ return 1 ;
325+ }
326+
313327/* Configures handling of extremely sparse arrays:
314328 * convert: Convert extremely sparse arrays into objects? Otherwise error.
315329 * ratio: 0: always allow sparse; 1: never allow sparse; >1: use ratio
@@ -400,6 +414,39 @@ static int json_cfg_encode_keep_buffer(lua_State *l)
400414 return 1 ;
401415}
402416
417+ /* Returns nonzero if the string consists only of allowed whitespace characters */
418+ static int is_allowed_ws (const char * s ) {
419+ if (!s ) return 0 ;
420+ for (const unsigned char * p = (const unsigned char * )s ; * p ; p ++ ) {
421+ switch (* p ) {
422+ case 0x20 : /* space */
423+ case 0x09 : /* tab */
424+ case 0x0A : /* newline */
425+ case 0x0D : /* carriage return */
426+ break ;
427+ default :
428+ return 0 ;
429+ }
430+ }
431+ return 1 ;
432+ }
433+
434+ /* Configure how to indent output */
435+ static int json_cfg_encode_indent (lua_State * l )
436+ {
437+ json_config_t * cfg = json_arg_init (l , 1 );
438+
439+ const char * indent = cfg -> encode_indent ;
440+ json_string_option (l , 1 , & indent );
441+ if (indent [0 ] == '\0' ) indent = NULL ;
442+ else if (!is_allowed_ws (indent )) {
443+ luaL_argerror (l , 1 , "indent must contain only spaces, tabs, line feeds, or carriage returns" );
444+ }
445+ cfg -> encode_indent = indent ;
446+
447+ return 1 ;
448+ }
449+
403450#if defined(DISABLE_INVALID_NUMBERS ) && !defined(USE_INTERNAL_FPCONV )
404451void json_verify_invalid_number_setting (lua_State * l , int * setting )
405452{
@@ -491,6 +538,7 @@ static void json_create_config(lua_State *l)
491538 cfg -> decode_array_with_array_mt = DEFAULT_DECODE_ARRAY_WITH_ARRAY_MT ;
492539 cfg -> encode_escape_forward_slash = DEFAULT_ENCODE_ESCAPE_FORWARD_SLASH ;
493540 cfg -> encode_skip_unsupported_value_types = DEFAULT_ENCODE_SKIP_UNSUPPORTED_VALUE_TYPES ;
541+ cfg -> encode_indent = DEFAULT_ENCODE_INDENT ;
494542
495543#if DEFAULT_ENCODE_KEEP_BUFFER > 0
496544 strbuf_init (& cfg -> encode_buf , 0 );
@@ -660,6 +708,13 @@ static void json_check_encode_depth(lua_State *l, json_config_t *cfg,
660708static int json_append_data (lua_State * l , json_config_t * cfg ,
661709 int current_depth , strbuf_t * json );
662710
711+ static void json_append_newline_and_indent (strbuf_t * json , json_config_t * cfg , int depth )
712+ {
713+ strbuf_append_char (json , '\n' );
714+ for (int i = 0 ; i < depth ; i ++ )
715+ strbuf_append_string (json , cfg -> encode_indent );
716+ }
717+
663718/* json_append_array args:
664719 * - lua_State
665720 * - JSON strbuf
@@ -668,15 +723,21 @@ static void json_append_array(lua_State *l, json_config_t *cfg, int current_dept
668723 strbuf_t * json , int array_length , int raw )
669724{
670725 int comma , i , json_pos , err ;
726+ int has_items = 0 ;
671727
672728 strbuf_append_char (json , '[' );
673729
674730 comma = 0 ;
675731 for (i = 1 ; i <= array_length ; i ++ ) {
732+ has_items = 1 ;
733+
676734 json_pos = strbuf_length (json );
677735 if (comma ++ > 0 )
678736 strbuf_append_char (json , ',' );
679737
738+ if (cfg -> encode_indent )
739+ json_append_newline_and_indent (json , cfg , current_depth );
740+
680741 if (raw ) {
681742 lua_rawgeti (l , -1 , i );
682743 } else {
@@ -698,6 +759,9 @@ static void json_append_array(lua_State *l, json_config_t *cfg, int current_dept
698759 lua_pop (l , 1 );
699760 }
700761
762+ if (has_items && cfg -> encode_indent )
763+ json_append_newline_and_indent (json , cfg , current_depth - 1 );
764+
701765 strbuf_append_char (json , ']' );
702766}
703767
@@ -752,6 +816,7 @@ static void json_append_object(lua_State *l, json_config_t *cfg,
752816 int current_depth , strbuf_t * json )
753817{
754818 int comma , keytype , json_pos , err ;
819+ int has_items = 0 ;
755820
756821 /* Object */
757822 strbuf_append_char (json , '{' );
@@ -760,10 +825,15 @@ static void json_append_object(lua_State *l, json_config_t *cfg,
760825 /* table, startkey */
761826 comma = 0 ;
762827 while (lua_next (l , -2 ) != 0 ) {
828+ has_items = 1 ;
829+
763830 json_pos = strbuf_length (json );
764831 if (comma ++ > 0 )
765832 strbuf_append_char (json , ',' );
766833
834+ if (cfg -> encode_indent )
835+ json_append_newline_and_indent (json , cfg , current_depth );
836+
767837 /* table, key, value */
768838 keytype = lua_type (l , -2 );
769839 if (keytype == LUA_TNUMBER ) {
@@ -778,6 +848,9 @@ static void json_append_object(lua_State *l, json_config_t *cfg,
778848 "table key must be a number or string" );
779849 /* never returns */
780850 }
851+ if (cfg -> encode_indent )
852+ strbuf_append_char (json , ' ' );
853+
781854
782855 /* table, key, value */
783856 err = json_append_data (l , cfg , current_depth , json );
@@ -792,6 +865,9 @@ static void json_append_object(lua_State *l, json_config_t *cfg,
792865 /* table, key */
793866 }
794867
868+ if (has_items && cfg -> encode_indent )
869+ json_append_newline_and_indent (json , cfg , current_depth - 1 );
870+
795871 strbuf_append_char (json , '}' );
796872}
797873
@@ -1571,6 +1647,7 @@ static int lua_cjson_new(lua_State *l)
15711647 { "decode_invalid_numbers" , json_cfg_decode_invalid_numbers },
15721648 { "encode_escape_forward_slash" , json_cfg_encode_escape_forward_slash },
15731649 { "encode_skip_unsupported_value_types" , json_cfg_encode_skip_unsupported_value_types },
1650+ { "encode_indent" , json_cfg_encode_indent },
15741651 { "new" , lua_cjson_new },
15751652 { NULL , NULL }
15761653 };
0 commit comments