oj 3.13.5 → 3.13.9

Sign up to get free protection for your applications and to get access to all the features.
data/ext/oj/oj.c CHANGED
@@ -94,6 +94,7 @@ VALUE oj_indent_sym;
94
94
  VALUE oj_object_class_sym;
95
95
  VALUE oj_quirks_mode_sym;
96
96
  VALUE oj_safe_sym;
97
+ VALUE oj_symbolize_names_sym;
97
98
  VALUE oj_trace_sym;
98
99
 
99
100
  static VALUE allow_blank_sym;
@@ -308,106 +309,76 @@ static VALUE get_def_opts(VALUE self) {
308
309
  rb_hash_aset(opts, sec_prec_sym, INT2FIX(oj_default_options.sec_prec));
309
310
  rb_hash_aset(opts,
310
311
  circular_sym,
311
- (Yes == oj_default_options.circular)
312
- ? Qtrue
313
- : ((No == oj_default_options.circular) ? Qfalse : Qnil));
314
- rb_hash_aset(opts,
315
- class_cache_sym,
316
- (Yes == oj_default_options.class_cache)
317
- ? Qtrue
318
- : ((No == oj_default_options.class_cache) ? Qfalse : Qnil));
319
- rb_hash_aset(opts,
320
- auto_define_sym,
321
- (Yes == oj_default_options.auto_define)
322
- ? Qtrue
323
- : ((No == oj_default_options.auto_define) ? Qfalse : Qnil));
312
+ (Yes == oj_default_options.circular) ? Qtrue : ((No == oj_default_options.circular) ? Qfalse : Qnil));
313
+ rb_hash_aset(
314
+ opts,
315
+ class_cache_sym,
316
+ (Yes == oj_default_options.class_cache) ? Qtrue : ((No == oj_default_options.class_cache) ? Qfalse : Qnil));
317
+ rb_hash_aset(
318
+ opts,
319
+ auto_define_sym,
320
+ (Yes == oj_default_options.auto_define) ? Qtrue : ((No == oj_default_options.auto_define) ? Qfalse : Qnil));
324
321
  rb_hash_aset(opts,
325
322
  symbol_keys_sym,
326
- (Yes == oj_default_options.sym_key)
327
- ? Qtrue
328
- : ((No == oj_default_options.sym_key) ? Qfalse : Qnil));
329
- rb_hash_aset(opts,
330
- bigdecimal_as_decimal_sym,
331
- (Yes == oj_default_options.bigdec_as_num)
332
- ? Qtrue
333
- : ((No == oj_default_options.bigdec_as_num) ? Qfalse : Qnil));
334
- rb_hash_aset(opts,
335
- oj_create_additions_sym,
336
- (Yes == oj_default_options.create_ok)
337
- ? Qtrue
338
- : ((No == oj_default_options.create_ok) ? Qfalse : Qnil));
323
+ (Yes == oj_default_options.sym_key) ? Qtrue : ((No == oj_default_options.sym_key) ? Qfalse : Qnil));
324
+ rb_hash_aset(
325
+ opts,
326
+ bigdecimal_as_decimal_sym,
327
+ (Yes == oj_default_options.bigdec_as_num) ? Qtrue : ((No == oj_default_options.bigdec_as_num) ? Qfalse : Qnil));
328
+ rb_hash_aset(
329
+ opts,
330
+ oj_create_additions_sym,
331
+ (Yes == oj_default_options.create_ok) ? Qtrue : ((No == oj_default_options.create_ok) ? Qfalse : Qnil));
339
332
  rb_hash_aset(opts,
340
333
  use_to_json_sym,
341
- (Yes == oj_default_options.to_json)
342
- ? Qtrue
343
- : ((No == oj_default_options.to_json) ? Qfalse : Qnil));
334
+ (Yes == oj_default_options.to_json) ? Qtrue : ((No == oj_default_options.to_json) ? Qfalse : Qnil));
344
335
  rb_hash_aset(opts,
345
336
  use_to_hash_sym,
346
- (Yes == oj_default_options.to_hash)
347
- ? Qtrue
348
- : ((No == oj_default_options.to_hash) ? Qfalse : Qnil));
337
+ (Yes == oj_default_options.to_hash) ? Qtrue : ((No == oj_default_options.to_hash) ? Qfalse : Qnil));
349
338
  rb_hash_aset(opts,
350
339
  use_as_json_sym,
351
- (Yes == oj_default_options.as_json)
352
- ? Qtrue
353
- : ((No == oj_default_options.as_json) ? Qfalse : Qnil));
340
+ (Yes == oj_default_options.as_json) ? Qtrue : ((No == oj_default_options.as_json) ? Qfalse : Qnil));
354
341
  rb_hash_aset(opts,
355
342
  use_raw_json_sym,
356
- (Yes == oj_default_options.raw_json)
357
- ? Qtrue
358
- : ((No == oj_default_options.raw_json) ? Qfalse : Qnil));
343
+ (Yes == oj_default_options.raw_json) ? Qtrue : ((No == oj_default_options.raw_json) ? Qfalse : Qnil));
359
344
  rb_hash_aset(opts,
360
345
  nilnil_sym,
361
- (Yes == oj_default_options.nilnil)
362
- ? Qtrue
363
- : ((No == oj_default_options.nilnil) ? Qfalse : Qnil));
364
- rb_hash_aset(opts,
365
- empty_string_sym,
366
- (Yes == oj_default_options.empty_string)
367
- ? Qtrue
368
- : ((No == oj_default_options.empty_string) ? Qfalse : Qnil));
346
+ (Yes == oj_default_options.nilnil) ? Qtrue : ((No == oj_default_options.nilnil) ? Qfalse : Qnil));
347
+ rb_hash_aset(
348
+ opts,
349
+ empty_string_sym,
350
+ (Yes == oj_default_options.empty_string) ? Qtrue : ((No == oj_default_options.empty_string) ? Qfalse : Qnil));
369
351
  rb_hash_aset(opts,
370
352
  allow_gc_sym,
371
- (Yes == oj_default_options.allow_gc)
372
- ? Qtrue
373
- : ((No == oj_default_options.allow_gc) ? Qfalse : Qnil));
374
- rb_hash_aset(opts,
375
- oj_quirks_mode_sym,
376
- (Yes == oj_default_options.quirks_mode)
377
- ? Qtrue
378
- : ((No == oj_default_options.quirks_mode) ? Qfalse : Qnil));
379
- rb_hash_aset(opts,
380
- allow_invalid_unicode_sym,
381
- (Yes == oj_default_options.allow_invalid)
382
- ? Qtrue
383
- : ((No == oj_default_options.allow_invalid) ? Qfalse : Qnil));
384
- rb_hash_aset(opts,
385
- oj_allow_nan_sym,
386
- (Yes == oj_default_options.allow_nan)
387
- ? Qtrue
388
- : ((No == oj_default_options.allow_nan) ? Qfalse : Qnil));
353
+ (Yes == oj_default_options.allow_gc) ? Qtrue : ((No == oj_default_options.allow_gc) ? Qfalse : Qnil));
354
+ rb_hash_aset(
355
+ opts,
356
+ oj_quirks_mode_sym,
357
+ (Yes == oj_default_options.quirks_mode) ? Qtrue : ((No == oj_default_options.quirks_mode) ? Qfalse : Qnil));
358
+ rb_hash_aset(
359
+ opts,
360
+ allow_invalid_unicode_sym,
361
+ (Yes == oj_default_options.allow_invalid) ? Qtrue : ((No == oj_default_options.allow_invalid) ? Qfalse : Qnil));
362
+ rb_hash_aset(
363
+ opts,
364
+ oj_allow_nan_sym,
365
+ (Yes == oj_default_options.allow_nan) ? Qtrue : ((No == oj_default_options.allow_nan) ? Qfalse : Qnil));
389
366
  rb_hash_aset(opts,
390
367
  oj_trace_sym,
391
- (Yes == oj_default_options.trace)
392
- ? Qtrue
393
- : ((No == oj_default_options.trace) ? Qfalse : Qnil));
368
+ (Yes == oj_default_options.trace) ? Qtrue : ((No == oj_default_options.trace) ? Qfalse : Qnil));
394
369
  rb_hash_aset(opts,
395
370
  oj_safe_sym,
396
- (Yes == oj_default_options.safe)
397
- ? Qtrue
398
- : ((No == oj_default_options.safe) ? Qfalse : Qnil));
371
+ (Yes == oj_default_options.safe) ? Qtrue : ((No == oj_default_options.safe) ? Qfalse : Qnil));
399
372
  rb_hash_aset(opts, float_prec_sym, INT2FIX(oj_default_options.float_prec));
400
373
  rb_hash_aset(opts, cache_str_sym, INT2FIX(oj_default_options.cache_str));
401
- rb_hash_aset(opts,
402
- ignore_under_sym,
403
- (Yes == oj_default_options.ignore_under)
404
- ? Qtrue
405
- : ((No == oj_default_options.ignore_under) ? Qfalse : Qnil));
406
- rb_hash_aset(opts,
407
- cache_keys_sym,
408
- (Yes == oj_default_options.cache_keys)
409
- ? Qtrue
410
- : ((No == oj_default_options.cache_keys) ? Qfalse : Qnil));
374
+ rb_hash_aset(
375
+ opts,
376
+ ignore_under_sym,
377
+ (Yes == oj_default_options.ignore_under) ? Qtrue : ((No == oj_default_options.ignore_under) ? Qfalse : Qnil));
378
+ rb_hash_aset(
379
+ opts,
380
+ cache_keys_sym,
381
+ (Yes == oj_default_options.cache_keys) ? Qtrue : ((No == oj_default_options.cache_keys) ? Qfalse : Qnil));
411
382
  switch (oj_default_options.mode) {
412
383
  case StrictMode: rb_hash_aset(opts, mode_sym, strict_sym); break;
413
384
  case CompatMode: rb_hash_aset(opts, mode_sym, compat_sym); break;
@@ -453,30 +424,25 @@ static VALUE get_def_opts(VALUE self) {
453
424
  default: rb_hash_aset(opts, bigdecimal_load_sym, auto_sym); break;
454
425
  }
455
426
  rb_hash_aset(opts, compat_bigdecimal_sym, oj_default_options.compat_bigdec ? Qtrue : Qfalse);
427
+ rb_hash_aset(opts,
428
+ create_id_sym,
429
+ (NULL == oj_default_options.create_id) ? Qnil : rb_str_new2(oj_default_options.create_id));
456
430
  rb_hash_aset(
457
431
  opts,
458
- create_id_sym,
459
- (NULL == oj_default_options.create_id) ? Qnil : rb_str_new2(oj_default_options.create_id));
460
- rb_hash_aset(opts,
461
- oj_space_sym,
462
- (0 == oj_default_options.dump_opts.after_size)
463
- ? Qnil
464
- : rb_str_new2(oj_default_options.dump_opts.after_sep));
465
- rb_hash_aset(opts,
466
- oj_space_before_sym,
467
- (0 == oj_default_options.dump_opts.before_size)
468
- ? Qnil
469
- : rb_str_new2(oj_default_options.dump_opts.before_sep));
470
- rb_hash_aset(opts,
471
- oj_object_nl_sym,
472
- (0 == oj_default_options.dump_opts.hash_size)
473
- ? Qnil
474
- : rb_str_new2(oj_default_options.dump_opts.hash_nl));
475
- rb_hash_aset(opts,
476
- oj_array_nl_sym,
477
- (0 == oj_default_options.dump_opts.array_size)
478
- ? Qnil
479
- : rb_str_new2(oj_default_options.dump_opts.array_nl));
432
+ oj_space_sym,
433
+ (0 == oj_default_options.dump_opts.after_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.after_sep));
434
+ rb_hash_aset(
435
+ opts,
436
+ oj_space_before_sym,
437
+ (0 == oj_default_options.dump_opts.before_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.before_sep));
438
+ rb_hash_aset(
439
+ opts,
440
+ oj_object_nl_sym,
441
+ (0 == oj_default_options.dump_opts.hash_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.hash_nl));
442
+ rb_hash_aset(
443
+ opts,
444
+ oj_array_nl_sym,
445
+ (0 == oj_default_options.dump_opts.array_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.array_nl));
480
446
 
481
447
  switch (oj_default_options.dump_opts.nan_dump) {
482
448
  case NullNan: rb_hash_aset(opts, nan_sym, null_sym); break;
@@ -584,16 +550,14 @@ static VALUE set_def_opts(VALUE self, VALUE opts) {
584
550
  return Qnil;
585
551
  }
586
552
 
587
- bool oj_hash_has_key(VALUE hash, VALUE key)
588
- {
553
+ bool oj_hash_has_key(VALUE hash, VALUE key) {
589
554
  if (Qundef == rb_hash_lookup2(hash, key, Qundef)) {
590
555
  return false;
591
556
  }
592
557
  return true;
593
558
  }
594
559
 
595
- bool set_yesno_options(VALUE key, VALUE value, Options copts)
596
- {
560
+ bool set_yesno_options(VALUE key, VALUE value, Options copts) {
597
561
  struct _yesNoOpt ynos[] = {{circular_sym, &copts->circular},
598
562
  {auto_define_sym, &copts->auto_define},
599
563
  {symbol_keys_sym, &copts->sym_key},
@@ -616,29 +580,26 @@ bool set_yesno_options(VALUE key, VALUE value, Options copts)
616
580
  {oj_create_additions_sym, &copts->create_ok},
617
581
  {cache_keys_sym, &copts->cache_keys},
618
582
  {Qnil, 0}};
619
- YesNoOpt o;
620
-
621
- for (o = ynos; 0 != o->attr; o++) {
622
- if (key == o->sym) {
623
- if (Qnil == value) {
624
- *o->attr = NotSet;
625
- } else if (Qtrue == value) {
626
- *o->attr = Yes;
627
- } else if (Qfalse == value) {
628
- *o->attr = No;
629
- } else {
630
- rb_raise(rb_eArgError,
631
- "%s must be true, false, or nil.",
632
- rb_id2name(key));
633
- }
634
- return true;
635
- }
636
- }
583
+ YesNoOpt o;
584
+
585
+ for (o = ynos; 0 != o->attr; o++) {
586
+ if (key == o->sym) {
587
+ if (Qnil == value) {
588
+ *o->attr = NotSet;
589
+ } else if (Qtrue == value) {
590
+ *o->attr = Yes;
591
+ } else if (Qfalse == value) {
592
+ *o->attr = No;
593
+ } else {
594
+ rb_raise(rb_eArgError, "%s must be true, false, or nil.", rb_id2name(key));
595
+ }
596
+ return true;
597
+ }
598
+ }
637
599
  return false;
638
600
  }
639
601
 
640
- static int parse_options_cb(VALUE k, VALUE v, VALUE opts)
641
- {
602
+ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
642
603
  Options copts = (Options)opts;
643
604
  size_t len;
644
605
 
@@ -753,8 +714,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts)
753
714
  } else if (rails_sym == v) {
754
715
  copts->mode = RailsMode;
755
716
  } else {
756
- rb_raise(rb_eArgError,
757
- ":mode must be :object, :strict, :compat, :null, :custom, :rails, or :wab.");
717
+ rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, :null, :custom, :rails, or :wab.");
758
718
  }
759
719
  } else if (time_format_sym == k) {
760
720
  if (unix_sym == v) {
@@ -780,8 +740,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts)
780
740
  } else if (unicode_xss_sym == v) {
781
741
  copts->escape_mode = JXEsc;
782
742
  } else {
783
- rb_raise(rb_eArgError,
784
- ":encoding must be :newline, :json, :xss_safe, :unicode_xss, or :ascii.");
743
+ rb_raise(rb_eArgError, ":encoding must be :newline, :json, :xss_safe, :unicode_xss, or :ascii.");
785
744
  }
786
745
  } else if (bigdecimal_load_sym == k) {
787
746
  if (Qnil == v) {
@@ -892,7 +851,6 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts)
892
851
  if (Qnil == v) {
893
852
  return ST_CONTINUE;
894
853
  }
895
-
896
854
  if (null_sym == v) {
897
855
  copts->dump_opts.nan_dump = NullNan;
898
856
  } else if (huge_sym == v) {
@@ -910,7 +868,6 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts)
910
868
  if (Qnil == v) {
911
869
  return ST_CONTINUE;
912
870
  }
913
-
914
871
  if (Qtrue == v) {
915
872
  copts->dump_opts.omit_nil = true;
916
873
  } else if (Qfalse == v) {
@@ -918,7 +875,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts)
918
875
  } else {
919
876
  rb_raise(rb_eArgError, ":omit_nil must be true or false.");
920
877
  }
921
- } else if(oj_ascii_only_sym == k) {
878
+ } else if (oj_ascii_only_sym == k) {
922
879
  // This is here only for backwards compatibility with the original Oj.
923
880
  if (Qtrue == v) {
924
881
  copts->escape_mode = ASCIIEsc;
@@ -968,7 +925,6 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts)
968
925
  if (Qnil == v) {
969
926
  return ST_CONTINUE;
970
927
  }
971
-
972
928
  if (TYPE(v) == T_STRUCT && rb_obj_class(v) == rb_cRange) {
973
929
  VALUE min = rb_funcall(v, oj_begin_id, 0);
974
930
  VALUE max = rb_funcall(v, oj_end_id, 0);
@@ -982,8 +938,12 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts)
982
938
  } else if (Qfalse != v) {
983
939
  rb_raise(rb_eArgError, ":integer_range must be a range of Fixnum.");
984
940
  }
941
+ } else if (symbol_keys_sym == k || oj_symbolize_names_sym == k) {
942
+ if (Qnil == v) {
943
+ return ST_CONTINUE;
944
+ }
945
+ copts->sym_key = (Qtrue == v) ? Yes : No;
985
946
  }
986
-
987
947
  return ST_CONTINUE;
988
948
  }
989
949
 
@@ -1014,9 +974,7 @@ static int match_string_cb(VALUE key, VALUE value, VALUE rx) {
1014
974
  rb_raise(rb_eArgError, "%s", rc->err);
1015
975
  }
1016
976
  break;
1017
- default:
1018
- rb_raise(rb_eArgError, "for :match_string, keys must either a String or RegExp.");
1019
- break;
977
+ default: rb_raise(rb_eArgError, "for :match_string, keys must either a String or RegExp."); break;
1020
978
  }
1021
979
  return ST_CONTINUE;
1022
980
  }
@@ -1184,9 +1142,7 @@ static VALUE load_file(int argc, VALUE *argv, VALUE self) {
1184
1142
  } else if (wab_sym == v) {
1185
1143
  mode = WabMode;
1186
1144
  } else {
1187
- rb_raise(
1188
- rb_eArgError,
1189
- ":mode must be :object, :strict, :compat, :null, :custom, :rails, or :wab.");
1145
+ rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, :null, :custom, :rails, or :wab.");
1190
1146
  }
1191
1147
  }
1192
1148
  }
@@ -1264,16 +1220,15 @@ static VALUE safe_load(VALUE self, VALUE doc) {
1264
1220
  */
1265
1221
 
1266
1222
  struct dump_arg {
1267
- struct _out *out;
1223
+ struct _out * out;
1268
1224
  struct _options *copts;
1269
- int argc;
1270
- VALUE *argv;
1225
+ int argc;
1226
+ VALUE * argv;
1271
1227
  };
1272
1228
 
1273
- static VALUE dump_body(VALUE a)
1274
- {
1229
+ static VALUE dump_body(VALUE a) {
1275
1230
  volatile struct dump_arg *arg = (void *)a;
1276
- VALUE rstr;
1231
+ VALUE rstr;
1277
1232
 
1278
1233
  oj_dump_obj_to_json_using_params(*arg->argv, arg->copts, arg->out, arg->argc - 1, arg->argv + 1);
1279
1234
  if (0 == arg->out->buf) {
@@ -1285,8 +1240,7 @@ static VALUE dump_body(VALUE a)
1285
1240
  return rstr;
1286
1241
  }
1287
1242
 
1288
- static VALUE dump_ensure(VALUE a)
1289
- {
1243
+ static VALUE dump_ensure(VALUE a) {
1290
1244
  volatile struct dump_arg *arg = (void *)a;
1291
1245
 
1292
1246
  if (arg->out->allocated) {
@@ -1320,10 +1274,10 @@ static VALUE dump(int argc, VALUE *argv, VALUE self) {
1320
1274
  if (CompatMode == copts.mode && copts.escape_mode != ASCIIEsc) {
1321
1275
  copts.escape_mode = JSONEsc;
1322
1276
  }
1323
- arg.out = &out;
1277
+ arg.out = &out;
1324
1278
  arg.copts = &copts;
1325
- arg.argc = argc;
1326
- arg.argv = argv;
1279
+ arg.argc = argc;
1280
+ arg.argv = argv;
1327
1281
 
1328
1282
  arg.out->buf = buf;
1329
1283
  arg.out->end = buf + sizeof(buf) - 10;
@@ -2015,6 +1969,8 @@ void Init_oj() {
2015
1969
  rb_gc_register_address(&strict_sym);
2016
1970
  symbol_keys_sym = ID2SYM(rb_intern("symbol_keys"));
2017
1971
  rb_gc_register_address(&symbol_keys_sym);
1972
+ oj_symbolize_names_sym = ID2SYM(rb_intern("symbolize_names"));
1973
+ rb_gc_register_address(&oj_symbolize_names_sym);
2018
1974
  time_format_sym = ID2SYM(rb_intern("time_format"));
2019
1975
  rb_gc_register_address(&time_format_sym);
2020
1976
  unicode_xss_sym = ID2SYM(rb_intern("unicode_xss"));
data/ext/oj/oj.h CHANGED
@@ -311,6 +311,7 @@ extern VALUE oj_object_nl_sym;
311
311
  extern VALUE oj_quirks_mode_sym;
312
312
  extern VALUE oj_space_before_sym;
313
313
  extern VALUE oj_space_sym;
314
+ extern VALUE oj_symbolize_names_sym;
314
315
  extern VALUE oj_trace_sym;
315
316
 
316
317
  extern VALUE oj_slash_string;
data/ext/oj/parse.c CHANGED
@@ -904,9 +904,17 @@ void oj_set_error_at(ParseInfo pi,
904
904
  char * end = p + sizeof(msg) - 2;
905
905
  char * start;
906
906
  Val vp;
907
+ int mlen;
907
908
 
908
909
  va_start(ap, format);
909
- p += vsnprintf(msg, sizeof(msg) - 1, format, ap);
910
+ mlen = vsnprintf(msg, sizeof(msg) - 1, format, ap);
911
+ if (0 < mlen) {
912
+ if (sizeof(msg) - 2 < (size_t)mlen) {
913
+ p = end - 2;
914
+ } else {
915
+ p += mlen;
916
+ }
917
+ }
910
918
  va_end(ap);
911
919
  pi->err.clas = err_clas;
912
920
  if (p + 3 < end) {
data/ext/oj/parser.c CHANGED
@@ -610,6 +610,9 @@ static void parse(ojParser p, const byte *json) {
610
610
  printf("*** parse - mode: %c %s\n", p->map[256], (const char *)json);
611
611
  #endif
612
612
  for (; '\0' != *b; b++) {
613
+ #if DEBUG
614
+ printf("*** parse - mode: %c %02x %s => %c\n", p->map[256], *b, b, p->map[*b]);
615
+ #endif
613
616
  switch (p->map[*b]) {
614
617
  case SKIP_NEWLINE:
615
618
  p->line++;
@@ -887,13 +890,17 @@ static void parse(ojParser p, const byte *json) {
887
890
  buf_append_string(&p->buf, (const char *)start, b - start);
888
891
  }
889
892
  if ('"' == *b) {
893
+ p->funcs[p->stack[p->depth]].add_str(p);
890
894
  p->map = p->next_map;
891
895
  break;
892
896
  }
893
897
  b--;
894
898
  break;
895
899
  case STR_SLASH: p->map = esc_map; break;
896
- case STR_QUOTE: p->map = p->next_map; break;
900
+ case STR_QUOTE:
901
+ p->funcs[p->stack[p->depth]].add_str(p);
902
+ p->map = p->next_map;
903
+ break;
897
904
  case ESC_U:
898
905
  p->map = u_map;
899
906
  p->ri = 0;
@@ -1135,13 +1142,42 @@ extern void oj_set_parser_saj(ojParser p);
1135
1142
  extern void oj_set_parser_usual(ojParser p);
1136
1143
  extern void oj_set_parser_debug(ojParser p);
1137
1144
 
1145
+ static int opt_cb(VALUE rkey, VALUE value, VALUE ptr) {
1146
+ ojParser p = (ojParser)ptr;
1147
+ const char *key = NULL;
1148
+ char set_key[64];
1149
+ long klen;
1150
+
1151
+ switch (rb_type(rkey)) {
1152
+ case RUBY_T_SYMBOL:
1153
+ rkey = rb_sym2str(rkey);
1154
+ // fall through
1155
+ case RUBY_T_STRING:
1156
+ key = rb_string_value_ptr(&rkey);
1157
+ klen = RSTRING_LEN(rkey);
1158
+ break;
1159
+ default: rb_raise(rb_eArgError, "option keys must be a symbol or string");
1160
+ }
1161
+ if ((long)sizeof(set_key) - 1 <= klen) {
1162
+ return ST_CONTINUE;
1163
+ }
1164
+ memcpy(set_key, key, klen);
1165
+ set_key[klen] = '=';
1166
+ set_key[klen + 1] = '\0';
1167
+ p->option(p, set_key, value);
1168
+
1169
+ return ST_CONTINUE;
1170
+ }
1171
+
1138
1172
  /* Document-method: new
1139
1173
  * call-seq: new(mode=nil)
1140
1174
  *
1141
1175
  * Creates a new Parser with the specified mode. If no mode is provided
1142
- * validation is assumed.
1176
+ * validation is assumed. Optional arguments can be provided that match the
1177
+ * mode. For example with the :usual mode the call might look like
1178
+ * Oj::Parser.new(:usual, cache_keys: true).
1143
1179
  */
1144
- static VALUE parser_new(VALUE self, VALUE mode) {
1180
+ static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
1145
1181
  ojParser p = ALLOC(struct _ojParser);
1146
1182
 
1147
1183
  #if HAVE_RB_EXT_RACTOR_SAFE
@@ -1151,33 +1187,45 @@ static VALUE parser_new(VALUE self, VALUE mode) {
1151
1187
  memset(p, 0, sizeof(struct _ojParser));
1152
1188
  buf_init(&p->key);
1153
1189
  buf_init(&p->buf);
1154
-
1155
1190
  p->map = value_map;
1156
- if (Qnil == mode) {
1157
- oj_set_parser_validator(p);
1191
+
1192
+ if (argc < 1) {
1193
+ oj_set_parser_validator(p);
1158
1194
  } else {
1159
- const char *ms = NULL;
1160
-
1161
- switch (rb_type(mode)) {
1162
- case RUBY_T_SYMBOL:
1163
- mode = rb_sym2str(mode);
1164
- // fall through
1165
- case RUBY_T_STRING: ms = RSTRING_PTR(mode); break;
1166
- default: rb_raise(rb_eArgError, "mode must be :validate, :usual, :saj, or :object");
1167
- }
1168
- if (0 == strcmp("usual", ms) || 0 == strcmp("standard", ms) || 0 == strcmp("strict", ms) ||
1169
- 0 == strcmp("compat", ms)) {
1170
- oj_set_parser_usual(p);
1171
- } else if (0 == strcmp("object", ms)) {
1172
- // TBD
1173
- } else if (0 == strcmp("saj", ms)) {
1174
- oj_set_parser_saj(p);
1175
- } else if (0 == strcmp("validate", ms)) {
1195
+ VALUE mode = argv[0];
1196
+
1197
+ if (Qnil == mode) {
1176
1198
  oj_set_parser_validator(p);
1177
- } else if (0 == strcmp("debug", ms)) {
1178
- oj_set_parser_debug(p);
1179
1199
  } else {
1180
- rb_raise(rb_eArgError, "mode must be :validate, :usual, :saj, or :object");
1200
+ const char *ms = NULL;
1201
+
1202
+ switch (rb_type(mode)) {
1203
+ case RUBY_T_SYMBOL:
1204
+ mode = rb_sym2str(mode);
1205
+ // fall through
1206
+ case RUBY_T_STRING: ms = RSTRING_PTR(mode); break;
1207
+ default: rb_raise(rb_eArgError, "mode must be :validate, :usual, :saj, or :object");
1208
+ }
1209
+ if (0 == strcmp("usual", ms) || 0 == strcmp("standard", ms) || 0 == strcmp("strict", ms) ||
1210
+ 0 == strcmp("compat", ms)) {
1211
+ oj_set_parser_usual(p);
1212
+ } else if (0 == strcmp("object", ms)) {
1213
+ // TBD
1214
+ } else if (0 == strcmp("saj", ms)) {
1215
+ oj_set_parser_saj(p);
1216
+ } else if (0 == strcmp("validate", ms)) {
1217
+ oj_set_parser_validator(p);
1218
+ } else if (0 == strcmp("debug", ms)) {
1219
+ oj_set_parser_debug(p);
1220
+ } else {
1221
+ rb_raise(rb_eArgError, "mode must be :validate, :usual, :saj, or :object");
1222
+ }
1223
+ }
1224
+ if (1 < argc) {
1225
+ VALUE ropts = argv[1];
1226
+
1227
+ Check_Type(ropts, T_HASH);
1228
+ rb_hash_foreach(ropts, opt_cb, (VALUE)p);
1181
1229
  }
1182
1230
  }
1183
1231
  return Data_Wrap_Struct(parser_class, parser_mark, parser_free, p);
@@ -1204,7 +1252,7 @@ static VALUE parser_new(VALUE self, VALUE mode) {
1204
1252
  * - *:usual*
1205
1253
  * - _cache_keys=_ sets the value of the _cache_keys_ flag.
1206
1254
  * - _cache_keys_ returns the value of the _cache_keys_ flag.
1207
- * - _cache_strings=_ sets the value of the _cache_strings_ to an positive integer less than 35. Strings shorter than
1255
+ * - _cache_strings=_ sets the value of the _cache_strings_ to a positive integer less than 35. Strings shorter than
1208
1256
  * that length are cached.
1209
1257
  * - _cache_strings_ returns the value of the _cache_strings_ integer value.
1210
1258
  * - _cache_expunge=_ sets the value of the _cache_expunge_ where 0 never expunges, 1 expunges slowly, 2 expunges
@@ -1469,7 +1517,7 @@ static VALUE parser_validate(VALUE self) {
1469
1517
  */
1470
1518
  void oj_parser_init() {
1471
1519
  parser_class = rb_define_class_under(Oj, "Parser", rb_cObject);
1472
- rb_define_module_function(parser_class, "new", parser_new, 1);
1520
+ rb_define_module_function(parser_class, "new", parser_new, -1);
1473
1521
  rb_define_method(parser_class, "parse", parser_parse, 1);
1474
1522
  rb_define_method(parser_class, "load", parser_load, 1);
1475
1523
  rb_define_method(parser_class, "file", parser_file, 1);