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,40 @@ 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+
450+
403451#if defined(DISABLE_INVALID_NUMBERS ) && !defined(USE_INTERNAL_FPCONV )
404452void json_verify_invalid_number_setting (lua_State * l , int * setting )
405453{
@@ -491,6 +539,7 @@ static void json_create_config(lua_State *l)
491539 cfg -> decode_array_with_array_mt = DEFAULT_DECODE_ARRAY_WITH_ARRAY_MT ;
492540 cfg -> encode_escape_forward_slash = DEFAULT_ENCODE_ESCAPE_FORWARD_SLASH ;
493541 cfg -> encode_skip_unsupported_value_types = DEFAULT_ENCODE_SKIP_UNSUPPORTED_VALUE_TYPES ;
542+ cfg -> encode_indent = DEFAULT_ENCODE_INDENT ;
494543
495544#if DEFAULT_ENCODE_KEEP_BUFFER > 0
496545 strbuf_init (& cfg -> encode_buf , 0 );
@@ -660,6 +709,13 @@ static void json_check_encode_depth(lua_State *l, json_config_t *cfg,
660709static int json_append_data (lua_State * l , json_config_t * cfg ,
661710 int current_depth , strbuf_t * json );
662711
712+ static void json_append_newline_and_indent (strbuf_t * json , json_config_t * cfg , int depth )
713+ {
714+ strbuf_append_char (json , '\n' );
715+ for (int i = 0 ; i < depth ; i ++ )
716+ strbuf_append_string (json , cfg -> encode_indent );
717+ }
718+
663719/* json_append_array args:
664720 * - lua_State
665721 * - JSON strbuf
@@ -668,15 +724,21 @@ static void json_append_array(lua_State *l, json_config_t *cfg, int current_dept
668724 strbuf_t * json , int array_length , int raw )
669725{
670726 int comma , i , json_pos , err ;
727+ int has_items = 0 ;
671728
672729 strbuf_append_char (json , '[' );
673730
674731 comma = 0 ;
675732 for (i = 1 ; i <= array_length ; i ++ ) {
733+ has_items = 1 ;
734+
676735 json_pos = strbuf_length (json );
677736 if (comma ++ > 0 )
678737 strbuf_append_char (json , ',' );
679738
739+ if (cfg -> encode_indent )
740+ json_append_newline_and_indent (json , cfg , current_depth );
741+
680742 if (raw ) {
681743 lua_rawgeti (l , -1 , i );
682744 } else {
@@ -698,6 +760,9 @@ static void json_append_array(lua_State *l, json_config_t *cfg, int current_dept
698760 lua_pop (l , 1 );
699761 }
700762
763+ if (has_items && cfg -> encode_indent )
764+ json_append_newline_and_indent (json , cfg , current_depth - 1 );
765+
701766 strbuf_append_char (json , ']' );
702767}
703768
@@ -752,6 +817,7 @@ static void json_append_object(lua_State *l, json_config_t *cfg,
752817 int current_depth , strbuf_t * json )
753818{
754819 int comma , keytype , json_pos , err ;
820+ int has_items = 0 ;
755821
756822 /* Object */
757823 strbuf_append_char (json , '{' );
@@ -760,10 +826,15 @@ static void json_append_object(lua_State *l, json_config_t *cfg,
760826 /* table, startkey */
761827 comma = 0 ;
762828 while (lua_next (l , -2 ) != 0 ) {
829+ has_items = 1 ;
830+
763831 json_pos = strbuf_length (json );
764832 if (comma ++ > 0 )
765833 strbuf_append_char (json , ',' );
766834
835+ if (cfg -> encode_indent )
836+ json_append_newline_and_indent (json , cfg , current_depth );
837+
767838 /* table, key, value */
768839 keytype = lua_type (l , -2 );
769840 if (keytype == LUA_TNUMBER ) {
@@ -778,6 +849,9 @@ static void json_append_object(lua_State *l, json_config_t *cfg,
778849 "table key must be a number or string" );
779850 /* never returns */
780851 }
852+ if (cfg -> encode_indent )
853+ strbuf_append_char (json , ' ' );
854+
781855
782856 /* table, key, value */
783857 err = json_append_data (l , cfg , current_depth , json );
@@ -792,6 +866,9 @@ static void json_append_object(lua_State *l, json_config_t *cfg,
792866 /* table, key */
793867 }
794868
869+ if (has_items && cfg -> encode_indent )
870+ json_append_newline_and_indent (json , cfg , current_depth - 1 );
871+
795872 strbuf_append_char (json , '}' );
796873}
797874
@@ -1571,6 +1648,7 @@ static int lua_cjson_new(lua_State *l)
15711648 { "decode_invalid_numbers" , json_cfg_decode_invalid_numbers },
15721649 { "encode_escape_forward_slash" , json_cfg_encode_escape_forward_slash },
15731650 { "encode_skip_unsupported_value_types" , json_cfg_encode_skip_unsupported_value_types },
1651+ { "encode_indent" , json_cfg_encode_indent },
15741652 { "new" , lua_cjson_new },
15751653 { NULL , NULL }
15761654 };
0 commit comments