oj 3.11.5 → 3.16.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (168) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1421 -0
  3. data/README.md +19 -5
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +20 -6
  6. data/ext/oj/cache.c +329 -0
  7. data/ext/oj/cache.h +22 -0
  8. data/ext/oj/cache8.c +10 -9
  9. data/ext/oj/circarray.c +8 -6
  10. data/ext/oj/circarray.h +2 -2
  11. data/ext/oj/code.c +19 -33
  12. data/ext/oj/code.h +2 -2
  13. data/ext/oj/compat.c +27 -77
  14. data/ext/oj/custom.c +86 -179
  15. data/ext/oj/debug.c +126 -0
  16. data/ext/oj/dump.c +256 -249
  17. data/ext/oj/dump.h +26 -12
  18. data/ext/oj/dump_compat.c +565 -642
  19. data/ext/oj/dump_leaf.c +17 -63
  20. data/ext/oj/dump_object.c +65 -187
  21. data/ext/oj/dump_strict.c +27 -51
  22. data/ext/oj/encoder.c +43 -0
  23. data/ext/oj/err.c +2 -13
  24. data/ext/oj/err.h +24 -8
  25. data/ext/oj/extconf.rb +21 -6
  26. data/ext/oj/fast.c +149 -149
  27. data/ext/oj/intern.c +313 -0
  28. data/ext/oj/intern.h +22 -0
  29. data/ext/oj/mem.c +318 -0
  30. data/ext/oj/mem.h +53 -0
  31. data/ext/oj/mimic_json.c +121 -106
  32. data/ext/oj/object.c +85 -162
  33. data/ext/oj/odd.c +89 -67
  34. data/ext/oj/odd.h +15 -15
  35. data/ext/oj/oj.c +542 -411
  36. data/ext/oj/oj.h +99 -73
  37. data/ext/oj/parse.c +175 -187
  38. data/ext/oj/parse.h +26 -24
  39. data/ext/oj/parser.c +1600 -0
  40. data/ext/oj/parser.h +101 -0
  41. data/ext/oj/rails.c +112 -159
  42. data/ext/oj/rails.h +1 -1
  43. data/ext/oj/reader.c +11 -14
  44. data/ext/oj/reader.h +4 -2
  45. data/ext/oj/resolve.c +5 -24
  46. data/ext/oj/rxclass.c +7 -6
  47. data/ext/oj/rxclass.h +1 -1
  48. data/ext/oj/saj.c +22 -33
  49. data/ext/oj/saj2.c +584 -0
  50. data/ext/oj/saj2.h +23 -0
  51. data/ext/oj/scp.c +5 -28
  52. data/ext/oj/sparse.c +28 -72
  53. data/ext/oj/stream_writer.c +50 -40
  54. data/ext/oj/strict.c +56 -61
  55. data/ext/oj/string_writer.c +72 -39
  56. data/ext/oj/trace.h +31 -4
  57. data/ext/oj/usual.c +1218 -0
  58. data/ext/oj/usual.h +69 -0
  59. data/ext/oj/util.h +1 -1
  60. data/ext/oj/val_stack.c +14 -3
  61. data/ext/oj/val_stack.h +8 -7
  62. data/ext/oj/validate.c +46 -0
  63. data/ext/oj/wab.c +63 -88
  64. data/lib/oj/active_support_helper.rb +1 -3
  65. data/lib/oj/bag.rb +7 -1
  66. data/lib/oj/easy_hash.rb +4 -5
  67. data/lib/oj/error.rb +1 -2
  68. data/lib/oj/json.rb +162 -150
  69. data/lib/oj/mimic.rb +9 -7
  70. data/lib/oj/saj.rb +20 -6
  71. data/lib/oj/schandler.rb +5 -4
  72. data/lib/oj/state.rb +12 -8
  73. data/lib/oj/version.rb +1 -2
  74. data/lib/oj.rb +2 -0
  75. data/pages/Compatibility.md +1 -1
  76. data/pages/InstallOptions.md +20 -0
  77. data/pages/JsonGem.md +15 -0
  78. data/pages/Modes.md +8 -3
  79. data/pages/Options.md +43 -5
  80. data/pages/Parser.md +309 -0
  81. data/pages/Rails.md +14 -2
  82. data/test/_test_active.rb +8 -9
  83. data/test/_test_active_mimic.rb +7 -8
  84. data/test/_test_mimic_rails.rb +17 -20
  85. data/test/activerecord/result_test.rb +5 -6
  86. data/test/activesupport6/encoding_test.rb +63 -28
  87. data/test/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
  88. data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
  89. data/test/{activesupport5 → activesupport7}/encoding_test.rb +86 -50
  90. data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
  91. data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
  92. data/test/files.rb +15 -15
  93. data/test/foo.rb +16 -45
  94. data/test/helper.rb +11 -8
  95. data/test/isolated/shared.rb +3 -2
  96. data/test/json_gem/json_addition_test.rb +2 -2
  97. data/test/json_gem/json_common_interface_test.rb +8 -6
  98. data/test/json_gem/json_encoding_test.rb +0 -0
  99. data/test/json_gem/json_ext_parser_test.rb +1 -0
  100. data/test/json_gem/json_fixtures_test.rb +3 -2
  101. data/test/json_gem/json_generator_test.rb +56 -38
  102. data/test/json_gem/json_generic_object_test.rb +11 -11
  103. data/test/json_gem/json_parser_test.rb +54 -47
  104. data/test/json_gem/json_string_matching_test.rb +9 -9
  105. data/test/json_gem/test_helper.rb +7 -3
  106. data/test/mem.rb +34 -0
  107. data/test/perf.rb +22 -27
  108. data/test/perf_compat.rb +31 -33
  109. data/test/perf_dump.rb +50 -0
  110. data/test/perf_fast.rb +80 -82
  111. data/test/perf_file.rb +27 -29
  112. data/test/perf_object.rb +65 -69
  113. data/test/perf_once.rb +59 -0
  114. data/test/perf_parser.rb +183 -0
  115. data/test/perf_saj.rb +46 -54
  116. data/test/perf_scp.rb +58 -69
  117. data/test/perf_simple.rb +41 -39
  118. data/test/perf_strict.rb +74 -82
  119. data/test/perf_wab.rb +67 -69
  120. data/test/prec.rb +5 -5
  121. data/test/sample/change.rb +0 -1
  122. data/test/sample/dir.rb +0 -1
  123. data/test/sample/doc.rb +0 -1
  124. data/test/sample/file.rb +0 -1
  125. data/test/sample/group.rb +0 -1
  126. data/test/sample/hasprops.rb +0 -1
  127. data/test/sample/layer.rb +0 -1
  128. data/test/sample/rect.rb +0 -1
  129. data/test/sample/shape.rb +0 -1
  130. data/test/sample/text.rb +0 -1
  131. data/test/sample.rb +16 -16
  132. data/test/sample_json.rb +8 -8
  133. data/test/test_compat.rb +95 -43
  134. data/test/test_custom.rb +73 -51
  135. data/test/test_debian.rb +7 -10
  136. data/test/test_fast.rb +135 -79
  137. data/test/test_file.rb +41 -30
  138. data/test/test_gc.rb +16 -5
  139. data/test/test_generate.rb +5 -5
  140. data/test/test_hash.rb +5 -5
  141. data/test/test_integer_range.rb +9 -9
  142. data/test/test_null.rb +20 -20
  143. data/test/test_object.rb +99 -96
  144. data/test/test_parser.rb +11 -0
  145. data/test/test_parser_debug.rb +27 -0
  146. data/test/test_parser_saj.rb +337 -0
  147. data/test/test_parser_usual.rb +251 -0
  148. data/test/test_rails.rb +2 -2
  149. data/test/test_saj.rb +10 -8
  150. data/test/test_scp.rb +37 -39
  151. data/test/test_strict.rb +40 -32
  152. data/test/test_various.rb +165 -84
  153. data/test/test_wab.rb +48 -44
  154. data/test/test_writer.rb +47 -47
  155. data/test/tests.rb +13 -5
  156. data/test/tests_mimic.rb +12 -3
  157. data/test/tests_mimic_addition.rb +12 -3
  158. metadata +74 -128
  159. data/ext/oj/hash.c +0 -131
  160. data/ext/oj/hash.h +0 -19
  161. data/ext/oj/hash_test.c +0 -491
  162. data/test/activesupport4/decoding_test.rb +0 -108
  163. data/test/activesupport4/encoding_test.rb +0 -531
  164. data/test/activesupport4/test_helper.rb +0 -41
  165. data/test/activesupport5/test_helper.rb +0 -72
  166. data/test/bar.rb +0 -35
  167. data/test/baz.rb +0 -16
  168. data/test/zoo.rb +0 -13
data/ext/oj/code.c CHANGED
@@ -18,8 +18,8 @@ inline static VALUE resolve_classname(VALUE mod, const char *classname) {
18
18
  static VALUE path2class(const char *name) {
19
19
  char class_name[1024];
20
20
  VALUE clas;
21
- char * end = class_name + sizeof(class_name) - 1;
22
- char * s;
21
+ char *end = class_name + sizeof(class_name) - 1;
22
+ char *s;
23
23
  const char *n = name;
24
24
 
25
25
  clas = rb_cObject;
@@ -140,21 +140,17 @@ void oj_code_attrs(VALUE obj, Attr attrs, int depth, Out out, bool with_class) {
140
140
  if (with_class) {
141
141
  fill_indent(out, d2);
142
142
  *out->cur++ = '"';
143
- memcpy(out->cur, out->opts->create_id, out->opts->create_id_len);
144
- out->cur += out->opts->create_id_len;
143
+ APPEND_CHARS(out->cur, out->opts->create_id, out->opts->create_id_len);
145
144
  *out->cur++ = '"';
146
145
  if (0 < out->opts->dump_opts.before_size) {
147
- strcpy(out->cur, out->opts->dump_opts.before_sep);
148
- out->cur += out->opts->dump_opts.before_size;
146
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
149
147
  }
150
148
  *out->cur++ = ':';
151
149
  if (0 < out->opts->dump_opts.after_size) {
152
- strcpy(out->cur, out->opts->dump_opts.after_sep);
153
- out->cur += out->opts->dump_opts.after_size;
150
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
154
151
  }
155
152
  *out->cur++ = '"';
156
- memcpy(out->cur, classname, len);
157
- out->cur += len;
153
+ APPEND_CHARS(out->cur, classname, len);
158
154
  *out->cur++ = '"';
159
155
  no_comma = false;
160
156
  }
@@ -168,17 +164,14 @@ void oj_code_attrs(VALUE obj, Attr attrs, int depth, Out out, bool with_class) {
168
164
  }
169
165
  fill_indent(out, d2);
170
166
  *out->cur++ = '"';
171
- memcpy(out->cur, attrs->name, attrs->len);
172
- out->cur += attrs->len;
167
+ APPEND_CHARS(out->cur, attrs->name, attrs->len);
173
168
  *out->cur++ = '"';
174
169
  if (0 < out->opts->dump_opts.before_size) {
175
- strcpy(out->cur, out->opts->dump_opts.before_sep);
176
- out->cur += out->opts->dump_opts.before_size;
170
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
177
171
  }
178
172
  *out->cur++ = ':';
179
173
  if (0 < out->opts->dump_opts.after_size) {
180
- strcpy(out->cur, out->opts->dump_opts.after_sep);
181
- out->cur += out->opts->dump_opts.after_size;
174
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
182
175
  }
183
176
  if (Qundef == attrs->value) {
184
177
  if (Qundef != attrs->time) {
@@ -190,32 +183,25 @@ void oj_code_attrs(VALUE obj, Attr attrs, int depth, Out out, bool with_class) {
190
183
  default: oj_dump_time(attrs->time, out, false); break;
191
184
  }
192
185
  } else {
193
- char buf[32];
194
- char *b = buf + sizeof(buf) - 1;
195
- int neg = 0;
196
- long num = attrs->num;
186
+ char buf[32];
187
+ char *b = buf + sizeof(buf) - 1;
188
+ bool neg = false;
189
+ long num = attrs->num;
190
+ size_t cnt = 0;
197
191
 
198
192
  if (0 > num) {
199
- neg = 1;
193
+ neg = true;
200
194
  num = -num;
201
195
  }
202
196
  *b-- = '\0';
203
197
  if (0 < num) {
204
- for (; 0 < num; num /= 10, b--) {
205
- *b = (num % 10) + '0';
206
- }
207
- if (neg) {
208
- *b = '-';
209
- } else {
210
- b++;
211
- }
198
+ b = oj_longlong_to_string(num, neg, b);
212
199
  } else {
213
200
  *b = '0';
214
201
  }
215
- assure_size(out, (sizeof(buf) - (b - buf)));
216
- for (; '\0' != *b; b++) {
217
- *out->cur++ = *b;
218
- }
202
+ cnt = sizeof(buf) - (b - buf) - 1;
203
+ assure_size(out, cnt);
204
+ APPEND_CHARS(out->cur, b, cnt);
219
205
  }
220
206
  } else {
221
207
  oj_dump_compat_val(attrs->value, d3, out, true);
data/ext/oj/code.h CHANGED
@@ -17,7 +17,7 @@ typedef struct _code {
17
17
  EncodeFunc encode;
18
18
  DecodeFunc decode;
19
19
  bool active; // For compat mode.
20
- } * Code;
20
+ } *Code;
21
21
 
22
22
  // Used by encode functions.
23
23
  typedef struct _attr {
@@ -26,7 +26,7 @@ typedef struct _attr {
26
26
  VALUE value;
27
27
  long num;
28
28
  VALUE time;
29
- } * Attr;
29
+ } *Attr;
30
30
 
31
31
  extern bool oj_code_dump(Code codes, VALUE obj, int depth, Out out);
32
32
  extern VALUE oj_code_load(Code codes, VALUE clas, VALUE args);
data/ext/oj/compat.c CHANGED
@@ -5,34 +5,27 @@
5
5
 
6
6
  #include "encode.h"
7
7
  #include "err.h"
8
- #include "hash.h"
8
+ #include "intern.h"
9
+ #include "mem.h"
9
10
  #include "oj.h"
10
11
  #include "parse.h"
11
12
  #include "resolve.h"
12
13
  #include "trace.h"
13
14
 
14
15
  static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
15
- const char * key = kval->key;
16
- int klen = kval->klen;
17
- Val parent = stack_peek(&pi->stack);
18
- volatile VALUE rkey = kval->key_val;
16
+ const char *key = kval->key;
17
+ int klen = kval->klen;
18
+ Val parent = stack_peek(&pi->stack);
19
19
 
20
- if (Qundef == rkey && Yes == pi->options.create_ok && NULL != pi->options.create_id &&
20
+ if (Qundef == kval->key_val && Yes == pi->options.create_ok && NULL != pi->options.create_id &&
21
21
  *pi->options.create_id == *key && (int)pi->options.create_id_len == klen &&
22
22
  0 == strncmp(pi->options.create_id, key, klen)) {
23
23
  parent->classname = oj_strndup(str, len);
24
24
  parent->clen = len;
25
25
  } else {
26
- volatile VALUE rstr = rb_str_new(str, len);
27
-
28
- if (Qundef == rkey) {
29
- rkey = rb_str_new(key, klen);
30
- rstr = oj_encode(rstr);
31
- rkey = oj_encode(rkey);
32
- if (Yes == pi->options.sym_key) {
33
- rkey = rb_str_intern(rkey);
34
- }
35
- }
26
+ volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
27
+ volatile VALUE rkey = oj_calc_hash_key(pi, kval);
28
+
36
29
  if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
37
30
  VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
38
31
 
@@ -49,9 +42,7 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
49
42
  } else {
50
43
  rb_hash_aset(parent->val, rkey, rstr);
51
44
  }
52
- if (Yes == pi->options.trace) {
53
- oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
54
- }
45
+ TRACE_PARSE_CALL(pi->options.trace, "set_string", pi, rstr);
55
46
  }
56
47
  }
57
48
 
@@ -63,9 +54,7 @@ static VALUE start_hash(ParseInfo pi) {
63
54
  } else {
64
55
  h = rb_hash_new();
65
56
  }
66
- if (Yes == pi->options.trace) {
67
- oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
68
- }
57
+ TRACE_PARSE_IN(pi->options.trace, "start_hash", pi);
69
58
  return h;
70
59
  }
71
60
 
@@ -84,32 +73,16 @@ static void end_hash(struct _parseInfo *pi) {
84
73
  }
85
74
  }
86
75
  if (0 != parent->classname) {
87
- xfree((char *)parent->classname);
76
+ OJ_R_FREE((char *)parent->classname);
88
77
  parent->classname = 0;
89
78
  }
90
79
  }
91
- if (Yes == pi->options.trace) {
92
- oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
93
- }
94
- }
95
-
96
- static VALUE calc_hash_key(ParseInfo pi, Val parent) {
97
- volatile VALUE rkey = parent->key_val;
98
-
99
- if (Qundef == rkey) {
100
- rkey = rb_str_new(parent->key, parent->klen);
101
- }
102
- rkey = oj_encode(rkey);
103
- if (Yes == pi->options.sym_key) {
104
- rkey = rb_str_intern(rkey);
105
- }
106
- return rkey;
80
+ TRACE_PARSE_HASH_END(pi->options.trace, pi);
107
81
  }
108
82
 
109
83
  static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
110
- volatile VALUE rstr = rb_str_new(str, len);
84
+ volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
111
85
 
112
- rstr = oj_encode(rstr);
113
86
  if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
114
87
  VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
115
88
 
@@ -119,37 +92,27 @@ static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig
119
92
  }
120
93
  }
121
94
  pi->stack.head->val = rstr;
122
- if (Yes == pi->options.trace) {
123
- oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr);
124
- }
95
+ TRACE_PARSE_CALL(pi->options.trace, "add_string", pi, rstr);
125
96
  }
126
97
 
127
98
  static void add_num(ParseInfo pi, NumInfo ni) {
128
99
  pi->stack.head->val = oj_num_as_value(ni);
129
- if (Yes == pi->options.trace) {
130
- oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
131
- }
100
+ TRACE_PARSE_CALL(pi->options.trace, "add_number", pi, pi->stack.head->val);
132
101
  }
133
102
 
134
103
  static void hash_set_num(struct _parseInfo *pi, Val parent, NumInfo ni) {
135
104
  volatile VALUE rval = oj_num_as_value(ni);
136
105
 
137
- if (!oj_use_hash_alt && rb_cHash != rb_obj_class(parent->val)) {
106
+ if (rb_cHash != rb_obj_class(parent->val)) {
138
107
  // The rb_hash_set would still work but the unit tests for the
139
108
  // json gem require the less efficient []= method be called to set
140
109
  // values. Even using the store method to set the values will fail
141
110
  // the unit tests.
142
- rb_funcall(stack_peek(&pi->stack)->val,
143
- rb_intern("[]="),
144
- 2,
145
- calc_hash_key(pi, parent),
146
- rval);
111
+ rb_funcall(stack_peek(&pi->stack)->val, rb_intern("[]="), 2, oj_calc_hash_key(pi, parent), rval);
147
112
  } else {
148
- rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval);
149
- }
150
- if (Yes == pi->options.trace) {
151
- oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval);
113
+ rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), rval);
152
114
  }
115
+ TRACE_PARSE_CALL(pi->options.trace, "set_number", pi, rval);
153
116
  }
154
117
 
155
118
  static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
@@ -158,26 +121,18 @@ static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
158
121
  // json gem require the less efficient []= method be called to set
159
122
  // values. Even using the store method to set the values will fail
160
123
  // the unit tests.
161
- rb_funcall(stack_peek(&pi->stack)->val,
162
- rb_intern("[]="),
163
- 2,
164
- calc_hash_key(pi, parent),
165
- value);
124
+ rb_funcall(stack_peek(&pi->stack)->val, rb_intern("[]="), 2, oj_calc_hash_key(pi, parent), value);
166
125
  } else {
167
- rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value);
168
- }
169
- if (Yes == pi->options.trace) {
170
- oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
126
+ rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), value);
171
127
  }
128
+ TRACE_PARSE_CALL(pi->options.trace, "set_value", pi, value);
172
129
  }
173
130
 
174
131
  static VALUE start_array(ParseInfo pi) {
175
132
  if (Qnil != pi->options.array_class) {
176
133
  return rb_class_new_instance(0, NULL, pi->options.array_class);
177
134
  }
178
- if (Yes == pi->options.trace) {
179
- oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
180
- }
135
+ TRACE_PARSE_IN(pi->options.trace, "start_array", pi);
181
136
  return rb_ary_new();
182
137
  }
183
138
 
@@ -193,15 +148,12 @@ static void array_append_num(ParseInfo pi, NumInfo ni) {
193
148
  } else {
194
149
  rb_ary_push(parent->val, rval);
195
150
  }
196
- if (Yes == pi->options.trace) {
197
- oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
198
- }
151
+ TRACE_PARSE_CALL(pi->options.trace, "append_number", pi, rval);
199
152
  }
200
153
 
201
154
  static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
202
- volatile VALUE rstr = rb_str_new(str, len);
155
+ volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
203
156
 
204
- rstr = oj_encode(rstr);
205
157
  if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
206
158
  VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
207
159
 
@@ -211,9 +163,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
211
163
  }
212
164
  }
213
165
  rb_ary_push(stack_peek(&pi->stack)->val, rstr);
214
- if (Yes == pi->options.trace) {
215
- oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
216
- }
166
+ TRACE_PARSE_CALL(pi->options.trace, "append_string", pi, rstr);
217
167
  }
218
168
 
219
169
  void oj_set_compat_callbacks(ParseInfo pi) {