ref: 457f87b17bbf6e1654073c870a49e9f02ae63143
parent: d9f555652a9743d98143ccf3a0a5b6b903dfeaaa
author: Tor Andersson <tor.andersson@artifex.com>
date: Thu Jan 2 09:22:00 EST 2020
Issue 128: Support property list as replacer argument in JSON.stringify. Also adds helper functions js_isstringobject and js_isnumberobject.
--- a/json.c
+++ b/json.c
@@ -5,6 +5,16 @@
#include "utf.h"
+int js_isnumberobject(js_State *J, int idx)
+{
+ return js_isobject(J, idx) && js_toobject(J, idx)->type == JS_CNUMBER;
+}
+
+int js_isstringobject(js_State *J, int idx)
+{
+ return js_isobject(J, idx) && js_toobject(J, idx)->type == JS_CSTRING;
+}
+
static void jsonnext(js_State *J)
{
J->lookahead = jsY_lexjson(J);
@@ -206,6 +216,25 @@
static int fmtvalue(js_State *J, js_Buffer **sb, const char *key, const char *gap, int level);
+static int filterprop(js_State *J, const char *key)
+{
+ int i, n, found;
+ /* replacer/property-list is in stack slot 2 */
+ if (js_isarray(J, 2)) {
+ found = 0;
+ n = js_getlength(J, 2);
+ for (i = 0; i < n && !found; ++i) {
+ js_getindex(J, 2, i);
+ if (js_isstring(J, -1) || js_isnumber(J, -1) ||
+ js_isstringobject(J, -1) || js_isnumberobject(J, -1))
+ found = !strcmp(key, js_tostring(J, -1));
+ js_pop(J, 1);
+ }
+ return found;
+ }
+ return 1;
+}
+
static void fmtobject(js_State *J, js_Buffer **sb, js_Object *obj, const char *gap, int level)
{
const char *key;
@@ -222,19 +251,21 @@
js_putc(J, sb, '{');
js_pushiterator(J, -1, 1);
while ((key = js_nextiterator(J, -1))) {
- save = (*sb)->n;
- if (n) js_putc(J, sb, ',');
- if (gap) fmtindent(J, sb, gap, level + 1);
- fmtstr(J, sb, key);
- js_putc(J, sb, ':');
- if (gap)
- js_putc(J, sb, ' ');
- js_rot2(J);
- if (!fmtvalue(J, sb, key, gap, level + 1))
- (*sb)->n = save;
- else
- ++n;
- js_rot2(J);
+ if (filterprop(J, key)) {
+ save = (*sb)->n;
+ if (n) js_putc(J, sb, ',');
+ if (gap) fmtindent(J, sb, gap, level + 1);
+ fmtstr(J, sb, key);
+ js_putc(J, sb, ':');
+ if (gap)
+ js_putc(J, sb, ' ');
+ js_rot2(J);
+ if (!fmtvalue(J, sb, key, gap, level + 1))
+ (*sb)->n = save;
+ else
+ ++n;
+ js_rot2(J);
+ }
}
js_pop(J, 1);
if (gap && n) fmtindent(J, sb, gap, level);
@@ -266,7 +297,7 @@
static int fmtvalue(js_State *J, js_Buffer **sb, const char *key, const char *gap, int level)
{
- /* replacer is in 2 */
+ /* replacer/property-list is in 2 */
/* holder is in -1 */
js_getproperty(J, -1, key);
@@ -329,7 +360,7 @@
gap = NULL;
- if (js_isnumber(J, 3) || (js_isobject(J, 3) && js_toobject(J, 3)->type == JS_CNUMBER)) {
+ if (js_isnumber(J, 3) || js_isnumberobject(J, 3)) {
n = js_tointeger(J, 3);
if (n < 0) n = 0;
if (n > 10) n = 10;
@@ -336,7 +367,7 @@
memset(buf, ' ', n);
buf[n] = 0;
if (n > 0) gap = buf;
- } else if (js_isstring(J, 3) || (js_isobject(J, 3) && js_toobject(J, 3)->type == JS_CSTRING)) {
+ } else if (js_isstring(J, 3) || js_isstringobject(J, 3)) {
s = js_tostring(J, 3);
n = strlen(s);
if (n > 10) n = 10;
--- a/mujs.h
+++ b/mujs.h
@@ -176,6 +176,8 @@
int js_iscallable(js_State *J, int idx);
int js_isuserdata(js_State *J, int idx, const char *tag);
int js_iserror(js_State *J, int idx);
+int js_isnumberobject(js_State *J, int idx);
+int js_isstringobject(js_State *J, int idx);
int js_toboolean(js_State *J, int idx);
double js_tonumber(js_State *J, int idx);