oj 3.4.0 → 3.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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;
|