oj 3.4.0 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/README.md +1 -1
- data/ext/oj/compat.c +39 -5
- data/ext/oj/custom.c +37 -6
- data/ext/oj/dump_compat.c +11 -1
- data/ext/oj/dump_object.c +10 -0
- data/ext/oj/dump_strict.c +16 -0
- data/ext/oj/mimic_json.c +4 -3
- data/ext/oj/object.c +73 -28
- data/ext/oj/oj.c +10 -2
- data/ext/oj/oj.h +2 -0
- data/ext/oj/rails.c +11 -2
- data/ext/oj/saj.c +1 -1
- data/ext/oj/sparse.c +1 -26
- data/ext/oj/strict.c +55 -5
- data/ext/oj/trace.c +77 -0
- data/ext/oj/trace.h +26 -0
- data/ext/oj/wab.c +67 -7
- data/lib/oj/version.rb +1 -1
- data/pages/Encoding.md +3 -3
- data/pages/Modes.md +1 -0
- data/pages/Options.md +6 -1
- data/pages/Rails.md +27 -4
- data/test/activesupport5/encoding_test.rb +1 -0
- data/test/foo.rb +32 -0
- data/test/test_various.rb +1 -0
- metadata +15 -5
data/ext/oj/oj.c
CHANGED
@@ -98,6 +98,7 @@ VALUE oj_hash_class_sym;
|
|
98
98
|
VALUE oj_indent_sym;
|
99
99
|
VALUE oj_object_class_sym;
|
100
100
|
VALUE oj_quirks_mode_sym;
|
101
|
+
VALUE oj_trace_sym;
|
101
102
|
|
102
103
|
static VALUE allow_blank_sym;
|
103
104
|
static VALUE allow_gc_sym;
|
@@ -181,6 +182,7 @@ struct _Options oj_default_options = {
|
|
181
182
|
No, // allow_invalid
|
182
183
|
No, // create_ok
|
183
184
|
Yes, // allow_nan
|
185
|
+
No, // trace
|
184
186
|
oj_json_class, // create_id
|
185
187
|
10, // create_id_len
|
186
188
|
9, // sec_prec
|
@@ -223,7 +225,7 @@ struct _Options oj_default_options = {
|
|
223
225
|
* - *:escape_mode* [_:newline_|_:json_|_:xss_safe_|_:ascii_|_unicode_xss_|_nil_] determines the characters to escape
|
224
226
|
* - *:class_cache* [_Boolean_|_nil_] cache classes for faster parsing (if dynamically modifying classes or reloading classes then don't use this)
|
225
227
|
* - *:mode* [_:object_|_:strict_|_:compat_|_:null_|_:custom_|_:rails_|_:wab_] load and dump modes to use for JSON
|
226
|
-
* - *:time_format* [_:unix_|_:unix_zone_|_:xmlschema_|_:ruby_] time format when dumping
|
228
|
+
* - *:time_format* [_:unix_|_:unix_zone_|_:xmlschema_|_:ruby_] time format when dumping
|
227
229
|
* - *:bigdecimal_as_decimal* [_Boolean_|_nil_] dump BigDecimal as a decimal number or as a String
|
228
230
|
* - *:bigdecimal_load* [_:bigdecimal_|_:float_|_:auto_] load decimals as BigDecimal instead of as a Float. :auto pick the most precise for the number of digits.
|
229
231
|
* - *:create_id* [_String_|_nil_] create id for json compatible object encoding, default is 'json_class'
|
@@ -242,11 +244,12 @@ struct _Options oj_default_options = {
|
|
242
244
|
* - *:space_before* [_String_|_nil_] String to use before the colon separator in JSON object fields
|
243
245
|
* - *:object_nl* [_String_|_nil_] String to use after a JSON object field value
|
244
246
|
* - *:array_nl* [_String_|_nil_] String to use after a JSON array value
|
245
|
-
* - *:nan* [_:null_|_:huge_|_:word_|_:raise_|_:auto_] how to dump Infinity and NaN
|
247
|
+
* - *:nan* [_:null_|_:huge_|_:word_|_:raise_|_:auto_] how to dump Infinity and NaN. :null places a null, :huge places a huge number, :word places Infinity or NaN, :raise raises and exception, :auto uses default for each mode.
|
246
248
|
* - *:hash_class* [_Class_|_nil_] Class to use instead of Hash on load, :object_class can also be used
|
247
249
|
* - *:array_class* [_Class_|_nil_] Class to use instead of Array on load
|
248
250
|
* - *:omit_nil* [_true_|_false_] if true Hash and Object attributes with nil values are omitted
|
249
251
|
* - *:ignore* [_nil_|Array] either nil or an Array of classes to ignore when dumping
|
252
|
+
* - *:trace* [_true,_|_false_] Trace all load and dump calls, default is false (trace is off)
|
250
253
|
*
|
251
254
|
* Return [_Hash_] all current option settings.
|
252
255
|
*/
|
@@ -274,6 +277,7 @@ get_def_opts(VALUE self) {
|
|
274
277
|
rb_hash_aset(opts, oj_quirks_mode_sym, (Yes == oj_default_options.quirks_mode) ? Qtrue : ((No == oj_default_options.quirks_mode) ? Qfalse : Qnil));
|
275
278
|
rb_hash_aset(opts, allow_invalid_unicode_sym, (Yes == oj_default_options.allow_invalid) ? Qtrue : ((No == oj_default_options.allow_invalid) ? Qfalse : Qnil));
|
276
279
|
rb_hash_aset(opts, oj_allow_nan_sym, (Yes == oj_default_options.allow_nan) ? Qtrue : ((No == oj_default_options.allow_nan) ? Qfalse : Qnil));
|
280
|
+
rb_hash_aset(opts, oj_trace_sym, (Yes == oj_default_options.trace) ? Qtrue : ((No == oj_default_options.trace) ? Qfalse : Qnil));
|
277
281
|
rb_hash_aset(opts, float_prec_sym, INT2FIX(oj_default_options.float_prec));
|
278
282
|
switch (oj_default_options.mode) {
|
279
283
|
case StrictMode: rb_hash_aset(opts, mode_sym, strict_sym); break;
|
@@ -373,6 +377,7 @@ get_def_opts(VALUE self) {
|
|
373
377
|
* - *:array_class* [_Class_|_nil_] Class to use instead of Array on load.
|
374
378
|
* - *:omit_nil* [_true_|_false_] if true Hash and Object attributes with nil values are omitted.
|
375
379
|
* - *:ignore* [_nil_|Array] either nil or an Array of classes to ignore when dumping
|
380
|
+
* - *:trace* [_Boolean_] turn trace on or off.
|
376
381
|
*/
|
377
382
|
static VALUE
|
378
383
|
set_def_opts(VALUE self, VALUE opts) {
|
@@ -400,6 +405,7 @@ oj_parse_options(VALUE ropts, Options copts) {
|
|
400
405
|
{ oj_quirks_mode_sym, &copts->quirks_mode },
|
401
406
|
{ allow_invalid_unicode_sym, &copts->allow_invalid },
|
402
407
|
{ oj_allow_nan_sym, &copts->allow_nan },
|
408
|
+
{ oj_trace_sym, &copts->trace },
|
403
409
|
{ oj_create_additions_sym, &copts->create_ok },
|
404
410
|
{ Qnil, 0 }
|
405
411
|
};
|
@@ -1040,6 +1046,7 @@ dump(int argc, VALUE *argv, VALUE self) {
|
|
1040
1046
|
* - *:space_before* [_String_|_nil_] String to use before the colon separator in JSON object fields.
|
1041
1047
|
* - *:object_nl* [_String_|_nil_] String to use after a JSON object field value.
|
1042
1048
|
* - *:array_nl* [_String_|_nil_] String to use after a JSON array value.
|
1049
|
+
* - *:trace* [_Boolean_] If true trace is turned on.
|
1043
1050
|
*
|
1044
1051
|
* Returns [_String_] the encoded JSON.
|
1045
1052
|
*/
|
@@ -1660,6 +1667,7 @@ Init_oj() {
|
|
1660
1667
|
oj_quirks_mode_sym = ID2SYM(rb_intern("quirks_mode")); rb_gc_register_address(&oj_quirks_mode_sym);
|
1661
1668
|
oj_space_before_sym = ID2SYM(rb_intern("space_before")); rb_gc_register_address(&oj_space_before_sym);
|
1662
1669
|
oj_space_sym = ID2SYM(rb_intern("space")); rb_gc_register_address(&oj_space_sym);
|
1670
|
+
oj_trace_sym = ID2SYM(rb_intern("trace")); rb_gc_register_address(&oj_trace_sym);
|
1663
1671
|
omit_nil_sym = ID2SYM(rb_intern("omit_nil")); rb_gc_register_address(&omit_nil_sym);
|
1664
1672
|
rails_sym = ID2SYM(rb_intern("rails")); rb_gc_register_address(&rails_sym);
|
1665
1673
|
raise_sym = ID2SYM(rb_intern("raise")); rb_gc_register_address(&raise_sym);
|
data/ext/oj/oj.h
CHANGED
@@ -152,6 +152,7 @@ typedef struct _Options {
|
|
152
152
|
char allow_invalid; // YesNo - allow invalid unicode
|
153
153
|
char create_ok; // YesNo allow create_id
|
154
154
|
char allow_nan; // YEsyNo for parsing only
|
155
|
+
char trace; // YesNo
|
155
156
|
const char *create_id; // 0 or string
|
156
157
|
size_t create_id_len; // length of create_id
|
157
158
|
int sec_prec; // second precision when dumping time
|
@@ -322,6 +323,7 @@ extern VALUE oj_object_nl_sym;
|
|
322
323
|
extern VALUE oj_quirks_mode_sym;
|
323
324
|
extern VALUE oj_space_before_sym;
|
324
325
|
extern VALUE oj_space_sym;
|
326
|
+
extern VALUE oj_trace_sym;
|
325
327
|
|
326
328
|
extern VALUE oj_slash_string;
|
327
329
|
|
data/ext/oj/rails.c
CHANGED
@@ -7,6 +7,7 @@
|
|
7
7
|
#include "encode.h"
|
8
8
|
#include "code.h"
|
9
9
|
#include "encode.h"
|
10
|
+
#include "trace.h"
|
10
11
|
|
11
12
|
#define OJ_INFINITY (1.0/0.0)
|
12
13
|
|
@@ -610,7 +611,6 @@ rails_mimic_json(VALUE self) {
|
|
610
611
|
json = rb_define_module("JSON");
|
611
612
|
}
|
612
613
|
oj_mimic_json_methods(json);
|
613
|
-
// TBD
|
614
614
|
|
615
615
|
return Qnil;
|
616
616
|
}
|
@@ -1272,7 +1272,7 @@ static DumpFunc rails_funcs[] = {
|
|
1272
1272
|
dump_obj, // RUBY_T_DATA = 0x0c,
|
1273
1273
|
NULL, // RUBY_T_MATCH = 0x0d,
|
1274
1274
|
// Rails raises a stack error on Complex and Rational. It also corrupts
|
1275
|
-
// something
|
1275
|
+
// something which causes a segfault on the next call. Oj will not mimic
|
1276
1276
|
// that behavior.
|
1277
1277
|
dump_as_string, // RUBY_T_COMPLEX = 0x0e,
|
1278
1278
|
dump_as_string, // RUBY_T_RATIONAL = 0x0f,
|
@@ -1288,6 +1288,9 @@ static void
|
|
1288
1288
|
dump_rails_val(VALUE obj, int depth, Out out, bool as_ok) {
|
1289
1289
|
int type = rb_type(obj);
|
1290
1290
|
|
1291
|
+
if (Yes == out->opts->trace) {
|
1292
|
+
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
1293
|
+
}
|
1291
1294
|
if (MAX_DEPTH < depth) {
|
1292
1295
|
rb_raise(rb_eNoMemError, "Too deeply nested.\n");
|
1293
1296
|
}
|
@@ -1296,10 +1299,16 @@ dump_rails_val(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1296
1299
|
|
1297
1300
|
if (NULL != f) {
|
1298
1301
|
f(obj, depth, out, as_ok);
|
1302
|
+
if (Yes == out->opts->trace) {
|
1303
|
+
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
1304
|
+
}
|
1299
1305
|
return;
|
1300
1306
|
}
|
1301
1307
|
}
|
1302
1308
|
oj_dump_nil(Qnil, depth, out, false);
|
1309
|
+
if (Yes == out->opts->trace) {
|
1310
|
+
oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
|
1311
|
+
}
|
1303
1312
|
}
|
1304
1313
|
|
1305
1314
|
void
|
data/ext/oj/saj.c
CHANGED
@@ -52,7 +52,7 @@ static void skip_comment(ParseInfo pi);
|
|
52
52
|
* a SAX parser because it uses callback when document elements are
|
53
53
|
* encountered.
|
54
54
|
*
|
55
|
-
* Parsing is very tolerant. Lack of headers and even
|
55
|
+
* Parsing is very tolerant. Lack of headers and even misspelled element
|
56
56
|
* endings are passed over without raising an error. A best attempt is made in
|
57
57
|
* all cases to parse the string.
|
58
58
|
*/
|
data/ext/oj/sparse.c
CHANGED
@@ -1,31 +1,6 @@
|
|
1
|
-
/*
|
1
|
+
/* sparse.c
|
2
2
|
* Copyright (c) 2013, Peter Ohler
|
3
3
|
* All rights reserved.
|
4
|
-
*
|
5
|
-
* Redistribution and use in source and binary forms, with or without
|
6
|
-
* modification, are permitted provided that the following conditions are met:
|
7
|
-
*
|
8
|
-
* - Redistributions of source code must retain the above copyright notice, this
|
9
|
-
* list of conditions and the following disclaimer.
|
10
|
-
*
|
11
|
-
* - Redistributions in binary form must reproduce the above copyright notice,
|
12
|
-
* this list of conditions and the following disclaimer in the documentation
|
13
|
-
* and/or other materials provided with the distribution.
|
14
|
-
*
|
15
|
-
* - Neither the name of Peter Ohler nor the names of its contributors may be
|
16
|
-
* used to endorse or promote products derived from this software without
|
17
|
-
* specific prior written permission.
|
18
|
-
*
|
19
|
-
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
20
|
-
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
21
|
-
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
22
|
-
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
23
|
-
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
24
|
-
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
25
|
-
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
26
|
-
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
27
|
-
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
|
-
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
4
|
*/
|
30
5
|
|
31
6
|
#include <stdlib.h>
|
data/ext/oj/strict.c
CHANGED
@@ -12,9 +12,20 @@
|
|
12
12
|
#include "err.h"
|
13
13
|
#include "parse.h"
|
14
14
|
#include "encode.h"
|
15
|
+
#include "trace.h"
|
15
16
|
|
16
17
|
static void
|
17
|
-
|
18
|
+
hash_end(struct _ParseInfo *pi) {
|
19
|
+
if (Yes == pi->options.trace) {
|
20
|
+
oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
static void
|
25
|
+
array_end(struct _ParseInfo *pi) {
|
26
|
+
if (Yes == pi->options.trace) {
|
27
|
+
oj_trace_parse_array_end(pi, __FILE__, __LINE__);
|
28
|
+
}
|
18
29
|
}
|
19
30
|
|
20
31
|
static VALUE
|
@@ -24,6 +35,9 @@ noop_hash_key(struct _ParseInfo *pi, const char *key, size_t klen) {
|
|
24
35
|
|
25
36
|
static void
|
26
37
|
add_value(ParseInfo pi, VALUE val) {
|
38
|
+
if (Yes == pi->options.trace) {
|
39
|
+
oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, val);
|
40
|
+
}
|
27
41
|
pi->stack.head->val = val;
|
28
42
|
}
|
29
43
|
|
@@ -33,6 +47,9 @@ add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
|
33
47
|
|
34
48
|
rstr = oj_encode(rstr);
|
35
49
|
pi->stack.head->val = rstr;
|
50
|
+
if (Yes == pi->options.trace) {
|
51
|
+
oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr);
|
52
|
+
}
|
36
53
|
}
|
37
54
|
|
38
55
|
static void
|
@@ -41,6 +58,9 @@ add_num(ParseInfo pi, NumInfo ni) {
|
|
41
58
|
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
42
59
|
}
|
43
60
|
pi->stack.head->val = oj_num_as_value(ni);
|
61
|
+
if (Yes == pi->options.trace) {
|
62
|
+
oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
|
63
|
+
}
|
44
64
|
}
|
45
65
|
|
46
66
|
static VALUE
|
@@ -48,6 +68,9 @@ start_hash(ParseInfo pi) {
|
|
48
68
|
if (Qnil != pi->options.hash_class) {
|
49
69
|
return rb_class_new_instance(0, NULL, pi->options.hash_class);
|
50
70
|
}
|
71
|
+
if (Yes == pi->options.trace) {
|
72
|
+
oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
|
73
|
+
}
|
51
74
|
return rb_hash_new();
|
52
75
|
}
|
53
76
|
|
@@ -71,23 +94,38 @@ hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char
|
|
71
94
|
|
72
95
|
rstr = oj_encode(rstr);
|
73
96
|
rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rstr);
|
97
|
+
if (Yes == pi->options.trace) {
|
98
|
+
oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
|
99
|
+
}
|
74
100
|
}
|
75
101
|
|
76
102
|
static void
|
77
103
|
hash_set_num(struct _ParseInfo *pi, Val parent, NumInfo ni) {
|
104
|
+
volatile VALUE v;
|
105
|
+
|
78
106
|
if (ni->infinity || ni->nan) {
|
79
107
|
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
80
108
|
}
|
81
|
-
|
109
|
+
v = oj_num_as_value(ni);
|
110
|
+
rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), v);
|
111
|
+
if (Yes == pi->options.trace) {
|
112
|
+
oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, v);
|
113
|
+
}
|
82
114
|
}
|
83
115
|
|
84
116
|
static void
|
85
117
|
hash_set_value(ParseInfo pi, Val parent, VALUE value) {
|
86
118
|
rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value);
|
119
|
+
if (Yes == pi->options.trace) {
|
120
|
+
oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
|
121
|
+
}
|
87
122
|
}
|
88
123
|
|
89
124
|
static VALUE
|
90
125
|
start_array(ParseInfo pi) {
|
126
|
+
if (Yes == pi->options.trace) {
|
127
|
+
oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
|
128
|
+
}
|
91
129
|
return rb_ary_new();
|
92
130
|
}
|
93
131
|
|
@@ -97,31 +135,43 @@ array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
|
97
135
|
|
98
136
|
rstr = oj_encode(rstr);
|
99
137
|
rb_ary_push(stack_peek(&pi->stack)->val, rstr);
|
138
|
+
if (Yes == pi->options.trace) {
|
139
|
+
oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
|
140
|
+
}
|
100
141
|
}
|
101
142
|
|
102
143
|
static void
|
103
144
|
array_append_num(ParseInfo pi, NumInfo ni) {
|
145
|
+
volatile VALUE v;
|
146
|
+
|
104
147
|
if (ni->infinity || ni->nan) {
|
105
148
|
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
106
149
|
}
|
107
|
-
|
150
|
+
v = oj_num_as_value(ni);
|
151
|
+
rb_ary_push(stack_peek(&pi->stack)->val, v);
|
152
|
+
if (Yes == pi->options.trace) {
|
153
|
+
oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, v);
|
154
|
+
}
|
108
155
|
}
|
109
156
|
|
110
157
|
static void
|
111
158
|
array_append_value(ParseInfo pi, VALUE value) {
|
112
159
|
rb_ary_push(stack_peek(&pi->stack)->val, value);
|
160
|
+
if (Yes == pi->options.trace) {
|
161
|
+
oj_trace_parse_call("append_value", pi, __FILE__, __LINE__, value);
|
162
|
+
}
|
113
163
|
}
|
114
164
|
|
115
165
|
void
|
116
166
|
oj_set_strict_callbacks(ParseInfo pi) {
|
117
167
|
pi->start_hash = start_hash;
|
118
|
-
pi->end_hash =
|
168
|
+
pi->end_hash = hash_end;
|
119
169
|
pi->hash_key = noop_hash_key;
|
120
170
|
pi->hash_set_cstr = hash_set_cstr;
|
121
171
|
pi->hash_set_num = hash_set_num;
|
122
172
|
pi->hash_set_value = hash_set_value;
|
123
173
|
pi->start_array = start_array;
|
124
|
-
pi->end_array =
|
174
|
+
pi->end_array = array_end;
|
125
175
|
pi->array_append_cstr = array_append_cstr;
|
126
176
|
pi->array_append_num = array_append_num;
|
127
177
|
pi->array_append_value = array_append_value;
|
data/ext/oj/trace.c
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
/* trace.h
|
2
|
+
* Copyright (c) 2018, Peter Ohler
|
3
|
+
* All rights reserved.
|
4
|
+
*/
|
5
|
+
|
6
|
+
#include "parse.h"
|
7
|
+
#include "trace.h"
|
8
|
+
|
9
|
+
#define MAX_INDENT 256
|
10
|
+
|
11
|
+
static void
|
12
|
+
fill_indent(char *indent, int depth) {
|
13
|
+
if (MAX_INDENT <= depth) {
|
14
|
+
depth = MAX_INDENT - 1;
|
15
|
+
} else if (depth < 0) {
|
16
|
+
depth = 0;
|
17
|
+
}
|
18
|
+
memset(indent, ' ', depth);
|
19
|
+
indent[depth] = '\0';
|
20
|
+
}
|
21
|
+
|
22
|
+
void
|
23
|
+
oj_trace(const char *func, VALUE obj, const char *file, int line, int depth, TraceWhere where) {
|
24
|
+
char fmt[64];
|
25
|
+
char indent[MAX_INDENT];
|
26
|
+
|
27
|
+
depth *= 2;
|
28
|
+
fill_indent(indent, depth);
|
29
|
+
sprintf(fmt, "#0:%%13s:%%3d:Oj:%c:%%%ds %%s %%s\n", where, depth);
|
30
|
+
printf(fmt, file, line, indent, func, rb_obj_classname(obj));
|
31
|
+
}
|
32
|
+
|
33
|
+
void
|
34
|
+
oj_trace_parse_call(const char *func, ParseInfo pi, const char *file, int line, VALUE obj) {
|
35
|
+
char fmt[64];
|
36
|
+
char indent[MAX_INDENT];
|
37
|
+
int depth = stack_size(&pi->stack) * 2;
|
38
|
+
|
39
|
+
fill_indent(indent, depth);
|
40
|
+
sprintf(fmt, "#0:%%13s:%%3d:Oj:-:%%%ds %%s %%s\n", depth);
|
41
|
+
printf(fmt, file, line, indent, func, rb_obj_classname(obj));
|
42
|
+
}
|
43
|
+
|
44
|
+
void
|
45
|
+
oj_trace_parse_in(const char *func, ParseInfo pi, const char *file, int line) {
|
46
|
+
char fmt[64];
|
47
|
+
char indent[MAX_INDENT];
|
48
|
+
int depth = stack_size(&pi->stack) * 2;
|
49
|
+
|
50
|
+
fill_indent(indent, depth);
|
51
|
+
sprintf(fmt, "#0:%%13s:%%3d:Oj:}:%%%ds %%s\n", depth);
|
52
|
+
printf(fmt, file, line, indent, func);
|
53
|
+
}
|
54
|
+
|
55
|
+
void
|
56
|
+
oj_trace_parse_hash_end(ParseInfo pi, const char *file, int line) {
|
57
|
+
char fmt[64];
|
58
|
+
char indent[MAX_INDENT];
|
59
|
+
int depth = stack_size(&pi->stack) * 2 - 2;
|
60
|
+
Val v = stack_peek(&pi->stack);
|
61
|
+
VALUE obj = v->val;
|
62
|
+
|
63
|
+
fill_indent(indent, depth);
|
64
|
+
sprintf(fmt, "#0:%%13s:%%3d:Oj:{:%%%ds hash_end %%s\n", depth);
|
65
|
+
printf(fmt, file, line, indent, rb_obj_classname(obj));
|
66
|
+
}
|
67
|
+
|
68
|
+
void
|
69
|
+
oj_trace_parse_array_end(ParseInfo pi, const char *file, int line) {
|
70
|
+
char fmt[64];
|
71
|
+
char indent[MAX_INDENT];
|
72
|
+
int depth = stack_size(&pi->stack) * 2;
|
73
|
+
|
74
|
+
fill_indent(indent, depth);
|
75
|
+
sprintf(fmt, "#0:%%13s:%%3d:Oj:{:%%%ds array_ned\n", depth);
|
76
|
+
printf(fmt, file, line, indent);
|
77
|
+
}
|
data/ext/oj/trace.h
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
/* trace.h
|
2
|
+
* Copyright (c) 2018, Peter Ohler
|
3
|
+
* All rights reserved.
|
4
|
+
*/
|
5
|
+
|
6
|
+
#ifndef __OJ_TRACE_H__
|
7
|
+
#define __OJ_TRACE_H__
|
8
|
+
|
9
|
+
#include <stdbool.h>
|
10
|
+
#include <ruby.h>
|
11
|
+
|
12
|
+
typedef enum {
|
13
|
+
TraceIn = '{',
|
14
|
+
TraceOut = '}',
|
15
|
+
TraceCall = '-',
|
16
|
+
} TraceWhere;
|
17
|
+
|
18
|
+
struct _ParseInfo;
|
19
|
+
|
20
|
+
extern void oj_trace(const char *func, VALUE obj, const char *file, int line, int depth, TraceWhere where);
|
21
|
+
extern void oj_trace_parse_in(const char *func, struct _ParseInfo *pi, const char *file, int line);
|
22
|
+
extern void oj_trace_parse_call(const char *func, struct _ParseInfo *pi, const char *file, int line, VALUE obj);
|
23
|
+
extern void oj_trace_parse_hash_end(struct _ParseInfo *pi, const char *file, int line);
|
24
|
+
extern void oj_trace_parse_array_end(struct _ParseInfo *pi, const char *file, int line);
|
25
|
+
|
26
|
+
#endif /* __OJ_TRACE_H__ */
|
data/ext/oj/wab.c
CHANGED
@@ -14,6 +14,7 @@
|
|
14
14
|
#include "parse.h"
|
15
15
|
#include "encode.h"
|
16
16
|
#include "dump.h"
|
17
|
+
#include "trace.h"
|
17
18
|
|
18
19
|
// Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
|
19
20
|
#define OJ_INFINITY (1.0/0.0)
|
@@ -266,6 +267,9 @@ void
|
|
266
267
|
oj_dump_wab_val(VALUE obj, int depth, Out out) {
|
267
268
|
int type = rb_type(obj);
|
268
269
|
|
270
|
+
if (Yes == out->opts->trace) {
|
271
|
+
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
272
|
+
}
|
269
273
|
if (MAX_DEPTH < depth) {
|
270
274
|
rb_raise(rb_eNoMemError, "Too deeply nested.\n");
|
271
275
|
}
|
@@ -274,6 +278,9 @@ oj_dump_wab_val(VALUE obj, int depth, Out out) {
|
|
274
278
|
|
275
279
|
if (NULL != f) {
|
276
280
|
f(obj, depth, out, false);
|
281
|
+
if (Yes == out->opts->trace) {
|
282
|
+
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
283
|
+
}
|
277
284
|
return;
|
278
285
|
}
|
279
286
|
}
|
@@ -283,7 +290,17 @@ oj_dump_wab_val(VALUE obj, int depth, Out out) {
|
|
283
290
|
///// load functions /////
|
284
291
|
|
285
292
|
static void
|
286
|
-
|
293
|
+
hash_end(struct _ParseInfo *pi) {
|
294
|
+
if (Yes == pi->options.trace) {
|
295
|
+
oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
|
296
|
+
}
|
297
|
+
}
|
298
|
+
|
299
|
+
static void
|
300
|
+
array_end(struct _ParseInfo *pi) {
|
301
|
+
if (Yes == pi->options.trace) {
|
302
|
+
oj_trace_parse_array_end(pi, __FILE__, __LINE__);
|
303
|
+
}
|
287
304
|
}
|
288
305
|
|
289
306
|
static VALUE
|
@@ -293,6 +310,9 @@ noop_hash_key(struct _ParseInfo *pi, const char *key, size_t klen) {
|
|
293
310
|
|
294
311
|
static void
|
295
312
|
add_value(ParseInfo pi, VALUE val) {
|
313
|
+
if (Yes == pi->options.trace) {
|
314
|
+
oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, val);
|
315
|
+
}
|
296
316
|
pi->stack.head->val = val;
|
297
317
|
}
|
298
318
|
|
@@ -444,6 +464,9 @@ cstr_to_rstr(const char *str, size_t len) {
|
|
444
464
|
static void
|
445
465
|
add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
446
466
|
pi->stack.head->val = cstr_to_rstr(str, len);
|
467
|
+
if (Yes == pi->options.trace) {
|
468
|
+
oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val);
|
469
|
+
}
|
447
470
|
}
|
448
471
|
|
449
472
|
static void
|
@@ -452,10 +475,16 @@ add_num(ParseInfo pi, NumInfo ni) {
|
|
452
475
|
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
453
476
|
}
|
454
477
|
pi->stack.head->val = oj_num_as_value(ni);
|
478
|
+
if (Yes == pi->options.trace) {
|
479
|
+
oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
|
480
|
+
}
|
455
481
|
}
|
456
482
|
|
457
483
|
static VALUE
|
458
484
|
start_hash(ParseInfo pi) {
|
485
|
+
if (Yes == pi->options.trace) {
|
486
|
+
oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
|
487
|
+
}
|
459
488
|
if (Qnil != pi->options.hash_class) {
|
460
489
|
return rb_class_new_instance(0, NULL, pi->options.hash_class);
|
461
490
|
}
|
@@ -477,55 +506,86 @@ calc_hash_key(ParseInfo pi, Val parent) {
|
|
477
506
|
|
478
507
|
static void
|
479
508
|
hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char *orig) {
|
480
|
-
|
509
|
+
volatile VALUE rval = cstr_to_rstr(str, len);
|
510
|
+
|
511
|
+
rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval);
|
512
|
+
if (Yes == pi->options.trace) {
|
513
|
+
oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
|
514
|
+
}
|
481
515
|
}
|
482
516
|
|
483
517
|
static void
|
484
518
|
hash_set_num(struct _ParseInfo *pi, Val parent, NumInfo ni) {
|
519
|
+
volatile VALUE rval = Qnil;
|
520
|
+
|
485
521
|
if (ni->infinity || ni->nan) {
|
486
522
|
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
487
523
|
}
|
488
|
-
|
524
|
+
rval = oj_num_as_value(ni);
|
525
|
+
rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval);
|
526
|
+
if (Yes == pi->options.trace) {
|
527
|
+
oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval);
|
528
|
+
}
|
489
529
|
}
|
490
530
|
|
491
531
|
static void
|
492
532
|
hash_set_value(ParseInfo pi, Val parent, VALUE value) {
|
493
533
|
rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value);
|
534
|
+
if (Yes == pi->options.trace) {
|
535
|
+
oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
|
536
|
+
}
|
494
537
|
}
|
495
538
|
|
496
539
|
static VALUE
|
497
540
|
start_array(ParseInfo pi) {
|
541
|
+
if (Yes == pi->options.trace) {
|
542
|
+
oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
|
543
|
+
}
|
498
544
|
return rb_ary_new();
|
499
545
|
}
|
500
546
|
|
501
547
|
static void
|
502
548
|
array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
503
|
-
|
549
|
+
volatile VALUE rval = cstr_to_rstr(str, len);
|
550
|
+
|
551
|
+
rb_ary_push(stack_peek(&pi->stack)->val, rval);
|
552
|
+
if (Yes == pi->options.trace) {
|
553
|
+
oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, rval);
|
554
|
+
}
|
504
555
|
}
|
505
556
|
|
506
557
|
static void
|
507
558
|
array_append_num(ParseInfo pi, NumInfo ni) {
|
559
|
+
volatile VALUE rval = Qnil;
|
560
|
+
|
508
561
|
if (ni->infinity || ni->nan) {
|
509
562
|
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
510
563
|
}
|
511
|
-
|
564
|
+
rval = oj_num_as_value(ni);
|
565
|
+
rb_ary_push(stack_peek(&pi->stack)->val, rval);
|
566
|
+
if (Yes == pi->options.trace) {
|
567
|
+
oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
|
568
|
+
}
|
512
569
|
}
|
513
570
|
|
514
571
|
static void
|
515
572
|
array_append_value(ParseInfo pi, VALUE value) {
|
516
573
|
rb_ary_push(stack_peek(&pi->stack)->val, value);
|
574
|
+
if (Yes == pi->options.trace) {
|
575
|
+
oj_trace_parse_call("append_value", pi, __FILE__, __LINE__, value);
|
576
|
+
}
|
517
577
|
}
|
518
578
|
|
519
579
|
void
|
520
580
|
oj_set_wab_callbacks(ParseInfo pi) {
|
521
581
|
pi->start_hash = start_hash;
|
522
|
-
pi->end_hash =
|
582
|
+
pi->end_hash = hash_end;
|
523
583
|
pi->hash_key = noop_hash_key;
|
524
584
|
pi->hash_set_cstr = hash_set_cstr;
|
525
585
|
pi->hash_set_num = hash_set_num;
|
526
586
|
pi->hash_set_value = hash_set_value;
|
527
587
|
pi->start_array = start_array;
|
528
|
-
pi->end_array =
|
588
|
+
pi->end_array = array_end;
|
529
589
|
pi->array_append_cstr = array_append_cstr;
|
530
590
|
pi->array_append_num = array_append_num;
|
531
591
|
pi->array_append_value = array_append_value;
|