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.
@@ -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 in :compat and :object mode
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 in null, strict, and compat mode. :null places a null, :huge places a huge number, :word places Infinity or NaN, :raise raises and exception, :auto uses default for each mode.
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);
@@ -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
 
@@ -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 whic causes a segfault on the next call. Oj will not mimic
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
@@ -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 mispelled element
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
  */
@@ -1,31 +1,6 @@
1
- /* parse.c
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>
@@ -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
- noop_end(struct _ParseInfo *pi) {
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
- rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), oj_num_as_value(ni));
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
- rb_ary_push(stack_peek(&pi->stack)->val, oj_num_as_value(ni));
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 = noop_end;
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 = noop_end;
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;
@@ -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
+ }
@@ -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__ */
@@ -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
- noop_end(struct _ParseInfo *pi) {
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
- rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), cstr_to_rstr(str, len));
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
- rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), oj_num_as_value(ni));
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
- rb_ary_push(stack_peek(&pi->stack)->val, cstr_to_rstr(str, len));
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
- rb_ary_push(stack_peek(&pi->stack)->val, oj_num_as_value(ni));
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 = noop_end;
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 = noop_end;
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;