oj 3.4.0 → 3.5.0

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