aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorskewb1k <skewb1kunix@gmail.com>2026-01-19 08:51:57 +0800
committerGitHub <noreply@github.com>2026-01-19 08:51:57 +0800
commitea05d06f5a56d94d423fc697561a33ca3b8bf085 (patch)
tree48fbfc307052ed233b9ccf0b39ee569b3467d244
parent3c64e2247623a66347a48d66b6a791b58a71fdbe (diff)
downloadlua-cjson-ea05d06f5a56d94d423fc697561a33ca3b8bf085.tar.gz
lua-cjson-ea05d06f5a56d94d423fc697561a33ca3b8bf085.tar.bz2
lua-cjson-ea05d06f5a56d94d423fc697561a33ca3b8bf085.zip
feature: add option to indent encoded output.HEADmaster
Diffstat (limited to '')
-rw-r--r--README.md26
-rw-r--r--lua_cjson.c56
-rwxr-xr-xtests/test.lua38
3 files changed, 120 insertions, 0 deletions
diff --git a/README.md b/README.md
index debe1ae..d2094b1 100644
--- a/README.md
+++ b/README.md
@@ -16,6 +16,7 @@ Table of Contents
16 * [encode_number_precision](#encode_number_precision) 16 * [encode_number_precision](#encode_number_precision)
17 * [encode_escape_forward_slash](#encode_escape_forward_slash) 17 * [encode_escape_forward_slash](#encode_escape_forward_slash)
18 * [encode_skip_unsupported_value_types](#encode_skip_unsupported_value_types) 18 * [encode_skip_unsupported_value_types](#encode_skip_unsupported_value_types)
19 * [encode_indent](#encode_indent)
19 * [decode_array_with_array_mt](#decode_array_with_array_mt) 20 * [decode_array_with_array_mt](#decode_array_with_array_mt)
20 21
21Description 22Description
@@ -201,6 +202,31 @@ This will generate:
201 202
202[Back to TOC](#table-of-contents) 203[Back to TOC](#table-of-contents)
203 204
205encode_indent
206----------------------------
207**syntax:** `cjson.encode_indent(indent)`
208
209If non-empty string provided, JSON values encoded by `cjson.encode()` will be
210formatted in a human-readable way, using `indent` for indentation
211at each nesting level. Also enables newlines and a space after colons.
212
213Example:
214
215```lua
216local cjson = require "cjson"
217
218cjson.encode_indent(" ")
219print(cjson.encode({ a = 1, b = { c = 2 } }))
220-- {
221-- "a": 1,
222-- "b": {
223-- "c": 2
224-- }
225-- }
226```
227
228[Back to TOC](#table-of-contents)
229
204decode_array_with_array_mt 230decode_array_with_array_mt
205-------------------------- 231--------------------------
206**syntax:** `cjson.decode_array_with_array_mt(enabled)` 232**syntax:** `cjson.decode_array_with_array_mt(enabled)`
diff --git a/lua_cjson.c b/lua_cjson.c
index 93b81e6..789817d 100644
--- a/lua_cjson.c
+++ b/lua_cjson.c
@@ -91,6 +91,7 @@
91#define DEFAULT_DECODE_ARRAY_WITH_ARRAY_MT 0 91#define DEFAULT_DECODE_ARRAY_WITH_ARRAY_MT 0
92#define DEFAULT_ENCODE_ESCAPE_FORWARD_SLASH 1 92#define DEFAULT_ENCODE_ESCAPE_FORWARD_SLASH 1
93#define DEFAULT_ENCODE_SKIP_UNSUPPORTED_VALUE_TYPES 0 93#define DEFAULT_ENCODE_SKIP_UNSUPPORTED_VALUE_TYPES 0
94#define DEFAULT_ENCODE_INDENT NULL
94 95
95#ifdef DISABLE_INVALID_NUMBERS 96#ifdef DISABLE_INVALID_NUMBERS
96#undef DEFAULT_DECODE_INVALID_NUMBERS 97#undef DEFAULT_DECODE_INVALID_NUMBERS
@@ -172,6 +173,7 @@ typedef struct {
172 int encode_keep_buffer; 173 int encode_keep_buffer;
173 int encode_empty_table_as_object; 174 int encode_empty_table_as_object;
174 int encode_escape_forward_slash; 175 int encode_escape_forward_slash;
176 const char *encode_indent;
175 177
176 int decode_invalid_numbers; 178 int decode_invalid_numbers;
177 int decode_max_depth; 179 int decode_max_depth;
@@ -310,6 +312,18 @@ static int json_enum_option(lua_State *l, int optindex, int *setting,
310 return 1; 312 return 1;
311} 313}
312 314
315/* Process string option for a configuration function */
316static 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
313/* Configures handling of extremely sparse arrays: 327/* Configures handling of extremely sparse arrays:
314 * convert: Convert extremely sparse arrays into objects? Otherwise error. 328 * convert: Convert extremely sparse arrays into objects? Otherwise error.
315 * ratio: 0: always allow sparse; 1: never allow sparse; >1: use ratio 329 * ratio: 0: always allow sparse; 1: never allow sparse; >1: use ratio
@@ -400,6 +414,18 @@ static int json_cfg_encode_keep_buffer(lua_State *l)
400 return 1; 414 return 1;
401} 415}
402 416
417/* Configure how to indent output */
418static int json_cfg_encode_indent(lua_State *l)
419{
420 json_config_t *cfg = json_arg_init(l, 1);
421
422 json_string_option(l, 1, &cfg->encode_indent);
423 /* simplify further checking */
424 if (cfg->encode_indent[0] == '\0') cfg->encode_indent = NULL;
425
426 return 1;
427}
428
403#if defined(DISABLE_INVALID_NUMBERS) && !defined(USE_INTERNAL_FPCONV) 429#if defined(DISABLE_INVALID_NUMBERS) && !defined(USE_INTERNAL_FPCONV)
404void json_verify_invalid_number_setting(lua_State *l, int *setting) 430void json_verify_invalid_number_setting(lua_State *l, int *setting)
405{ 431{
@@ -491,6 +517,7 @@ static void json_create_config(lua_State *l)
491 cfg->decode_array_with_array_mt = DEFAULT_DECODE_ARRAY_WITH_ARRAY_MT; 517 cfg->decode_array_with_array_mt = DEFAULT_DECODE_ARRAY_WITH_ARRAY_MT;
492 cfg->encode_escape_forward_slash = DEFAULT_ENCODE_ESCAPE_FORWARD_SLASH; 518 cfg->encode_escape_forward_slash = DEFAULT_ENCODE_ESCAPE_FORWARD_SLASH;
493 cfg->encode_skip_unsupported_value_types = DEFAULT_ENCODE_SKIP_UNSUPPORTED_VALUE_TYPES; 519 cfg->encode_skip_unsupported_value_types = DEFAULT_ENCODE_SKIP_UNSUPPORTED_VALUE_TYPES;
520 cfg->encode_indent = DEFAULT_ENCODE_INDENT;
494 521
495#if DEFAULT_ENCODE_KEEP_BUFFER > 0 522#if DEFAULT_ENCODE_KEEP_BUFFER > 0
496 strbuf_init(&cfg->encode_buf, 0); 523 strbuf_init(&cfg->encode_buf, 0);
@@ -660,6 +687,13 @@ static void json_check_encode_depth(lua_State *l, json_config_t *cfg,
660static int json_append_data(lua_State *l, json_config_t *cfg, 687static int json_append_data(lua_State *l, json_config_t *cfg,
661 int current_depth, strbuf_t *json); 688 int current_depth, strbuf_t *json);
662 689
690static void json_append_newline_and_indent(strbuf_t *json, json_config_t *cfg, int depth)
691{
692 strbuf_append_char(json, '\n');
693 for (int i = 0; i < depth; i++)
694 strbuf_append_string(json, cfg->encode_indent);
695}
696
663/* json_append_array args: 697/* json_append_array args:
664 * - lua_State 698 * - lua_State
665 * - JSON strbuf 699 * - JSON strbuf
@@ -668,15 +702,21 @@ static void json_append_array(lua_State *l, json_config_t *cfg, int current_dept
668 strbuf_t *json, int array_length, int raw) 702 strbuf_t *json, int array_length, int raw)
669{ 703{
670 int comma, i, json_pos, err; 704 int comma, i, json_pos, err;
705 int has_items = 0;
671 706
672 strbuf_append_char(json, '['); 707 strbuf_append_char(json, '[');
673 708
674 comma = 0; 709 comma = 0;
675 for (i = 1; i <= array_length; i++) { 710 for (i = 1; i <= array_length; i++) {
711 has_items = 1;
712
676 json_pos = strbuf_length(json); 713 json_pos = strbuf_length(json);
677 if (comma++ > 0) 714 if (comma++ > 0)
678 strbuf_append_char(json, ','); 715 strbuf_append_char(json, ',');
679 716
717 if (cfg->encode_indent)
718 json_append_newline_and_indent(json, cfg, current_depth);
719
680 if (raw) { 720 if (raw) {
681 lua_rawgeti(l, -1, i); 721 lua_rawgeti(l, -1, i);
682 } else { 722 } else {
@@ -698,6 +738,9 @@ static void json_append_array(lua_State *l, json_config_t *cfg, int current_dept
698 lua_pop(l, 1); 738 lua_pop(l, 1);
699 } 739 }
700 740
741 if (has_items && cfg->encode_indent)
742 json_append_newline_and_indent(json, cfg, current_depth-1);
743
701 strbuf_append_char(json, ']'); 744 strbuf_append_char(json, ']');
702} 745}
703 746
@@ -752,6 +795,7 @@ static void json_append_object(lua_State *l, json_config_t *cfg,
752 int current_depth, strbuf_t *json) 795 int current_depth, strbuf_t *json)
753{ 796{
754 int comma, keytype, json_pos, err; 797 int comma, keytype, json_pos, err;
798 int has_items = 0;
755 799
756 /* Object */ 800 /* Object */
757 strbuf_append_char(json, '{'); 801 strbuf_append_char(json, '{');
@@ -760,10 +804,15 @@ static void json_append_object(lua_State *l, json_config_t *cfg,
760 /* table, startkey */ 804 /* table, startkey */
761 comma = 0; 805 comma = 0;
762 while (lua_next(l, -2) != 0) { 806 while (lua_next(l, -2) != 0) {
807 has_items = 1;
808
763 json_pos = strbuf_length(json); 809 json_pos = strbuf_length(json);
764 if (comma++ > 0) 810 if (comma++ > 0)
765 strbuf_append_char(json, ','); 811 strbuf_append_char(json, ',');
766 812
813 if (cfg->encode_indent)
814 json_append_newline_and_indent(json, cfg, current_depth);
815
767 /* table, key, value */ 816 /* table, key, value */
768 keytype = lua_type(l, -2); 817 keytype = lua_type(l, -2);
769 if (keytype == LUA_TNUMBER) { 818 if (keytype == LUA_TNUMBER) {
@@ -778,6 +827,9 @@ static void json_append_object(lua_State *l, json_config_t *cfg,
778 "table key must be a number or string"); 827 "table key must be a number or string");
779 /* never returns */ 828 /* never returns */
780 } 829 }
830 if (cfg->encode_indent)
831 strbuf_append_char(json, ' ');
832
781 833
782 /* table, key, value */ 834 /* table, key, value */
783 err = json_append_data(l, cfg, current_depth, json); 835 err = json_append_data(l, cfg, current_depth, json);
@@ -792,6 +844,9 @@ static void json_append_object(lua_State *l, json_config_t *cfg,
792 /* table, key */ 844 /* table, key */
793 } 845 }
794 846
847 if (has_items && cfg->encode_indent)
848 json_append_newline_and_indent(json, cfg, current_depth-1);
849
795 strbuf_append_char(json, '}'); 850 strbuf_append_char(json, '}');
796} 851}
797 852
@@ -1579,6 +1634,7 @@ static int lua_cjson_new(lua_State *l)
1579 { "decode_invalid_numbers", json_cfg_decode_invalid_numbers }, 1634 { "decode_invalid_numbers", json_cfg_decode_invalid_numbers },
1580 { "encode_escape_forward_slash", json_cfg_encode_escape_forward_slash }, 1635 { "encode_escape_forward_slash", json_cfg_encode_escape_forward_slash },
1581 { "encode_skip_unsupported_value_types", json_cfg_encode_skip_unsupported_value_types }, 1636 { "encode_skip_unsupported_value_types", json_cfg_encode_skip_unsupported_value_types },
1637 { "encode_indent", json_cfg_encode_indent },
1582 { "new", lua_cjson_new }, 1638 { "new", lua_cjson_new },
1583 { NULL, NULL } 1639 { NULL, NULL }
1584 }; 1640 };
diff --git a/tests/test.lua b/tests/test.lua
index cf7a54a..0513d97 100755
--- a/tests/test.lua
+++ b/tests/test.lua
@@ -333,6 +333,44 @@ local cjson_tests = {
333 json.decode, { [["\uDB00\uD"]] }, 333 json.decode, { [["\uDB00\uD"]] },
334 false, { "Expected value but found invalid unicode escape code at character 2" } }, 334 false, { "Expected value but found invalid unicode escape code at character 2" } },
335 335
336 -- Test indenting
337 { 'Set encode_indent(" ")',
338 json.encode_indent, { " " }, true, { " " } },
339 { "Encode object with indenting",
340 json.encode, { { a = "a", b = "b" } },
341 true, {
342 util.one_of {
343 '{\n "a": "a",\n "b": "b"\n}',
344 '{\n "b": "b",\n "a": "a"\n}',
345 }
346 } },
347 { "Encode empty object with indenting",
348 json.encode, { { } }, true, { '{}' } },
349 { "Encode nested object with indenting",
350 json.encode, { { a = { b = 1 } } },
351 true, { '{\n "a": {\n "b": 1\n }\n}' } },
352 { "Encode array with indenting",
353 json.encode, { { 1, 2, 3 } },
354 true, { '[\n 1,\n 2,\n 3\n]' } },
355 { "Encode empty array with indenting",
356 json.encode, { json.empty_array }, true, { '[]' } },
357 { "Encode nested arrays with indenting",
358 json.encode, { { { 1, 2 }, { 3, 4 } } },
359 true, { '[\n [\n 1,\n 2\n ],\n [\n 3,\n 4\n ]\n]' } },
360 { "Encode array of objects with indenting",
361 json.encode, { { { a = "a" }, { b = "b" } } },
362 true, { '[\n {\n "a": "a"\n },\n {\n "b": "b"\n }\n]' } },
363 { 'Set encode_indent("abc")',
364 json.encode_indent, { "abc" }, true, { "abc" } },
365 { "Encode object with non-whitespace indenting",
366 json.encode, { { a = { b = 1 } } },
367 true, { '{\nabc"a": {\nabcabc"b": 1\nabc}\n}' } },
368 { 'Set encode_indent("")',
369 json.encode_indent, { "" }, true, { "" } },
370 { "Encode array of objects with empty indenting",
371 json.encode, { { { a = "a" }, { b = "b" } } },
372 true, { '[{"a":"a"},{"b":"b"}]' } },
373
336 -- Test locale support 374 -- Test locale support
337 -- 375 --
338 -- The standard Lua interpreter is ANSI C online doesn't support locales 376 -- The standard Lua interpreter is ANSI C online doesn't support locales