A patch for bug 44331
| From: | Florian Anderiasch | Date: | Wed, 09 Dec 2009 21:54:46 +0000 |
| Subject: | A patch for bug 44331 | ||
| Groups: | php.internals | ||
| Request: | Send a blank email to internals+get-46384@lists.php.net to get a copy of this message | ||
Hi there,
I've tried to come up with a solution for
Formatting option for json_encode
http://bugs.php.net/bug.php?id=44331
Any comments are highly welcome :)
the patch is against the PHP_5_3 branch as HEAD changes quite some
unicode stuff.
Greetings,
Florian
--- ext/json/json.c.orig 2009-12-09 22:15:33.000000000 +0100 +++ ext/json/json.c 2009-12-09 22:48:04.000000000 +0100 @@ -42,6 +42,7 @@ #define PHP_JSON_HEX_APOS (1<<2) #define PHP_JSON_HEX_QUOT (1<<3) #define PHP_JSON_FORCE_OBJECT (1<<4) +#define PHP_JSON_FORMAT_OUTPUT (1<<5) #define PHP_JSON_OUTPUT_ARRAY 0 #define PHP_JSON_OUTPUT_OBJECT 1 @@ -81,6 +82,7 @@ REGISTER_LONG_CONSTANT("JSON_HEX_APOS", PHP_JSON_HEX_APOS, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("JSON_HEX_QUOT", PHP_JSON_HEX_QUOT, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("JSON_FORCE_OBJECT", PHP_JSON_FORCE_OBJECT, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("JSON_FORMAT_OUTPUT", PHP_JSON_FORMAT_OUTPUT, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("JSON_ERROR_NONE", PHP_JSON_ERROR_NONE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("JSON_ERROR_DEPTH", PHP_JSON_ERROR_DEPTH, CONST_CS | CONST_PERSISTENT); @@ -172,9 +174,10 @@ } /* }}} */ -static void json_encode_array(smart_str *buf, zval **val, int options TSRMLS_DC) /* {{{ */ +static void json_encode_array(smart_str *buf, zval **val, int options, int nesting_level TSRMLS_DC) /* {{{ */ { - int i, r; + int i, r, fmt; + int ii = 0; HashTable *myht; if (Z_TYPE_PP(val) == IS_ARRAY) { @@ -184,6 +187,7 @@ myht = Z_OBJPROP_PP(val); r = PHP_JSON_OUTPUT_OBJECT; } + fmt = ( options & PHP_JSON_FORMAT_OUTPUT) ? 1 : 0; if (myht && myht->nApplyCount > 1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected"); @@ -195,6 +199,9 @@ smart_str_appendc(buf, '['); } else { smart_str_appendc(buf, '{'); + if (fmt) { + smart_str_appendc(buf, '\n'); + } } i = myht ? zend_hash_num_elements(myht) : 0; @@ -227,8 +234,7 @@ } else { need_comma = 1; } - - php_json_encode(buf, *data, options TSRMLS_CC); + php_json_encode_ex(buf, *data, options, nesting_level+1 TSRMLS_CC); } else if (r == PHP_JSON_OUTPUT_OBJECT) { if (i == HASH_KEY_IS_STRING) { if (key[0] == '\0' && Z_TYPE_PP(val) == IS_OBJECT) { @@ -241,27 +247,43 @@ if (need_comma) { smart_str_appendc(buf, ','); + if (fmt) { + smart_str_appendc(buf, '\n'); + } } else { need_comma = 1; } + if (fmt) { + for (ii=0;ii<=nesting_level;ii++) { + smart_str_appendc(buf, '\t'); + } + } json_escape_string(buf, key, key_len - 1, options TSRMLS_CC); smart_str_appendc(buf, ':'); - php_json_encode(buf, *data, options TSRMLS_CC); + php_json_encode_ex(buf, *data, options, nesting_level+1 TSRMLS_CC); } else { if (need_comma) { smart_str_appendc(buf, ','); + if (fmt) { + smart_str_appendc(buf, '\n'); + } } else { need_comma = 1; } + if (fmt) { + for (ii=0;ii<=nesting_level;ii++) { + smart_str_appendc(buf, '\t'); + } + } smart_str_appendc(buf, '"'); smart_str_append_long(buf, (long) index); smart_str_appendc(buf, '"'); smart_str_appendc(buf, ':'); - php_json_encode(buf, *data, options TSRMLS_CC); + php_json_encode_ex(buf, *data, options, nesting_level+1 TSRMLS_CC); } } @@ -275,6 +297,12 @@ if (r == PHP_JSON_OUTPUT_ARRAY) { smart_str_appendc(buf, ']'); } else { + if (fmt) { + smart_str_appendc(buf, '\n'); + for (ii=0;ii<nesting_level;ii++) { + smart_str_appendc(buf, '\t'); + } + } smart_str_appendc(buf, '}'); } } @@ -414,6 +442,12 @@ PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options TSRMLS_DC) /* {{{ */ { + php_json_encode_ex(buf, val, options, 0 TSRMLS_DC); +} +/* }}} */ + +PHP_JSON_API void php_json_encode_ex(smart_str *buf, zval *val, int options, int nesting_level TSRMLS_DC) /* {{{ */ +{ JSON_G(error_code) = PHP_JSON_ERROR_NONE; switch (Z_TYPE_P(val)) { @@ -456,7 +490,7 @@ case IS_ARRAY: case IS_OBJECT: - json_encode_array(buf, &val, options TSRMLS_CC); + json_encode_array(buf, &val, options, nesting_level TSRMLS_CC); break; default: @@ -544,6 +578,7 @@ zval *parameter; smart_str buf = {0}; long options = 0; + int nesting_level = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", ¶meter, &options) == FAILURE) { return;
--- ext/json/json.c.orig 2009-12-09 22:15:33.000000000 +0100 +++ ext/json/json.c 2009-12-09 22:48:04.000000000 +0100 @@ -42,6 +42,7 @@ #define PHP_JSON_HEX_APOS (1<<2) #define PHP_JSON_HEX_QUOT (1<<3) #define PHP_JSON_FORCE_OBJECT (1<<4) +#define PHP_JSON_FORMAT_OUTPUT (1<<5) #define PHP_JSON_OUTPUT_ARRAY 0 #define PHP_JSON_OUTPUT_OBJECT 1 @@ -81,6 +82,7 @@ REGISTER_LONG_CONSTANT("JSON_HEX_APOS", PHP_JSON_HEX_APOS, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("JSON_HEX_QUOT", PHP_JSON_HEX_QUOT, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("JSON_FORCE_OBJECT", PHP_JSON_FORCE_OBJECT, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("JSON_FORMAT_OUTPUT", PHP_JSON_FORMAT_OUTPUT, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("JSON_ERROR_NONE", PHP_JSON_ERROR_NONE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("JSON_ERROR_DEPTH", PHP_JSON_ERROR_DEPTH, CONST_CS | CONST_PERSISTENT); @@ -172,9 +174,10 @@ } /* }}} */ -static void json_encode_array(smart_str *buf, zval **val, int options TSRMLS_DC) /* {{{ */ +static void json_encode_array(smart_str *buf, zval **val, int options, int nesting_level TSRMLS_DC) /* {{{ */ { - int i, r; + int i, r, fmt; + int ii = 0; HashTable *myht; if (Z_TYPE_PP(val) == IS_ARRAY) { @@ -184,6 +187,7 @@ myht = Z_OBJPROP_PP(val); r = PHP_JSON_OUTPUT_OBJECT; } + fmt = ( options & PHP_JSON_FORMAT_OUTPUT) ? 1 : 0; if (myht && myht->nApplyCount > 1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected"); @@ -195,6 +199,9 @@ smart_str_appendc(buf, '['); } else { smart_str_appendc(buf, '{'); + if (fmt) { + smart_str_appendc(buf, '\n'); + } } i = myht ? zend_hash_num_elements(myht) : 0; @@ -227,8 +234,7 @@ } else { need_comma = 1; } - - php_json_encode(buf, *data, options TSRMLS_CC); + php_json_encode_ex(buf, *data, options, nesting_level+1 TSRMLS_CC); } else if (r == PHP_JSON_OUTPUT_OBJECT) { if (i == HASH_KEY_IS_STRING) { if (key[0] == '\0' && Z_TYPE_PP(val) == IS_OBJECT) { @@ -241,27 +247,43 @@ if (need_comma) { smart_str_appendc(buf, ','); + if (fmt) { + smart_str_appendc(buf, '\n'); + } } else { need_comma = 1; } + if (fmt) { + for (ii=0;ii<=nesting_level;ii++) { + smart_str_appendc(buf, '\t'); + } + } json_escape_string(buf, key, key_len - 1, options TSRMLS_CC); smart_str_appendc(buf, ':'); - php_json_encode(buf, *data, options TSRMLS_CC); + php_json_encode_ex(buf, *data, options, nesting_level+1 TSRMLS_CC); } else { if (need_comma) { smart_str_appendc(buf, ','); + if (fmt) { + smart_str_appendc(buf, '\n'); + } } else { need_comma = 1; } + if (fmt) { + for (ii=0;ii<=nesting_level;ii++) { + smart_str_appendc(buf, '\t'); + } + } smart_str_appendc(buf, '"'); smart_str_append_long(buf, (long) index); smart_str_appendc(buf, '"'); smart_str_appendc(buf, ':'); - php_json_encode(buf, *data, options TSRMLS_CC); + php_json_encode_ex(buf, *data, options, nesting_level+1 TSRMLS_CC); } } @@ -275,6 +297,12 @@ if (r == PHP_JSON_OUTPUT_ARRAY) { smart_str_appendc(buf, ']'); } else { + if (fmt) { + smart_str_appendc(buf, '\n'); + for (ii=0;ii<nesting_level;ii++) { + smart_str_appendc(buf, '\t'); + } + } smart_str_appendc(buf, '}'); } } @@ -414,6 +442,12 @@ PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options TSRMLS_DC) /* {{{ */ { + php_json_encode_ex(buf, val, options, 0 TSRMLS_DC); +} +/* }}} */ + +PHP_JSON_API void php_json_encode_ex(smart_str *buf, zval *val, int options, int nesting_level TSRMLS_DC) /* {{{ */ +{ JSON_G(error_code) = PHP_JSON_ERROR_NONE; switch (Z_TYPE_P(val)) { @@ -456,7 +490,7 @@ case IS_ARRAY: case IS_OBJECT: - json_encode_array(buf, &val, options TSRMLS_CC); + json_encode_array(buf, &val, options, nesting_level TSRMLS_CC); break; default: @@ -544,6 +578,7 @@ zval *parameter; smart_str buf = {0}; long options = 0; + int nesting_level = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", ¶meter, &options) == FAILURE) { return;