oj 3.11.0 → 3.11.5

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.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -1
  3. data/ext/oj/buf.h +34 -38
  4. data/ext/oj/cache8.c +59 -62
  5. data/ext/oj/cache8.h +8 -7
  6. data/ext/oj/circarray.c +33 -35
  7. data/ext/oj/circarray.h +11 -9
  8. data/ext/oj/code.c +170 -174
  9. data/ext/oj/code.h +21 -20
  10. data/ext/oj/compat.c +159 -166
  11. data/ext/oj/custom.c +802 -851
  12. data/ext/oj/dump.c +766 -778
  13. data/ext/oj/dump.h +49 -51
  14. data/ext/oj/dump_compat.c +1 -0
  15. data/ext/oj/dump_leaf.c +116 -157
  16. data/ext/oj/dump_object.c +609 -628
  17. data/ext/oj/dump_strict.c +318 -327
  18. data/ext/oj/encode.h +3 -4
  19. data/ext/oj/err.c +39 -25
  20. data/ext/oj/err.h +24 -15
  21. data/ext/oj/extconf.rb +2 -1
  22. data/ext/oj/fast.c +1008 -1038
  23. data/ext/oj/hash.c +62 -66
  24. data/ext/oj/hash.h +7 -6
  25. data/ext/oj/hash_test.c +450 -443
  26. data/ext/oj/mimic_json.c +413 -402
  27. data/ext/oj/object.c +559 -528
  28. data/ext/oj/odd.c +123 -128
  29. data/ext/oj/odd.h +27 -25
  30. data/ext/oj/oj.c +1131 -924
  31. data/ext/oj/oj.h +286 -298
  32. data/ext/oj/parse.c +938 -930
  33. data/ext/oj/parse.h +70 -69
  34. data/ext/oj/rails.c +836 -839
  35. data/ext/oj/rails.h +7 -7
  36. data/ext/oj/reader.c +135 -140
  37. data/ext/oj/reader.h +66 -79
  38. data/ext/oj/resolve.c +43 -43
  39. data/ext/oj/resolve.h +3 -2
  40. data/ext/oj/rxclass.c +67 -68
  41. data/ext/oj/rxclass.h +12 -10
  42. data/ext/oj/saj.c +451 -479
  43. data/ext/oj/scp.c +93 -103
  44. data/ext/oj/sparse.c +770 -730
  45. data/ext/oj/stream_writer.c +120 -149
  46. data/ext/oj/strict.c +71 -86
  47. data/ext/oj/string_writer.c +198 -243
  48. data/ext/oj/trace.c +29 -33
  49. data/ext/oj/trace.h +14 -11
  50. data/ext/oj/util.c +103 -103
  51. data/ext/oj/util.h +3 -2
  52. data/ext/oj/val_stack.c +47 -47
  53. data/ext/oj/val_stack.h +79 -86
  54. data/ext/oj/wab.c +291 -309
  55. data/lib/oj/bag.rb +1 -0
  56. data/lib/oj/easy_hash.rb +5 -4
  57. data/lib/oj/mimic.rb +0 -12
  58. data/lib/oj/version.rb +1 -1
  59. data/test/activerecord/result_test.rb +7 -2
  60. data/test/foo.rb +35 -32
  61. data/test/helper.rb +10 -0
  62. data/test/json_gem/json_generator_test.rb +15 -3
  63. data/test/json_gem/test_helper.rb +8 -0
  64. data/test/test_compat.rb +2 -2
  65. data/test/test_generate.rb +21 -0
  66. data/test/test_hash.rb +10 -0
  67. data/test/test_scp.rb +1 -1
  68. metadata +4 -2
data/ext/oj/encode.h CHANGED
@@ -1,15 +1,14 @@
1
1
  // Copyright (c) 2011 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
2
3
 
3
4
  #ifndef OJ_ENCODE_H
4
5
  #define OJ_ENCODE_H
5
6
 
7
+ #include "oj.h"
6
8
  #include "ruby.h"
7
9
  #include "ruby/encoding.h"
8
10
 
9
- #include "oj.h"
10
-
11
- static inline VALUE
12
- oj_encode(VALUE rstr) {
11
+ static inline VALUE oj_encode(VALUE rstr) {
13
12
  rb_enc_associate(rstr, oj_utf8_encoding);
14
13
  return rstr;
15
14
  }
data/ext/oj/err.c CHANGED
@@ -1,12 +1,12 @@
1
1
  // Copyright (c) 2011 Peter Ohler. All rights reserved.
2
-
3
- #include <stdarg.h>
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
4
3
 
5
4
  #include "err.h"
6
5
 
7
- void
8
- oj_err_set(Err e, VALUE clas, const char *format, ...) {
9
- va_list ap;
6
+ #include <stdarg.h>
7
+
8
+ void oj_err_set(Err e, VALUE clas, const char *format, ...) {
9
+ va_list ap;
10
10
 
11
11
  va_start(ap, format);
12
12
  e->clas = clas;
@@ -14,41 +14,55 @@ oj_err_set(Err e, VALUE clas, const char *format, ...) {
14
14
  va_end(ap);
15
15
  }
16
16
 
17
- void
18
- oj_err_raise(Err e) {
17
+ void oj_err_raise(Err e) {
19
18
  rb_raise(e->clas, "%s", e->msg);
20
19
  }
21
20
 
22
- void
23
- _oj_err_set_with_location(Err err, VALUE eclas, const char *msg, const char *json, const char *current, const char* file, int line) {
24
- int n = 1;
25
- int col = 1;
21
+ void _oj_err_set_with_location(Err err,
22
+ VALUE eclas,
23
+ const char *msg,
24
+ const char *json,
25
+ const char *current,
26
+ const char *file,
27
+ int line) {
28
+ int n = 1;
29
+ int col = 1;
26
30
 
27
31
  for (; json < current && '\n' != *current; current--) {
28
- col++;
32
+ col++;
29
33
  }
30
34
  for (; json < current; current--) {
31
- if ('\n' == *current) {
32
- n++;
33
- }
35
+ if ('\n' == *current) {
36
+ n++;
37
+ }
34
38
  }
35
39
  oj_err_set(err, eclas, "%s at line %d, column %d [%s:%d]", msg, n, col, file, line);
36
40
  }
37
41
 
38
- void
39
- _oj_raise_error(const char *msg, const char *json, const char *current, const char* file, int line) {
40
- struct _err err;
41
- int n = 1;
42
- int col = 1;
42
+ void _oj_raise_error(const char *msg,
43
+ const char *json,
44
+ const char *current,
45
+ const char *file,
46
+ int line) {
47
+ struct _err err;
48
+ int n = 1;
49
+ int col = 1;
43
50
 
44
51
  for (; json < current && '\n' != *current; current--) {
45
- col++;
52
+ col++;
46
53
  }
47
54
  for (; json < current; current--) {
48
- if ('\n' == *current) {
49
- n++;
50
- }
55
+ if ('\n' == *current) {
56
+ n++;
57
+ }
51
58
  }
52
- oj_err_set(&err, oj_parse_error_class, "%s at line %d, column %d [%s:%d]", msg, n, col, file, line);
59
+ oj_err_set(&err,
60
+ oj_parse_error_class,
61
+ "%s at line %d, column %d [%s:%d]",
62
+ msg,
63
+ n,
64
+ col,
65
+ file,
66
+ line);
53
67
  rb_raise(err.clas, "%s", err.msg);
54
68
  }
data/ext/oj/err.h CHANGED
@@ -1,4 +1,5 @@
1
1
  // Copyright (c) 2011 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
2
3
 
3
4
  #ifndef OJ_ERR_H
4
5
  #define OJ_ERR_H
@@ -6,36 +7,44 @@
6
7
  #include "ruby.h"
7
8
  // Needed to silence 2.4.0 warnings.
8
9
  #ifndef NORETURN
9
- # define NORETURN(x) x
10
+ #define NORETURN(x) x
10
11
  #endif
11
12
 
12
- #define set_error(err, eclas, msg, json, current) _oj_err_set_with_location(err, eclas, msg, json, current, FILE, LINE)
13
+ #define set_error(err, eclas, msg, json, current) \
14
+ _oj_err_set_with_location(err, eclas, msg, json, current, FILE, LINE)
13
15
 
14
16
  typedef struct _err {
15
- VALUE clas;
16
- char msg[128];
17
- } *Err;
17
+ VALUE clas;
18
+ char msg[128];
19
+ } * Err;
18
20
 
19
- extern VALUE oj_parse_error_class;
21
+ extern VALUE oj_parse_error_class;
20
22
 
21
- extern void oj_err_set(Err e, VALUE clas, const char *format, ...);
22
- extern void _oj_err_set_with_location(Err err, VALUE eclas, const char *msg, const char *json, const char *current, const char* file, int line);
23
+ extern void oj_err_set(Err e, VALUE clas, const char *format, ...);
24
+ extern void _oj_err_set_with_location(Err err,
25
+ VALUE eclas,
26
+ const char *msg,
27
+ const char *json,
28
+ const char *current,
29
+ const char *file,
30
+ int line);
23
31
 
24
- NORETURN(extern void oj_err_raise(Err e));
32
+ NORETURN(extern void oj_err_raise(Err e));
25
33
 
26
34
  #define raise_error(msg, json, current) _oj_raise_error(msg, json, current, __FILE__, __LINE__)
27
35
 
28
- NORETURN(extern void _oj_raise_error(const char *msg, const char *json, const char *current, const char* file, int line));
36
+ NORETURN(extern void _oj_raise_error(const char *msg,
37
+ const char *json,
38
+ const char *current,
39
+ const char *file,
40
+ int line));
29
41
 
30
-
31
- inline static void
32
- err_init(Err e) {
42
+ inline static void err_init(Err e) {
33
43
  e->clas = Qnil;
34
44
  *e->msg = '\0';
35
45
  }
36
46
 
37
- inline static int
38
- err_has(Err e) {
47
+ inline static int err_has(Err e) {
39
48
  return (Qnil != e->clas);
40
49
  }
41
50
 
data/ext/oj/extconf.rb CHANGED
@@ -26,8 +26,9 @@ dflags = {
26
26
  have_func('rb_time_timespec')
27
27
  have_func('rb_ivar_count')
28
28
  have_func('rb_ivar_foreach')
29
+ # Support for compaction.
30
+ have_func('rb_gc_mark_movable')
29
31
  have_func('stpcpy')
30
- have_func('rb_data_object_wrap')
31
32
  have_func('pthread_mutex_init')
32
33
 
33
34
  dflags['OJ_DEBUG'] = true unless ENV['OJ_DEBUG'].nil?
data/ext/oj/fast.c CHANGED
@@ -1,98 +1,107 @@
1
1
  // Copyright (c) 2012 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for
3
+ // license details.
2
4
 
3
5
  #if !IS_WINDOWS
4
6
  #include <sys/resource.h> // for getrlimit() on linux
5
7
  #endif
6
- #include <stdlib.h>
8
+ #include <errno.h>
9
+ #include <math.h>
7
10
  #include <stdio.h>
11
+ #include <stdlib.h>
8
12
  #include <string.h>
9
- #include <math.h>
10
- #include <errno.h>
11
13
 
12
- #include "oj.h"
13
14
  #include "encode.h"
15
+ #include "oj.h"
14
16
 
15
17
  // maximum to allocate on the stack, arbitrary limit
16
- #define SMALL_XML 65536
17
- #define MAX_STACK 100
18
+ #define SMALL_JSON 65536
19
+ #define MAX_STACK 100
18
20
  //#define BATCH_SIZE (4096 / sizeof(struct _leaf) - 1)
19
- #define BATCH_SIZE 100
21
+ #define BATCH_SIZE 100
22
+
23
+ // Support for compaction
24
+ #ifdef HAVE_RB_GC_MARK_MOVABLE
25
+ #define mark rb_gc_mark_movable
26
+ #else
27
+ #define mark rb_gc_mark
28
+ #endif
20
29
 
21
30
  typedef struct _batch {
22
- struct _batch *next;
23
- int next_avail;
24
- struct _leaf leaves[BATCH_SIZE];
25
- } *Batch;
31
+ struct _batch *next;
32
+ int next_avail;
33
+ struct _leaf leaves[BATCH_SIZE];
34
+ } * Batch;
26
35
 
27
36
  typedef struct _doc {
28
- Leaf data;
29
- Leaf *where; // points to current location
30
- Leaf where_path[MAX_STACK]; // points to head of path
31
- char *json;
32
- unsigned long size; // number of leaves/branches in the doc
33
- VALUE self;
34
- Batch batches;
35
- struct _batch batch0;
36
- } *Doc;
37
+ Leaf data;
38
+ Leaf * where; // points to current location
39
+ Leaf where_path[MAX_STACK]; // points to head of path
40
+ char * json;
41
+ unsigned long size; // number of leaves/branches in the doc
42
+ VALUE self;
43
+ Batch batches;
44
+ struct _batch batch0;
45
+ } * Doc;
37
46
 
38
47
  typedef struct _parseInfo {
39
- char *str; /* buffer being read from */
40
- char *s; /* current position in buffer */
41
- Doc doc;
42
- void *stack_min;
43
- } *ParseInfo;
44
-
45
- static void leaf_init(Leaf leaf, int type);
46
- static Leaf leaf_new(Doc doc, int type);
47
- static void leaf_append_element(Leaf parent, Leaf element);
48
- static VALUE leaf_value(Doc doc, Leaf leaf);
49
- static void leaf_fixnum_value(Leaf leaf);
50
- static void leaf_float_value(Leaf leaf);
51
- static VALUE leaf_array_value(Doc doc, Leaf leaf);
52
- static VALUE leaf_hash_value(Doc doc, Leaf leaf);
53
-
54
- static Leaf read_next(ParseInfo pi);
55
- static Leaf read_obj(ParseInfo pi);
56
- static Leaf read_array(ParseInfo pi);
57
- static Leaf read_str(ParseInfo pi);
58
- static Leaf read_num(ParseInfo pi);
59
- static Leaf read_true(ParseInfo pi);
60
- static Leaf read_false(ParseInfo pi);
61
- static Leaf read_nil(ParseInfo pi);
62
- static void next_non_white(ParseInfo pi);
63
- static char* read_quoted_value(ParseInfo pi);
64
- static void skip_comment(ParseInfo pi);
65
-
66
- static VALUE protect_open_proc(VALUE x);
67
- static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated);
68
- static void each_leaf(Doc doc, VALUE self);
69
- static int move_step(Doc doc, const char *path, int loc);
70
- static Leaf get_doc_leaf(Doc doc, const char *path);
71
- static Leaf get_leaf(Leaf *stack, Leaf *lp, const char *path);
72
- static void each_value(Doc doc, Leaf leaf);
73
-
74
- static void doc_init(Doc doc);
75
- static void doc_free(Doc doc);
76
- static VALUE doc_open(VALUE clas, VALUE str);
77
- static VALUE doc_open_file(VALUE clas, VALUE filename);
78
- static VALUE doc_where(VALUE self);
79
- static VALUE doc_local_key(VALUE self);
80
- static VALUE doc_home(VALUE self);
81
- static VALUE doc_type(int argc, VALUE *argv, VALUE self);
82
- static VALUE doc_fetch(int argc, VALUE *argv, VALUE self);
83
- static VALUE doc_each_leaf(int argc, VALUE *argv, VALUE self);
84
- static VALUE doc_move(VALUE self, VALUE str);
85
- static VALUE doc_each_child(int argc, VALUE *argv, VALUE self);
86
- static VALUE doc_each_value(int argc, VALUE *argv, VALUE self);
87
- static VALUE doc_dump(int argc, VALUE *argv, VALUE self);
88
- static VALUE doc_size(VALUE self);
89
-
90
- VALUE oj_doc_class = Qundef;
48
+ char *str; // buffer being read from
49
+ char *s; // current position in buffer
50
+ Doc doc;
51
+ void *stack_min;
52
+ } * ParseInfo;
53
+
54
+ static void leaf_init(Leaf leaf, int type);
55
+ static Leaf leaf_new(Doc doc, int type);
56
+ static void leaf_append_element(Leaf parent, Leaf element);
57
+ static VALUE leaf_value(Doc doc, Leaf leaf);
58
+ static void leaf_fixnum_value(Leaf leaf);
59
+ static void leaf_float_value(Leaf leaf);
60
+ static VALUE leaf_array_value(Doc doc, Leaf leaf);
61
+ static VALUE leaf_hash_value(Doc doc, Leaf leaf);
62
+
63
+ static Leaf read_next(ParseInfo pi);
64
+ static Leaf read_obj(ParseInfo pi);
65
+ static Leaf read_array(ParseInfo pi);
66
+ static Leaf read_str(ParseInfo pi);
67
+ static Leaf read_num(ParseInfo pi);
68
+ static Leaf read_true(ParseInfo pi);
69
+ static Leaf read_false(ParseInfo pi);
70
+ static Leaf read_nil(ParseInfo pi);
71
+ static void next_non_white(ParseInfo pi);
72
+ static char *read_quoted_value(ParseInfo pi);
73
+ static void skip_comment(ParseInfo pi);
74
+
75
+ static VALUE protect_open_proc(VALUE x);
76
+ static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated);
77
+ static void each_leaf(Doc doc, VALUE self);
78
+ static int move_step(Doc doc, const char *path, int loc);
79
+ static Leaf get_doc_leaf(Doc doc, const char *path);
80
+ static Leaf get_leaf(Leaf *stack, Leaf *lp, const char *path);
81
+ static void each_value(Doc doc, Leaf leaf);
82
+
83
+ static void doc_init(Doc doc);
84
+ static void doc_free(Doc doc);
85
+ static VALUE doc_open(VALUE clas, VALUE str);
86
+ static VALUE doc_open_file(VALUE clas, VALUE filename);
87
+ static VALUE doc_where(VALUE self);
88
+ static VALUE doc_local_key(VALUE self);
89
+ static VALUE doc_home(VALUE self);
90
+ static VALUE doc_type(int argc, VALUE *argv, VALUE self);
91
+ static VALUE doc_fetch(int argc, VALUE *argv, VALUE self);
92
+ static VALUE doc_each_leaf(int argc, VALUE *argv, VALUE self);
93
+ static VALUE doc_move(VALUE self, VALUE str);
94
+ static VALUE doc_each_child(int argc, VALUE *argv, VALUE self);
95
+ static VALUE doc_each_value(int argc, VALUE *argv, VALUE self);
96
+ static VALUE doc_dump(int argc, VALUE *argv, VALUE self);
97
+ static VALUE doc_size(VALUE self);
98
+
99
+ VALUE oj_doc_class = Qundef;
91
100
 
92
101
  // This is only for CentOS 5.4 with Ruby 1.9.3-p0.
93
102
  #ifndef HAVE_STPCPY
94
103
  char *stpcpy(char *dest, const char *src) {
95
- size_t cnt = strlen(src);
104
+ size_t cnt = strlen(src);
96
105
 
97
106
  strcpy(dest, src);
98
107
 
@@ -100,89 +109,79 @@ char *stpcpy(char *dest, const char *src) {
100
109
  }
101
110
  #endif
102
111
 
103
- inline static void
104
- next_non_white(ParseInfo pi) {
112
+ inline static void next_non_white(ParseInfo pi) {
105
113
  for (; 1; pi->s++) {
106
- switch(*pi->s) {
107
- case ' ':
108
- case '\t':
109
- case '\f':
110
- case '\n':
111
- case '\r':
112
- break;
113
- case '/':
114
- skip_comment(pi);
115
- break;
116
- default:
117
- return;
118
- }
114
+ switch (*pi->s) {
115
+ case ' ':
116
+ case '\t':
117
+ case '\f':
118
+ case '\n':
119
+ case '\r': break;
120
+ case '/': skip_comment(pi); break;
121
+ default: return;
122
+ }
119
123
  }
120
124
  }
121
125
 
122
- inline static char*
123
- ulong_fill(char *s, size_t num) {
124
- char buf[32];
125
- char *b = buf + sizeof(buf) - 1;
126
+ inline static char *ulong_fill(char *s, size_t num) {
127
+ char buf[32];
128
+ char *b = buf + sizeof(buf) - 1;
126
129
 
127
130
  *b-- = '\0';
128
131
  for (; 0 < num; num /= 10, b--) {
129
- *b = (num % 10) + '0';
132
+ *b = (num % 10) + '0';
130
133
  }
131
134
  b++;
132
135
  if ('\0' == *b) {
133
- b--;
134
- *b = '0';
136
+ b--;
137
+ *b = '0';
135
138
  }
136
139
  for (; '\0' != *b; b++, s++) {
137
- *s = *b;
140
+ *s = *b;
138
141
  }
139
142
  return s;
140
143
  }
141
144
 
142
- inline static void
143
- leaf_init(Leaf leaf, int type) {
144
- leaf->next = 0;
145
- leaf->rtype = type;
145
+ inline static void leaf_init(Leaf leaf, int type) {
146
+ leaf->next = 0;
147
+ leaf->rtype = type;
146
148
  leaf->parent_type = T_NONE;
147
149
  switch (type) {
148
150
  case T_ARRAY:
149
151
  case T_HASH:
150
- leaf->elements = 0;
151
- leaf->value_type = COL_VAL;
152
- break;
152
+ leaf->elements = 0;
153
+ leaf->value_type = COL_VAL;
154
+ break;
153
155
  case T_NIL:
154
- leaf->value = Qnil;
155
- leaf->value_type = RUBY_VAL;
156
- break;
156
+ leaf->value = Qnil;
157
+ leaf->value_type = RUBY_VAL;
158
+ break;
157
159
  case T_TRUE:
158
- leaf->value = Qtrue;
159
- leaf->value_type = RUBY_VAL;
160
- break;
160
+ leaf->value = Qtrue;
161
+ leaf->value_type = RUBY_VAL;
162
+ break;
161
163
  case T_FALSE:
162
- leaf->value = Qfalse;
163
- leaf->value_type = RUBY_VAL;
164
- break;
164
+ leaf->value = Qfalse;
165
+ leaf->value_type = RUBY_VAL;
166
+ break;
165
167
  case T_FIXNUM:
166
168
  case T_FLOAT:
167
169
  case T_STRING:
168
- default:
169
- leaf->value_type = STR_VAL;
170
- break;
170
+ default: leaf->value_type = STR_VAL; break;
171
171
  }
172
172
  }
173
173
 
174
- inline static Leaf
175
- leaf_new(Doc doc, int type) {
176
- Leaf leaf;
174
+ inline static Leaf leaf_new(Doc doc, int type) {
175
+ Leaf leaf;
177
176
 
178
177
  if (0 == doc->batches || BATCH_SIZE == doc->batches->next_avail) {
179
- Batch b = ALLOC(struct _batch);
178
+ Batch b = ALLOC(struct _batch);
180
179
 
181
- // Initializes all leaves with a NO_VAL value_type
182
- memset(b, 0, sizeof(struct _batch));
183
- b->next = doc->batches;
184
- doc->batches = b;
185
- b->next_avail = 0;
180
+ // Initializes all leaves with a NO_VAL value_type
181
+ memset(b, 0, sizeof(struct _batch));
182
+ b->next = doc->batches;
183
+ doc->batches = b;
184
+ b->next_avail = 0;
186
185
  }
187
186
  leaf = &doc->batches->leaves[doc->batches->next_avail];
188
187
  doc->batches->next_avail++;
@@ -191,93 +190,73 @@ leaf_new(Doc doc, int type) {
191
190
  return leaf;
192
191
  }
193
192
 
194
- inline static void
195
- leaf_append_element(Leaf parent, Leaf element) {
193
+ inline static void leaf_append_element(Leaf parent, Leaf element) {
196
194
  if (0 == parent->elements) {
197
- parent->elements = element;
198
- element->next = element;
195
+ parent->elements = element;
196
+ element->next = element;
199
197
  } else {
200
- element->next = parent->elements->next;
201
- parent->elements->next = element;
202
- parent->elements = element;
198
+ element->next = parent->elements->next;
199
+ parent->elements->next = element;
200
+ parent->elements = element;
203
201
  }
204
202
  }
205
203
 
206
- static VALUE
207
- leaf_value(Doc doc, Leaf leaf) {
204
+ static VALUE leaf_value(Doc doc, Leaf leaf) {
208
205
  if (RUBY_VAL != leaf->value_type) {
209
- switch (leaf->rtype) {
210
- case T_NIL:
211
- leaf->value = Qnil;
212
- break;
213
- case T_TRUE:
214
- leaf->value = Qtrue;
215
- break;
216
- case T_FALSE:
217
- leaf->value = Qfalse;
218
- break;
219
- case T_FIXNUM:
220
- leaf_fixnum_value(leaf);
221
- break;
222
- case T_FLOAT:
223
- leaf_float_value(leaf);
224
- break;
225
- case T_STRING:
226
- leaf->value = rb_str_new2(leaf->str);
227
- leaf->value = oj_encode(leaf->value);
228
- leaf->value_type = RUBY_VAL;
229
- break;
230
- case T_ARRAY:
231
- return leaf_array_value(doc, leaf);
232
- break;
233
- case T_HASH:
234
- return leaf_hash_value(doc, leaf);
235
- break;
236
- default:
237
- rb_raise(rb_const_get_at(Oj, rb_intern("Error")), "Unexpected type %02x.", leaf->rtype);
238
- break;
239
- }
206
+ switch (leaf->rtype) {
207
+ case T_NIL: leaf->value = Qnil; break;
208
+ case T_TRUE: leaf->value = Qtrue; break;
209
+ case T_FALSE: leaf->value = Qfalse; break;
210
+ case T_FIXNUM: leaf_fixnum_value(leaf); break;
211
+ case T_FLOAT: leaf_float_value(leaf); break;
212
+ case T_STRING:
213
+ leaf->value = rb_str_new2(leaf->str);
214
+ leaf->value = oj_encode(leaf->value);
215
+ leaf->value_type = RUBY_VAL;
216
+ break;
217
+ case T_ARRAY: return leaf_array_value(doc, leaf); break;
218
+ case T_HASH: return leaf_hash_value(doc, leaf); break;
219
+ default:
220
+ rb_raise(rb_const_get_at(Oj, rb_intern("Error")), "Unexpected type %02x.", leaf->rtype);
221
+ break;
222
+ }
240
223
  }
241
224
  return leaf->value;
242
225
  }
243
226
 
244
- inline static Doc
245
- self_doc(VALUE self) {
246
- Doc doc = DATA_PTR(self);
227
+ inline static Doc self_doc(VALUE self) {
228
+ Doc doc = DATA_PTR(self);
247
229
 
248
230
  if (0 == doc) {
249
- rb_raise(rb_eIOError, "Document already closed or not open.");
231
+ rb_raise(rb_eIOError, "Document already closed or not open.");
250
232
  }
251
233
  return doc;
252
234
  }
253
235
 
254
- static void
255
- skip_comment(ParseInfo pi) {
256
- pi->s++; // skip first /
236
+ static void skip_comment(ParseInfo pi) {
237
+ pi->s++; // skip first /
257
238
  if ('*' == *pi->s) {
258
- pi->s++;
259
- for (; '\0' != *pi->s; pi->s++) {
260
- if ('*' == *pi->s && '/' == *(pi->s + 1)) {
261
- pi->s++;
262
- return;
263
- } else if ('\0' == *pi->s) {
264
- raise_error("comment not terminated", pi->str, pi->s);
265
- }
266
- }
239
+ pi->s++;
240
+ for (; '\0' != *pi->s; pi->s++) {
241
+ if ('*' == *pi->s && '/' == *(pi->s + 1)) {
242
+ pi->s++;
243
+ return;
244
+ } else if ('\0' == *pi->s) {
245
+ raise_error("comment not terminated", pi->str, pi->s);
246
+ }
247
+ }
267
248
  } else if ('/' == *pi->s) {
268
- for (; 1; pi->s++) {
269
- switch (*pi->s) {
270
- case '\n':
271
- case '\r':
272
- case '\f':
273
- case '\0':
274
- return;
275
- default:
276
- break;
277
- }
278
- }
249
+ for (; 1; pi->s++) {
250
+ switch (*pi->s) {
251
+ case '\n':
252
+ case '\r':
253
+ case '\f':
254
+ case '\0': return;
255
+ default: break;
256
+ }
257
+ }
279
258
  } else {
280
- raise_error("invalid comment", pi->str, pi->s);
259
+ raise_error("invalid comment", pi->str, pi->s);
281
260
  }
282
261
  }
283
262
 
@@ -287,100 +266,88 @@ skip_comment(ParseInfo pi) {
287
266
  #define NUM_MAX (FIXNUM_MAX >> 8)
288
267
  #endif
289
268
 
290
-
291
- static void
292
- leaf_fixnum_value(Leaf leaf) {
293
- char *s = leaf->str;
294
- int64_t n = 0;
295
- int neg = 0;
296
- int big = 0;
269
+ static void leaf_fixnum_value(Leaf leaf) {
270
+ char * s = leaf->str;
271
+ int64_t n = 0;
272
+ int neg = 0;
273
+ int big = 0;
297
274
 
298
275
  if ('-' == *s) {
299
- s++;
300
- neg = 1;
276
+ s++;
277
+ neg = 1;
301
278
  } else if ('+' == *s) {
302
- s++;
279
+ s++;
303
280
  }
304
281
  for (; '0' <= *s && *s <= '9'; s++) {
305
- n = n * 10 + (*s - '0');
306
- if (NUM_MAX <= n) {
307
- big = 1;
308
- }
282
+ n = n * 10 + (*s - '0');
283
+ if (NUM_MAX <= n) {
284
+ big = 1;
285
+ }
309
286
  }
310
287
  if (big) {
311
- char c = *s;
288
+ char c = *s;
312
289
 
313
- *s = '\0';
314
- leaf->value = rb_cstr_to_inum(leaf->str, 10, 0);
315
- *s = c;
290
+ *s = '\0';
291
+ leaf->value = rb_cstr_to_inum(leaf->str, 10, 0);
292
+ *s = c;
316
293
  } else {
317
- if (neg) {
318
- n = -n;
319
- }
320
- leaf->value = rb_ll2inum(n);
294
+ if (neg) {
295
+ n = -n;
296
+ }
297
+ leaf->value = rb_ll2inum(n);
321
298
  }
322
299
  leaf->value_type = RUBY_VAL;
323
300
  }
324
301
 
325
- static void
326
- leaf_float_value(Leaf leaf) {
327
- leaf->value = rb_float_new(rb_cstr_to_dbl(leaf->str, 1));
302
+ static void leaf_float_value(Leaf leaf) {
303
+ leaf->value = rb_float_new(rb_cstr_to_dbl(leaf->str, 1));
328
304
  leaf->value_type = RUBY_VAL;
329
305
  }
330
306
 
331
- static VALUE
332
- leaf_array_value(Doc doc, Leaf leaf) {
333
- volatile VALUE a = rb_ary_new();
307
+ static VALUE leaf_array_value(Doc doc, Leaf leaf) {
308
+ volatile VALUE a = rb_ary_new();
334
309
 
335
310
  if (0 != leaf->elements) {
336
- Leaf first = leaf->elements->next;
337
- Leaf e = first;
311
+ Leaf first = leaf->elements->next;
312
+ Leaf e = first;
338
313
 
339
- do {
340
- rb_ary_push(a, leaf_value(doc, e));
341
- e = e->next;
342
- } while (e != first);
314
+ do {
315
+ rb_ary_push(a, leaf_value(doc, e));
316
+ e = e->next;
317
+ } while (e != first);
343
318
  }
344
319
  return a;
345
320
  }
346
321
 
347
- static VALUE
348
- leaf_hash_value(Doc doc, Leaf leaf) {
349
- volatile VALUE h = rb_hash_new();
322
+ static VALUE leaf_hash_value(Doc doc, Leaf leaf) {
323
+ volatile VALUE h = rb_hash_new();
350
324
 
351
325
  if (0 != leaf->elements) {
352
- Leaf first = leaf->elements->next;
353
- Leaf e = first;
354
- volatile VALUE key;
326
+ Leaf first = leaf->elements->next;
327
+ Leaf e = first;
328
+ volatile VALUE key;
355
329
 
356
- do {
357
- key = rb_str_new2(e->key);
358
- key = oj_encode(key);
359
- rb_hash_aset(h, key, leaf_value(doc, e));
360
- e = e->next;
361
- } while (e != first);
330
+ do {
331
+ key = rb_str_new2(e->key);
332
+ key = oj_encode(key);
333
+ rb_hash_aset(h, key, leaf_value(doc, e));
334
+ e = e->next;
335
+ } while (e != first);
362
336
  }
363
337
  return h;
364
338
  }
365
339
 
366
- static Leaf
367
- read_next(ParseInfo pi) {
368
- Leaf leaf = 0;
340
+ static Leaf read_next(ParseInfo pi) {
341
+ Leaf leaf = 0;
369
342
 
370
- if ((void*)&leaf < pi->stack_min) {
371
- rb_raise(rb_eSysStackError, "JSON is too deeply nested");
343
+ if ((void *)&leaf < pi->stack_min) {
344
+ rb_raise(rb_eSysStackError, "JSON is too deeply nested");
372
345
  }
373
- next_non_white(pi); // skip white space
346
+ next_non_white(pi); // skip white space
374
347
  switch (*pi->s) {
375
- case '{':
376
- leaf = read_obj(pi);
377
- break;
378
- case '[':
379
- leaf = read_array(pi);
380
- break;
381
- case '"':
382
- leaf = read_str(pi);
383
- break;
348
+ case '{': leaf = read_obj(pi); break;
349
+ case '[': leaf = read_array(pi); break;
350
+ case '"': leaf = read_str(pi); break;
384
351
  case '+':
385
352
  case '-':
386
353
  case '0':
@@ -392,716 +359,727 @@ read_next(ParseInfo pi) {
392
359
  case '6':
393
360
  case '7':
394
361
  case '8':
395
- case '9':
396
- leaf = read_num(pi);
397
- break;
398
- case 't':
399
- leaf = read_true(pi);
400
- break;
401
- case 'f':
402
- leaf = read_false(pi);
403
- break;
404
- case 'n':
405
- leaf = read_nil(pi);
406
- break;
362
+ case '9': leaf = read_num(pi); break;
363
+ case 't': leaf = read_true(pi); break;
364
+ case 'f': leaf = read_false(pi); break;
365
+ case 'n': leaf = read_nil(pi); break;
407
366
  case '\0':
408
- default:
409
- break; // returns 0
367
+ default: break; // returns 0
410
368
  }
411
369
  pi->doc->size++;
412
370
 
413
371
  return leaf;
414
372
  }
415
373
 
416
- static Leaf
417
- read_obj(ParseInfo pi) {
418
- Leaf h = leaf_new(pi->doc, T_HASH);
419
- char *end;
420
- const char *key = 0;
421
- Leaf val = 0;
374
+ static Leaf read_obj(ParseInfo pi) {
375
+ Leaf h = leaf_new(pi->doc, T_HASH);
376
+ char * end;
377
+ const char *key = 0;
378
+ Leaf val = 0;
422
379
 
423
380
  pi->s++;
424
381
  next_non_white(pi);
425
382
  if ('}' == *pi->s) {
426
- pi->s++;
427
- return h;
383
+ pi->s++;
384
+ return h;
428
385
  }
429
386
  while (1) {
430
- next_non_white(pi);
431
- key = 0;
432
- val = 0;
433
- if ('"' != *pi->s || 0 == (key = read_quoted_value(pi))) {
434
- raise_error("unexpected character", pi->str, pi->s);
435
- }
436
- next_non_white(pi);
437
- if (':' == *pi->s) {
438
- pi->s++;
439
- } else {
440
- raise_error("invalid format, expected :", pi->str, pi->s);
441
- }
442
- if (0 == (val = read_next(pi))) {
443
- //printf("*** '%s'\n", pi->s);
444
- raise_error("unexpected character", pi->str, pi->s);
445
- }
446
- end = pi->s;
447
- val->key = key;
448
- val->parent_type = T_HASH;
449
- leaf_append_element(h, val);
450
- next_non_white(pi);
451
- if ('}' == *pi->s) {
452
- pi->s++;
453
- *end = '\0';
454
- break;
455
- } else if (',' == *pi->s) {
456
- pi->s++;
457
- } else {
458
- //printf("*** '%s'\n", pi->s);
459
- raise_error("invalid format, expected , or } while in an object", pi->str, pi->s);
460
- }
461
- *end = '\0';
387
+ next_non_white(pi);
388
+ key = 0;
389
+ val = 0;
390
+ if ('"' != *pi->s || 0 == (key = read_quoted_value(pi))) {
391
+ raise_error("unexpected character", pi->str, pi->s);
392
+ }
393
+ next_non_white(pi);
394
+ if (':' == *pi->s) {
395
+ pi->s++;
396
+ } else {
397
+ raise_error("invalid format, expected :", pi->str, pi->s);
398
+ }
399
+ if (0 == (val = read_next(pi))) {
400
+ // printf("*** '%s'\n", pi->s);
401
+ raise_error("unexpected character", pi->str, pi->s);
402
+ }
403
+ end = pi->s;
404
+ val->key = key;
405
+ val->parent_type = T_HASH;
406
+ leaf_append_element(h, val);
407
+ next_non_white(pi);
408
+ if ('}' == *pi->s) {
409
+ pi->s++;
410
+ *end = '\0';
411
+ break;
412
+ } else if (',' == *pi->s) {
413
+ pi->s++;
414
+ } else {
415
+ // printf("*** '%s'\n", pi->s);
416
+ raise_error("invalid format, expected , or } while in an object", pi->str, pi->s);
417
+ }
418
+ *end = '\0';
462
419
  }
463
420
  return h;
464
421
  }
465
422
 
466
- static Leaf
467
- read_array(ParseInfo pi) {
468
- Leaf a = leaf_new(pi->doc, T_ARRAY);
469
- Leaf e;
470
- char *end;
471
- int cnt = 0;
423
+ static Leaf read_array(ParseInfo pi) {
424
+ Leaf a = leaf_new(pi->doc, T_ARRAY);
425
+ Leaf e;
426
+ char *end;
427
+ int cnt = 0;
472
428
 
473
429
  pi->s++;
474
430
  next_non_white(pi);
475
431
  if (']' == *pi->s) {
476
- pi->s++;
477
- return a;
432
+ pi->s++;
433
+ return a;
478
434
  }
479
435
  while (1) {
480
- next_non_white(pi);
481
- if (0 == (e = read_next(pi))) {
482
- raise_error("unexpected character", pi->str, pi->s);
483
- }
484
- cnt++;
485
- e->index = cnt;
486
- e->parent_type = T_ARRAY;
487
- leaf_append_element(a, e);
488
- end = pi->s;
489
- next_non_white(pi);
490
- if (',' == *pi->s) {
491
- pi->s++;
492
- } else if (']' == *pi->s) {
493
- pi->s++;
494
- *end = '\0';
495
- break;
496
- } else {
497
- raise_error("invalid format, expected , or ] while in an array", pi->str, pi->s);
498
- }
499
- *end = '\0';
436
+ next_non_white(pi);
437
+ if (0 == (e = read_next(pi))) {
438
+ raise_error("unexpected character", pi->str, pi->s);
439
+ }
440
+ cnt++;
441
+ e->index = cnt;
442
+ e->parent_type = T_ARRAY;
443
+ leaf_append_element(a, e);
444
+ end = pi->s;
445
+ next_non_white(pi);
446
+ if (',' == *pi->s) {
447
+ pi->s++;
448
+ } else if (']' == *pi->s) {
449
+ pi->s++;
450
+ *end = '\0';
451
+ break;
452
+ } else {
453
+ raise_error("invalid format, expected , or ] while in an array", pi->str, pi->s);
454
+ }
455
+ *end = '\0';
500
456
  }
501
457
  return a;
502
458
  }
503
459
 
504
- static Leaf
505
- read_str(ParseInfo pi) {
506
- Leaf leaf = leaf_new(pi->doc, T_STRING);
460
+ static Leaf read_str(ParseInfo pi) {
461
+ Leaf leaf = leaf_new(pi->doc, T_STRING);
507
462
 
508
463
  leaf->str = read_quoted_value(pi);
509
464
 
510
465
  return leaf;
511
466
  }
512
467
 
513
- static Leaf
514
- read_num(ParseInfo pi) {
515
- char *start = pi->s;
516
- int type = T_FIXNUM;
517
- Leaf leaf;
468
+ static Leaf read_num(ParseInfo pi) {
469
+ char *start = pi->s;
470
+ int type = T_FIXNUM;
471
+ Leaf leaf;
518
472
 
519
473
  if ('-' == *pi->s) {
520
- pi->s++;
474
+ pi->s++;
521
475
  }
522
476
  // digits
523
477
  for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
524
478
  }
525
479
  if ('.' == *pi->s) {
526
- type = T_FLOAT;
527
- pi->s++;
528
- for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
529
- }
480
+ type = T_FLOAT;
481
+ pi->s++;
482
+ for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
483
+ }
530
484
  }
531
485
  if ('e' == *pi->s || 'E' == *pi->s) {
532
- pi->s++;
533
- if ('-' == *pi->s || '+' == *pi->s) {
534
- pi->s++;
535
- }
536
- for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
537
- }
538
- }
539
- leaf = leaf_new(pi->doc, type);
486
+ pi->s++;
487
+ if ('-' == *pi->s || '+' == *pi->s) {
488
+ pi->s++;
489
+ }
490
+ for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
491
+ }
492
+ }
493
+ leaf = leaf_new(pi->doc, type);
540
494
  leaf->str = start;
541
495
 
542
496
  return leaf;
543
497
  }
544
498
 
545
- static Leaf
546
- read_true(ParseInfo pi) {
547
- Leaf leaf = leaf_new(pi->doc, T_TRUE);
499
+ static Leaf read_true(ParseInfo pi) {
500
+ Leaf leaf = leaf_new(pi->doc, T_TRUE);
548
501
 
549
502
  pi->s++;
550
503
  if ('r' != *pi->s || 'u' != *(pi->s + 1) || 'e' != *(pi->s + 2)) {
551
- raise_error("invalid format, expected 'true'", pi->str, pi->s);
504
+ raise_error("invalid format, expected 'true'", pi->str, pi->s);
552
505
  }
553
506
  pi->s += 3;
554
507
 
555
508
  return leaf;
556
509
  }
557
510
 
558
- static Leaf
559
- read_false(ParseInfo pi) {
560
- Leaf leaf = leaf_new(pi->doc, T_FALSE);
511
+ static Leaf read_false(ParseInfo pi) {
512
+ Leaf leaf = leaf_new(pi->doc, T_FALSE);
561
513
 
562
514
  pi->s++;
563
515
  if ('a' != *pi->s || 'l' != *(pi->s + 1) || 's' != *(pi->s + 2) || 'e' != *(pi->s + 3)) {
564
- raise_error("invalid format, expected 'false'", pi->str, pi->s);
516
+ raise_error("invalid format, expected 'false'", pi->str, pi->s);
565
517
  }
566
518
  pi->s += 4;
567
519
 
568
520
  return leaf;
569
521
  }
570
522
 
571
- static Leaf
572
- read_nil(ParseInfo pi) {
573
- Leaf leaf = leaf_new(pi->doc, T_NIL);
523
+ static Leaf read_nil(ParseInfo pi) {
524
+ Leaf leaf = leaf_new(pi->doc, T_NIL);
574
525
 
575
526
  pi->s++;
576
527
  if ('u' != *pi->s || 'l' != *(pi->s + 1) || 'l' != *(pi->s + 2)) {
577
- raise_error("invalid format, expected 'nil'", pi->str, pi->s);
528
+ raise_error("invalid format, expected 'nil'", pi->str, pi->s);
578
529
  }
579
530
  pi->s += 3;
580
531
 
581
532
  return leaf;
582
533
  }
583
534
 
584
- static uint32_t
585
- read_4hex(ParseInfo pi, const char *h) {
586
- uint32_t b = 0;
587
- int i;
535
+ static uint32_t read_4hex(ParseInfo pi, const char *h) {
536
+ uint32_t b = 0;
537
+ int i;
588
538
 
589
539
  for (i = 0; i < 4; i++, h++) {
590
- b = b << 4;
591
- if ('0' <= *h && *h <= '9') {
592
- b += *h - '0';
593
- } else if ('A' <= *h && *h <= 'F') {
594
- b += *h - 'A' + 10;
595
- } else if ('a' <= *h && *h <= 'f') {
596
- b += *h - 'a' + 10;
597
- } else {
598
- raise_error("invalid hex character", pi->str, pi->s);
599
- }
540
+ b = b << 4;
541
+ if ('0' <= *h && *h <= '9') {
542
+ b += *h - '0';
543
+ } else if ('A' <= *h && *h <= 'F') {
544
+ b += *h - 'A' + 10;
545
+ } else if ('a' <= *h && *h <= 'f') {
546
+ b += *h - 'a' + 10;
547
+ } else {
548
+ raise_error("invalid hex character", pi->str, pi->s);
549
+ }
600
550
  }
601
551
  return b;
602
552
  }
603
553
 
604
- static char*
605
- unicode_to_chars(ParseInfo pi, char *t, uint32_t code) {
554
+ static char *unicode_to_chars(ParseInfo pi, char *t, uint32_t code) {
606
555
  if (0x0000007F >= code) {
607
- *t++ = (char)code;
556
+ *t++ = (char)code;
608
557
  } else if (0x000007FF >= code) {
609
- *t++ = 0xC0 | (code >> 6);
610
- *t++ = 0x80 | (0x3F & code);
558
+ *t++ = 0xC0 | (code >> 6);
559
+ *t++ = 0x80 | (0x3F & code);
611
560
  } else if (0x0000FFFF >= code) {
612
- *t++ = 0xE0 | (code >> 12);
613
- *t++ = 0x80 | ((code >> 6) & 0x3F);
614
- *t++ = 0x80 | (0x3F & code);
561
+ *t++ = 0xE0 | (code >> 12);
562
+ *t++ = 0x80 | ((code >> 6) & 0x3F);
563
+ *t++ = 0x80 | (0x3F & code);
615
564
  } else if (0x001FFFFF >= code) {
616
- *t++ = 0xF0 | (code >> 18);
617
- *t++ = 0x80 | ((code >> 12) & 0x3F);
618
- *t++ = 0x80 | ((code >> 6) & 0x3F);
619
- *t++ = 0x80 | (0x3F & code);
565
+ *t++ = 0xF0 | (code >> 18);
566
+ *t++ = 0x80 | ((code >> 12) & 0x3F);
567
+ *t++ = 0x80 | ((code >> 6) & 0x3F);
568
+ *t++ = 0x80 | (0x3F & code);
620
569
  } else if (0x03FFFFFF >= code) {
621
- *t++ = 0xF8 | (code >> 24);
622
- *t++ = 0x80 | ((code >> 18) & 0x3F);
623
- *t++ = 0x80 | ((code >> 12) & 0x3F);
624
- *t++ = 0x80 | ((code >> 6) & 0x3F);
625
- *t++ = 0x80 | (0x3F & code);
570
+ *t++ = 0xF8 | (code >> 24);
571
+ *t++ = 0x80 | ((code >> 18) & 0x3F);
572
+ *t++ = 0x80 | ((code >> 12) & 0x3F);
573
+ *t++ = 0x80 | ((code >> 6) & 0x3F);
574
+ *t++ = 0x80 | (0x3F & code);
626
575
  } else if (0x7FFFFFFF >= code) {
627
- *t++ = 0xFC | (code >> 30);
628
- *t++ = 0x80 | ((code >> 24) & 0x3F);
629
- *t++ = 0x80 | ((code >> 18) & 0x3F);
630
- *t++ = 0x80 | ((code >> 12) & 0x3F);
631
- *t++ = 0x80 | ((code >> 6) & 0x3F);
632
- *t++ = 0x80 | (0x3F & code);
576
+ *t++ = 0xFC | (code >> 30);
577
+ *t++ = 0x80 | ((code >> 24) & 0x3F);
578
+ *t++ = 0x80 | ((code >> 18) & 0x3F);
579
+ *t++ = 0x80 | ((code >> 12) & 0x3F);
580
+ *t++ = 0x80 | ((code >> 6) & 0x3F);
581
+ *t++ = 0x80 | (0x3F & code);
633
582
  } else {
634
- raise_error("invalid Unicode character", pi->str, pi->s);
583
+ raise_error("invalid Unicode character", pi->str, pi->s);
635
584
  }
636
585
  return t;
637
586
  }
638
587
 
639
- /* Assume the value starts immediately and goes until the quote character is
640
- * reached again. Do not read the character after the terminating quote.
641
- */
642
- static char*
643
- read_quoted_value(ParseInfo pi) {
644
- char *value = 0;
645
- char *h = pi->s; // head
646
- char *t = h; // tail
588
+ // Assume the value starts immediately and goes until the quote character is
589
+ // reached again. Do not read the character after the terminating quote.
590
+ static char *read_quoted_value(ParseInfo pi) {
591
+ char *value = 0;
592
+ char *h = pi->s; // head
593
+ char *t = h; // tail
647
594
 
648
- h++; // skip quote character
595
+ h++; // skip quote character
649
596
  t++;
650
597
  value = h;
651
598
  for (; '"' != *h; h++, t++) {
652
- if ('\0' == *h) {
653
- pi->s = h;
654
- raise_error("quoted string not terminated", pi->str, pi->s);
655
- } else if ('\\' == *h) {
656
- h++;
657
- switch (*h) {
658
- case 'n': *t = '\n'; break;
659
- case 'r': *t = '\r'; break;
660
- case 't': *t = '\t'; break;
661
- case 'f': *t = '\f'; break;
662
- case 'b': *t = '\b'; break;
663
- case '"': *t = '"'; break;
664
- case '/': *t = '/'; break;
665
- case '\\': *t = '\\'; break;
666
- case 'u': {
667
- uint32_t code;
668
-
669
- h++;
670
- code = read_4hex(pi, h);
671
- h += 3;
672
- if (0x0000D800 <= code && code <= 0x0000DFFF) {
673
- uint32_t c1 = (code - 0x0000D800) & 0x000003FF;
674
- uint32_t c2;
675
-
676
- h++;
677
- if ('\\' != *h || 'u' != *(h + 1)) {
678
- pi->s = h;
679
- raise_error("invalid escaped character", pi->str, pi->s);
680
- }
681
- h += 2;
682
- c2 = read_4hex(pi, h);
683
- h += 3;
684
- c2 = (c2 - 0x0000DC00) & 0x000003FF;
685
- code = ((c1 << 10) | c2) + 0x00010000;
686
- }
687
- t = unicode_to_chars(pi, t, code);
688
- t--;
689
- break;
690
- }
691
- default:
692
- pi->s = h;
693
- raise_error("invalid escaped character", pi->str, pi->s);
694
- break;
695
- }
696
- } else if (t != h) {
697
- *t = *h;
698
- }
699
- }
700
- *t = '\0'; // terminate value
599
+ if ('\0' == *h) {
600
+ pi->s = h;
601
+ raise_error("quoted string not terminated", pi->str, pi->s);
602
+ } else if ('\\' == *h) {
603
+ h++;
604
+ switch (*h) {
605
+ case 'n': *t = '\n'; break;
606
+ case 'r': *t = '\r'; break;
607
+ case 't': *t = '\t'; break;
608
+ case 'f': *t = '\f'; break;
609
+ case 'b': *t = '\b'; break;
610
+ case '"': *t = '"'; break;
611
+ case '/': *t = '/'; break;
612
+ case '\\': *t = '\\'; break;
613
+ case 'u': {
614
+ uint32_t code;
615
+
616
+ h++;
617
+ code = read_4hex(pi, h);
618
+ h += 3;
619
+ if (0x0000D800 <= code && code <= 0x0000DFFF) {
620
+ uint32_t c1 = (code - 0x0000D800) & 0x000003FF;
621
+ uint32_t c2;
622
+
623
+ h++;
624
+ if ('\\' != *h || 'u' != *(h + 1)) {
625
+ pi->s = h;
626
+ raise_error("invalid escaped character", pi->str, pi->s);
627
+ }
628
+ h += 2;
629
+ c2 = read_4hex(pi, h);
630
+ h += 3;
631
+ c2 = (c2 - 0x0000DC00) & 0x000003FF;
632
+ code = ((c1 << 10) | c2) + 0x00010000;
633
+ }
634
+ t = unicode_to_chars(pi, t, code);
635
+ t--;
636
+ break;
637
+ }
638
+ default:
639
+ pi->s = h;
640
+ raise_error("invalid escaped character", pi->str, pi->s);
641
+ break;
642
+ }
643
+ } else if (t != h) {
644
+ *t = *h;
645
+ }
646
+ }
647
+ *t = '\0'; // terminate value
701
648
  pi->s = h + 1;
702
649
 
703
650
  return value;
704
651
  }
705
652
 
706
653
  // doc support functions
707
- inline static void
708
- doc_init(Doc doc) {
654
+ inline static void doc_init(Doc doc) {
709
655
  memset(doc, 0, sizeof(struct _doc));
710
- doc->where = doc->where_path;
711
- doc->self = Qundef;
656
+ doc->where = doc->where_path;
657
+ doc->self = Qundef;
712
658
  doc->batches = &doc->batch0;
713
659
  }
714
660
 
715
- static void
716
- doc_free(Doc doc) {
661
+ static void doc_free(Doc doc) {
717
662
  if (0 != doc) {
718
- Batch b;
663
+ Batch b;
719
664
 
720
- while (0 != (b = doc->batches)) {
721
- doc->batches = doc->batches->next;
722
- if (&doc->batch0 != b) {
723
- xfree(b);
724
- }
725
- }
726
- //xfree(f);
665
+ while (0 != (b = doc->batches)) {
666
+ doc->batches = doc->batches->next;
667
+ if (&doc->batch0 != b) {
668
+ xfree(b);
669
+ }
670
+ }
671
+ // xfree(f);
727
672
  }
728
673
  }
729
674
 
730
- static VALUE
731
- protect_open_proc(VALUE x) {
732
- ParseInfo pi = (ParseInfo)x;
675
+ static VALUE protect_open_proc(VALUE x) {
676
+ ParseInfo pi = (ParseInfo)x;
733
677
 
734
- pi->doc->data = read_next(pi); // parse
678
+ pi->doc->data = read_next(pi); // parse
735
679
  *pi->doc->where = pi->doc->data;
736
- pi->doc->where = pi->doc->where_path;
680
+ pi->doc->where = pi->doc->where_path;
737
681
  if (rb_block_given_p()) {
738
- return rb_yield(pi->doc->self); // caller processing
682
+ return rb_yield(pi->doc->self); // caller processing
739
683
  }
740
684
  return Qnil;
741
685
  }
742
686
 
743
- static void
744
- free_doc_cb(void *x) {
745
- Doc doc = (Doc)x;
687
+ static void free_doc_cb(void *x) {
688
+ Doc doc = (Doc)x;
746
689
 
747
690
  if (0 != doc) {
748
- xfree(doc->json);
749
- doc_free(doc);
691
+ xfree(doc->json);
692
+ doc_free(doc);
750
693
  }
751
694
  }
752
695
 
753
- static void
754
- mark_leaf(Leaf leaf) {
696
+ static void mark_leaf(Leaf leaf) {
755
697
  switch (leaf->value_type) {
756
698
  case COL_VAL:
757
- if (NULL != leaf->elements) {
758
- Leaf first = leaf->elements->next;
759
- Leaf e = first;
760
-
761
- do {
762
- mark_leaf(e);
763
- e = e->next;
764
- } while (e != first);
765
- }
766
- break;
767
- case RUBY_VAL:
768
- rb_gc_mark(leaf->value);
769
- break;
770
-
771
- default:
772
- break;
699
+ if (NULL != leaf->elements) {
700
+ Leaf first = leaf->elements->next;
701
+ Leaf e = first;
702
+
703
+ do {
704
+ mark_leaf(e);
705
+ e = e->next;
706
+ } while (e != first);
707
+ }
708
+ break;
709
+ case RUBY_VAL: mark(leaf->value); break;
710
+
711
+ default: break;
773
712
  }
774
713
  }
775
714
 
776
- static void
777
- mark_doc(void *ptr) {
715
+ static void mark_doc(void *ptr) {
778
716
  if (NULL != ptr) {
779
- Doc doc = (Doc)ptr;
717
+ Doc doc = (Doc)ptr;
780
718
 
781
- rb_gc_mark(doc->self);
782
- mark_leaf(doc->data);
719
+ mark(doc->self);
720
+ mark_leaf(doc->data);
721
+ }
722
+ }
723
+ #ifdef HAVE_RB_GC_MARK_MOVABLE
724
+ static void compact_leaf(Leaf leaf) {
725
+ switch (leaf->value_type) {
726
+ case COL_VAL:
727
+ if (NULL != leaf->elements) {
728
+ Leaf first = leaf->elements->next;
729
+ Leaf e = first;
730
+
731
+ do {
732
+ compact_leaf(e);
733
+ e = e->next;
734
+ } while (e != first);
735
+ }
736
+ break;
737
+ case RUBY_VAL: leaf->value = rb_gc_location(leaf->value); break;
738
+
739
+ default: break;
783
740
  }
784
741
  }
785
742
 
786
- static VALUE
787
- parse_json(VALUE clas, char *json, bool given, bool allocated) {
788
- struct _parseInfo pi;
789
- volatile VALUE result = Qnil;
790
- Doc doc;
791
- int ex = 0;
792
- volatile VALUE self;
743
+ static void compact_doc(void *ptr) {
744
+ Doc doc = (Doc)ptr;
745
+
746
+ if (doc) {
747
+ doc->self = rb_gc_location(doc->self);
748
+ compact_leaf(doc->data);
749
+ }
750
+ }
751
+ #endif
752
+
753
+ static const rb_data_type_t oj_doc_type = {
754
+ "Oj/doc",
755
+ {
756
+ mark_doc,
757
+ free_doc_cb,
758
+ NULL,
759
+ #ifdef HAVE_RB_GC_MARK_MOVABLE
760
+ compact_doc,
761
+ #endif
762
+ },
763
+ 0,
764
+ 0,
765
+ };
766
+
767
+ static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated) {
768
+ struct _parseInfo pi;
769
+ volatile VALUE result = Qnil;
770
+ Doc doc;
771
+ int ex = 0;
772
+ volatile VALUE self;
793
773
 
794
774
  // TBD are both needed? is stack allocation ever needed?
795
775
 
796
776
  if (given) {
797
- doc = ALLOCA_N(struct _doc, 1);
777
+ doc = ALLOCA_N(struct _doc, 1);
798
778
  } else {
799
- doc = ALLOC(struct _doc);
779
+ doc = ALLOC(struct _doc);
800
780
  }
801
- /* skip UTF-8 BOM if present */
781
+ // skip UTF-8 BOM if present
802
782
  if (0xEF == (uint8_t)*json && 0xBB == (uint8_t)json[1] && 0xBF == (uint8_t)json[2]) {
803
- pi.str = json + 3;
783
+ pi.str = json + 3;
804
784
  } else {
805
- pi.str = json;
785
+ pi.str = json;
806
786
  }
807
787
  pi.s = pi.str;
808
788
  doc_init(doc);
809
789
  pi.doc = doc;
810
790
  #if IS_WINDOWS
811
- pi.stack_min = (void*)((char*)&pi - (512 * 1024)); // assume a 1M stack and give half to ruby
791
+ // assume a 1M stack and give half to ruby
792
+ pi.stack_min = (void *)((char *)&pi - (512 * 1024));
812
793
  #else
813
794
  {
814
- struct rlimit lim;
795
+ struct rlimit lim;
815
796
 
816
- if (0 == getrlimit(RLIMIT_STACK, &lim) && RLIM_INFINITY != lim.rlim_cur) {
817
- pi.stack_min = (void*)((char*)&lim - (lim.rlim_cur / 4 * 3)); // let 3/4ths of the stack be used only
818
- } else {
819
- pi.stack_min = 0; // indicates not to check stack limit
820
- }
797
+ if (0 == getrlimit(RLIMIT_STACK, &lim) && RLIM_INFINITY != lim.rlim_cur) {
798
+ // let 3/4ths of the stack be used only
799
+ pi.stack_min = (void *)((char *)&lim - (lim.rlim_cur / 4 * 3));
800
+ } else {
801
+ pi.stack_min = 0; // indicates not to check stack limit
802
+ }
821
803
  }
822
804
  #endif
823
- // last arg is free func void* func(void*)
824
- #ifdef HAVE_RB_DATA_OBJECT_WRAP
825
- self = rb_data_object_wrap(clas, doc, mark_doc, free_doc_cb);
826
- #else
827
- self = rb_data_object_alloc(clas, doc, mark_doc, free_doc_cb);
828
- #endif
829
- doc->self = self;
830
- doc->json = json;
805
+ self = TypedData_Wrap_Struct(clas, &oj_doc_type, doc);
806
+ doc->self = self;
807
+ doc->json = json;
831
808
  DATA_PTR(doc->self) = doc;
832
- result = rb_protect(protect_open_proc, (VALUE)&pi, &ex);
809
+ result = rb_protect(protect_open_proc, (VALUE)&pi, &ex);
833
810
  if (given || 0 != ex) {
834
- DATA_PTR(doc->self) = NULL;
835
- doc_free(pi.doc);
836
- if (allocated && 0 != ex) { // will jump so caller will not free
837
- xfree(json);
838
- }
839
- rb_gc_enable();
811
+ DATA_PTR(doc->self) = NULL;
812
+ doc_free(pi.doc);
813
+ if (allocated && 0 != ex) { // will jump so caller will not free
814
+ xfree(json);
815
+ }
816
+ rb_gc_enable();
840
817
  } else {
841
- result = doc->self;
818
+ result = doc->self;
842
819
  }
843
820
  if (0 != ex) {
844
- rb_jump_tag(ex);
821
+ rb_jump_tag(ex);
845
822
  }
846
823
  return result;
847
824
  }
848
825
 
849
- static Leaf
850
- get_doc_leaf(Doc doc, const char *path) {
851
- Leaf leaf = *doc->where;
826
+ static Leaf get_doc_leaf(Doc doc, const char *path) {
827
+ Leaf leaf = *doc->where;
852
828
 
853
829
  if (0 != doc->data && 0 != path) {
854
- Leaf stack[MAX_STACK];
855
- Leaf *lp;
856
-
857
- if ('/' == *path) {
858
- path++;
859
- *stack = doc->data;
860
- lp = stack;
861
- } else if (doc->where == doc->where_path) {
862
- *stack = doc->data;
863
- lp = stack;
864
- } else {
865
- size_t cnt = doc->where - doc->where_path;
866
-
867
- if (MAX_STACK <= cnt) {
868
- rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
869
- }
870
- memcpy(stack, doc->where_path, sizeof(Leaf) * (cnt + 1));
871
- lp = stack + cnt;
872
- }
873
- return get_leaf(stack, lp, path);
830
+ Leaf stack[MAX_STACK];
831
+ Leaf *lp;
832
+
833
+ if ('/' == *path) {
834
+ path++;
835
+ *stack = doc->data;
836
+ lp = stack;
837
+ } else if (doc->where == doc->where_path) {
838
+ *stack = doc->data;
839
+ lp = stack;
840
+ } else {
841
+ size_t cnt = doc->where - doc->where_path;
842
+
843
+ if (MAX_STACK <= cnt) {
844
+ rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")),
845
+ "Path too deep. Limit is %d levels.",
846
+ MAX_STACK);
847
+ }
848
+ memcpy(stack, doc->where_path, sizeof(Leaf) * (cnt + 1));
849
+ lp = stack + cnt;
850
+ }
851
+ return get_leaf(stack, lp, path);
874
852
  }
875
853
  return leaf;
876
854
  }
877
855
 
878
- static const char*
879
- next_slash(const char *s) {
856
+ static const char *next_slash(const char *s) {
880
857
  for (; '\0' != *s; s++) {
881
- if ('\\' == *s) {
882
- s++;
883
- if ('\0' == *s) {
884
- break;
885
- }
886
- } else if ('/' == *s) {
887
- return s;
888
- }
858
+ if ('\\' == *s) {
859
+ s++;
860
+ if ('\0' == *s) {
861
+ break;
862
+ }
863
+ } else if ('/' == *s) {
864
+ return s;
865
+ }
889
866
  }
890
867
  return NULL;
891
868
  }
892
869
 
893
- static bool
894
- key_match(const char *pat, const char *key, int plen) {
870
+ static bool key_match(const char *pat, const char *key, int plen) {
895
871
  for (; 0 < plen; plen--, pat++, key++) {
896
- if ('\\' == *pat) {
897
- plen--;
898
- pat++;
899
- }
900
- if (*pat != *key) {
901
- return false;
902
- }
872
+ if ('\\' == *pat) {
873
+ plen--;
874
+ pat++;
875
+ }
876
+ if (*pat != *key) {
877
+ return false;
878
+ }
903
879
  }
904
880
  return '\0' == *key;
905
881
  }
906
882
 
907
- static Leaf
908
- get_leaf(Leaf *stack, Leaf *lp, const char *path) {
909
- Leaf leaf = *lp;
883
+ static Leaf get_leaf(Leaf *stack, Leaf *lp, const char *path) {
884
+ Leaf leaf = *lp;
910
885
 
911
886
  if (MAX_STACK <= lp - stack) {
912
- rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
887
+ rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")),
888
+ "Path too deep. Limit is %d levels.",
889
+ MAX_STACK);
913
890
  }
914
891
  if ('\0' != *path) {
915
- if ('.' == *path && '.' == *(path + 1)) {
916
- path += 2;
917
- if ('/' == *path) {
918
- path++;
919
- }
920
- if (stack < lp) {
921
- leaf = get_leaf(stack, lp - 1, path);
922
- } else {
923
- return 0;
924
- }
925
- } else if (COL_VAL == leaf->value_type && 0 != leaf->elements) {
926
- Leaf first = leaf->elements->next;
927
- Leaf e = first;
928
- int type = leaf->rtype;
929
-
930
- leaf = 0;
931
- if (T_ARRAY == type) {
932
- int cnt = 0;
933
-
934
- for (; '0' <= *path && *path <= '9'; path++) {
935
- cnt = cnt * 10 + (*path - '0');
936
- }
937
- if ('/' == *path) {
938
- path++;
939
- }
940
- do {
941
- if (1 >= cnt) {
942
- lp++;
943
- *lp = e;
944
- leaf = get_leaf(stack, lp, path);
945
- break;
946
- }
947
- cnt--;
948
- e = e->next;
949
- } while (e != first);
950
- } else if (T_HASH == type) {
951
- const char *key = path;
952
- const char *slash = next_slash(path);
953
- int klen;
954
-
955
- if (0 == slash) {
956
- klen = (int)strlen(key);
957
- path += klen;
958
- } else {
959
- klen = (int)(slash - key);
960
- path += klen + 1;
961
- }
962
- do {
963
- if (key_match(key, e->key, klen)) {
964
- lp++;
965
- *lp = e;
966
- leaf = get_leaf(stack, lp, path);
967
- break;
968
- }
969
- e = e->next;
970
- } while (e != first);
971
- }
972
- }
892
+ if ('.' == *path && '.' == *(path + 1)) {
893
+ path += 2;
894
+ if ('/' == *path) {
895
+ path++;
896
+ }
897
+ if (stack < lp) {
898
+ leaf = get_leaf(stack, lp - 1, path);
899
+ } else {
900
+ return 0;
901
+ }
902
+ } else if (COL_VAL == leaf->value_type && 0 != leaf->elements) {
903
+ Leaf first = leaf->elements->next;
904
+ Leaf e = first;
905
+ int type = leaf->rtype;
906
+
907
+ leaf = 0;
908
+ if (T_ARRAY == type) {
909
+ int cnt = 0;
910
+
911
+ for (; '0' <= *path && *path <= '9'; path++) {
912
+ cnt = cnt * 10 + (*path - '0');
913
+ }
914
+ if ('/' == *path) {
915
+ path++;
916
+ }
917
+ do {
918
+ if (1 >= cnt) {
919
+ lp++;
920
+ *lp = e;
921
+ leaf = get_leaf(stack, lp, path);
922
+ break;
923
+ }
924
+ cnt--;
925
+ e = e->next;
926
+ } while (e != first);
927
+ } else if (T_HASH == type) {
928
+ const char *key = path;
929
+ const char *slash = next_slash(path);
930
+ int klen;
931
+
932
+ if (0 == slash) {
933
+ klen = (int)strlen(key);
934
+ path += klen;
935
+ } else {
936
+ klen = (int)(slash - key);
937
+ path += klen + 1;
938
+ }
939
+ do {
940
+ if (key_match(key, e->key, klen)) {
941
+ lp++;
942
+ *lp = e;
943
+ leaf = get_leaf(stack, lp, path);
944
+ break;
945
+ }
946
+ e = e->next;
947
+ } while (e != first);
948
+ }
949
+ }
973
950
  }
974
951
  return leaf;
975
952
  }
976
953
 
977
- static void
978
- each_leaf(Doc doc, VALUE self) {
954
+ static void each_leaf(Doc doc, VALUE self) {
979
955
  if (COL_VAL == (*doc->where)->value_type) {
980
- if (0 != (*doc->where)->elements) {
981
- Leaf first = (*doc->where)->elements->next;
982
- Leaf e = first;
983
-
984
- doc->where++;
985
- if (MAX_STACK <= doc->where - doc->where_path) {
986
- rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
987
- }
988
- do {
989
- *doc->where = e;
990
- each_leaf(doc, self);
991
- e = e->next;
992
- } while (e != first);
993
- doc->where--;
994
- }
956
+ if (0 != (*doc->where)->elements) {
957
+ Leaf first = (*doc->where)->elements->next;
958
+ Leaf e = first;
959
+
960
+ doc->where++;
961
+ if (MAX_STACK <= doc->where - doc->where_path) {
962
+ rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")),
963
+ "Path too deep. Limit is %d levels.",
964
+ MAX_STACK);
965
+ }
966
+ do {
967
+ *doc->where = e;
968
+ each_leaf(doc, self);
969
+ e = e->next;
970
+ } while (e != first);
971
+ doc->where--;
972
+ }
995
973
  } else {
996
- rb_yield(self);
974
+ rb_yield(self);
997
975
  }
998
976
  }
999
977
 
1000
- static int
1001
- move_step(Doc doc, const char *path, int loc) {
978
+ static int move_step(Doc doc, const char *path, int loc) {
1002
979
  if (MAX_STACK <= doc->where - doc->where_path) {
1003
- rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
980
+ rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")),
981
+ "Path too deep. Limit is %d levels.",
982
+ MAX_STACK);
1004
983
  }
1005
984
  if ('\0' == *path) {
1006
- loc = 0;
985
+ loc = 0;
1007
986
  } else {
1008
- Leaf leaf;
1009
-
1010
- if (0 == doc->where || 0 == (leaf = *doc->where)) {
1011
- printf("*** Internal error at %s\n", path);
1012
- return loc;
1013
- }
1014
- if ('.' == *path && '.' == *(path + 1)) {
1015
- Leaf init = *doc->where;
1016
-
1017
- path += 2;
1018
- if (doc->where == doc->where_path) {
1019
- return loc;
1020
- }
1021
- if ('/' == *path) {
1022
- path++;
1023
- }
1024
- *doc->where = 0;
1025
- doc->where--;
1026
- loc = move_step(doc, path, loc + 1);
1027
- if (0 != loc) {
1028
- *doc->where = init;
1029
- doc->where++;
1030
- }
1031
- } else if (COL_VAL == leaf->value_type && 0 != leaf->elements) {
1032
- Leaf first = leaf->elements->next;
1033
- Leaf e = first;
1034
-
1035
- if (T_ARRAY == leaf->rtype) {
1036
- int cnt = 0;
1037
-
1038
- for (; '0' <= *path && *path <= '9'; path++) {
1039
- cnt = cnt * 10 + (*path - '0');
1040
- }
1041
- if ('/' == *path) {
1042
- path++;
1043
- } else if ('\0' != *path) {
1044
- return loc;
1045
- }
1046
- do {
1047
- if (1 >= cnt) {
1048
- doc->where++;
1049
- *doc->where = e;
1050
- loc = move_step(doc, path, loc + 1);
1051
- if (0 != loc) {
1052
- *doc->where = 0;
1053
- doc->where--;
1054
- }
1055
- break;
1056
- }
1057
- cnt--;
1058
- e = e->next;
1059
- } while (e != first);
1060
- } else if (T_HASH == leaf->rtype) {
1061
- const char *key = path;
1062
- const char *slash = next_slash(path);
1063
- int klen;
1064
-
1065
- if (0 == slash) {
1066
- klen = (int)strlen(key);
1067
- path += klen;
1068
- } else {
1069
- klen = (int)(slash - key);
1070
- path += klen + 1;
1071
- }
1072
- do {
1073
- if (key_match(key, e->key, klen)) {
1074
- doc->where++;
1075
- *doc->where = e;
1076
- loc = move_step(doc, path, loc + 1);
1077
- if (0 != loc) {
1078
- *doc->where = 0;
1079
- doc->where--;
1080
- }
1081
- break;
1082
- }
1083
- e = e->next;
1084
- } while (e != first);
1085
- }
1086
- }
987
+ Leaf leaf;
988
+
989
+ if (0 == doc->where || 0 == (leaf = *doc->where)) {
990
+ printf("*** Internal error at %s\n", path);
991
+ return loc;
992
+ }
993
+ if ('.' == *path && '.' == *(path + 1)) {
994
+ Leaf init = *doc->where;
995
+
996
+ path += 2;
997
+ if (doc->where == doc->where_path) {
998
+ return loc;
999
+ }
1000
+ if ('/' == *path) {
1001
+ path++;
1002
+ }
1003
+ *doc->where = 0;
1004
+ doc->where--;
1005
+ loc = move_step(doc, path, loc + 1);
1006
+ if (0 != loc) {
1007
+ *doc->where = init;
1008
+ doc->where++;
1009
+ }
1010
+ } else if (COL_VAL == leaf->value_type && 0 != leaf->elements) {
1011
+ Leaf first = leaf->elements->next;
1012
+ Leaf e = first;
1013
+
1014
+ if (T_ARRAY == leaf->rtype) {
1015
+ int cnt = 0;
1016
+
1017
+ for (; '0' <= *path && *path <= '9'; path++) {
1018
+ cnt = cnt * 10 + (*path - '0');
1019
+ }
1020
+ if ('/' == *path) {
1021
+ path++;
1022
+ } else if ('\0' != *path) {
1023
+ return loc;
1024
+ }
1025
+ do {
1026
+ if (1 >= cnt) {
1027
+ doc->where++;
1028
+ *doc->where = e;
1029
+ loc = move_step(doc, path, loc + 1);
1030
+ if (0 != loc) {
1031
+ *doc->where = 0;
1032
+ doc->where--;
1033
+ }
1034
+ break;
1035
+ }
1036
+ cnt--;
1037
+ e = e->next;
1038
+ } while (e != first);
1039
+ } else if (T_HASH == leaf->rtype) {
1040
+ const char *key = path;
1041
+ const char *slash = next_slash(path);
1042
+ int klen;
1043
+
1044
+ if (0 == slash) {
1045
+ klen = (int)strlen(key);
1046
+ path += klen;
1047
+ } else {
1048
+ klen = (int)(slash - key);
1049
+ path += klen + 1;
1050
+ }
1051
+ do {
1052
+ if (key_match(key, e->key, klen)) {
1053
+ doc->where++;
1054
+ *doc->where = e;
1055
+ loc = move_step(doc, path, loc + 1);
1056
+ if (0 != loc) {
1057
+ *doc->where = 0;
1058
+ doc->where--;
1059
+ }
1060
+ break;
1061
+ }
1062
+ e = e->next;
1063
+ } while (e != first);
1064
+ }
1065
+ }
1087
1066
  }
1088
1067
  return loc;
1089
1068
  }
1090
1069
 
1091
- static void
1092
- each_value(Doc doc, Leaf leaf) {
1070
+ static void each_value(Doc doc, Leaf leaf) {
1093
1071
  if (COL_VAL == leaf->value_type) {
1094
- if (0 != leaf->elements) {
1095
- Leaf first = leaf->elements->next;
1096
- Leaf e = first;
1097
-
1098
- do {
1099
- each_value(doc, e);
1100
- e = e->next;
1101
- } while (e != first);
1102
- }
1072
+ if (0 != leaf->elements) {
1073
+ Leaf first = leaf->elements->next;
1074
+ Leaf e = first;
1075
+
1076
+ do {
1077
+ each_value(doc, e);
1078
+ e = e->next;
1079
+ } while (e != first);
1080
+ }
1103
1081
  } else {
1104
- rb_yield(leaf_value(doc, leaf));
1082
+ rb_yield(leaf_value(doc, leaf));
1105
1083
  }
1106
1084
  }
1107
1085
 
@@ -1116,7 +1094,8 @@ each_value(Doc doc, Leaf leaf) {
1116
1094
  *
1117
1095
  * @param [String] json JSON document string
1118
1096
  * @yieldparam [Oj::Doc] doc parsed JSON document
1119
- * @yieldreturn [Object] returns the result of the yield as the result of the method call
1097
+ * @yieldreturn [Object] returns the result of the yield as the result of the
1098
+ * method call
1120
1099
  * @example
1121
1100
  * Oj::Doc.open('[1,2,3]') { |doc| doc.size() } #=> 4
1122
1101
  * # or as an alternative
@@ -1124,21 +1103,20 @@ each_value(Doc doc, Leaf leaf) {
1124
1103
  * doc.size() #=> 4
1125
1104
  * doc.close()
1126
1105
  */
1127
- static VALUE
1128
- doc_open(VALUE clas, VALUE str) {
1129
- char *json;
1130
- size_t len;
1131
- volatile VALUE obj;
1132
- int given = rb_block_given_p();
1133
- int allocate;
1106
+ static VALUE doc_open(VALUE clas, VALUE str) {
1107
+ char * json;
1108
+ size_t len;
1109
+ volatile VALUE obj;
1110
+ int given = rb_block_given_p();
1111
+ int allocate;
1134
1112
 
1135
1113
  Check_Type(str, T_STRING);
1136
- len = (int)RSTRING_LEN(str) + 1;
1137
- allocate = (SMALL_XML < len || !given);
1114
+ len = (int)RSTRING_LEN(str) + 1;
1115
+ allocate = (SMALL_JSON < len || !given);
1138
1116
  if (allocate) {
1139
- json = ALLOC_N(char, len);
1117
+ json = ALLOC_N(char, len);
1140
1118
  } else {
1141
- json = ALLOCA_N(char, len);
1119
+ json = ALLOCA_N(char, len);
1142
1120
  }
1143
1121
  // It should not be necessaary to stop GC but if it is not stopped and a
1144
1122
  // large string is parsed that string is corrupted or freed during
@@ -1149,7 +1127,7 @@ doc_open(VALUE clas, VALUE str) {
1149
1127
  obj = parse_json(clas, json, given, allocate);
1150
1128
  rb_gc_enable();
1151
1129
  if (given && allocate) {
1152
- xfree(json);
1130
+ xfree(json);
1153
1131
  }
1154
1132
  return obj;
1155
1133
  }
@@ -1163,7 +1141,8 @@ doc_open(VALUE clas, VALUE str) {
1163
1141
  *
1164
1142
  * @param [String] filename name of file that contains a JSON document
1165
1143
  * @yieldparam [Oj::Doc] doc parsed JSON document
1166
- * @yieldreturn [Object] returns the result of the yield as the result of the method call
1144
+ * @yieldreturn [Object] returns the result of the yield as the result of the
1145
+ * method call
1167
1146
  * @example
1168
1147
  * File.open('array.json', 'w') { |f| f.write('[1,2,3]') }
1169
1148
  * Oj::Doc.open_file(filename) { |doc| doc.size() } #=> 4
@@ -1172,34 +1151,35 @@ doc_open(VALUE clas, VALUE str) {
1172
1151
  * doc.size() #=> 4
1173
1152
  * doc.close()
1174
1153
  */
1175
- static VALUE
1176
- doc_open_file(VALUE clas, VALUE filename) {
1177
- char *path;
1178
- char *json;
1179
- FILE *f;
1180
- size_t len;
1181
- volatile VALUE obj;
1182
- int given = rb_block_given_p();
1183
- int allocate;
1154
+ static VALUE doc_open_file(VALUE clas, VALUE filename) {
1155
+ char * path;
1156
+ char * json;
1157
+ FILE * f;
1158
+ size_t len;
1159
+ volatile VALUE obj;
1160
+ int given = rb_block_given_p();
1161
+ int allocate;
1184
1162
 
1185
1163
  Check_Type(filename, T_STRING);
1186
1164
  path = StringValuePtr(filename);
1187
1165
  if (0 == (f = fopen(path, "r"))) {
1188
- rb_raise(rb_eIOError, "%s", strerror(errno));
1166
+ rb_raise(rb_eIOError, "%s", strerror(errno));
1189
1167
  }
1190
1168
  fseek(f, 0, SEEK_END);
1191
- len = ftell(f);
1192
- allocate = (SMALL_XML < len || !given);
1169
+ len = ftell(f);
1170
+ allocate = (SMALL_JSON < len || !given);
1193
1171
  if (allocate) {
1194
- json = ALLOC_N(char, len + 1);
1172
+ json = ALLOC_N(char, len + 1);
1195
1173
  } else {
1196
- json = ALLOCA_N(char, len + 1);
1174
+ json = ALLOCA_N(char, len + 1);
1197
1175
  }
1198
1176
  fseek(f, 0, SEEK_SET);
1199
1177
  if (len != fread(json, 1, len, f)) {
1200
- fclose(f);
1201
- rb_raise(rb_const_get_at(Oj, rb_intern("LoadError")),
1202
- "Failed to read %lu bytes from %s.", (unsigned long)len, path);
1178
+ fclose(f);
1179
+ rb_raise(rb_const_get_at(Oj, rb_intern("LoadError")),
1180
+ "Failed to read %lu bytes from %s.",
1181
+ (unsigned long)len,
1182
+ path);
1203
1183
  }
1204
1184
  fclose(f);
1205
1185
  json[len] = '\0';
@@ -1207,30 +1187,28 @@ doc_open_file(VALUE clas, VALUE filename) {
1207
1187
  obj = parse_json(clas, json, given, allocate);
1208
1188
  rb_gc_enable();
1209
1189
  if (given && allocate) {
1210
- xfree(json);
1190
+ xfree(json);
1211
1191
  }
1212
1192
  return obj;
1213
1193
  }
1214
1194
 
1215
- static int
1216
- esc_strlen(const char *s) {
1217
- int cnt = 0;
1195
+ static int esc_strlen(const char *s) {
1196
+ int cnt = 0;
1218
1197
 
1219
1198
  for (; '\0' != *s; s++, cnt++) {
1220
- if ('/' == *s) {
1221
- cnt++;
1222
- }
1199
+ if ('/' == *s) {
1200
+ cnt++;
1201
+ }
1223
1202
  }
1224
1203
  return cnt;
1225
1204
  }
1226
1205
 
1227
- static char*
1228
- append_key(char *p, const char *key) {
1206
+ static char *append_key(char *p, const char *key) {
1229
1207
  for (; '\0' != *key; p++, key++) {
1230
- if ('/' == *key) {
1231
- *p++ = '\\';
1232
- }
1233
- *p = *key;
1208
+ if ('/' == *key) {
1209
+ *p++ = '\\';
1210
+ }
1211
+ *p = *key;
1234
1212
  }
1235
1213
  return p;
1236
1214
  }
@@ -1244,41 +1222,40 @@ append_key(char *p, const char *key) {
1244
1222
  * Returns a String that describes the absolute path to the current location
1245
1223
  * in the JSON document.
1246
1224
  */
1247
- static VALUE
1248
- doc_where(VALUE self) {
1249
- Doc doc = self_doc(self);
1225
+ static VALUE doc_where(VALUE self) {
1226
+ Doc doc = self_doc(self);
1250
1227
 
1251
1228
  if (0 == *doc->where_path || doc->where == doc->where_path) {
1252
- return oj_slash_string;
1229
+ return oj_slash_string;
1253
1230
  } else {
1254
- Leaf *lp;
1255
- Leaf leaf;
1256
- size_t size = 3; // leading / and terminating \0
1257
- char *path;
1258
- char *p;
1259
-
1260
- for (lp = doc->where_path; lp <= doc->where; lp++) {
1261
- leaf = *lp;
1262
- if (T_HASH == leaf->parent_type) {
1263
- size += esc_strlen((*lp)->key) + 1;
1264
- } else if (T_ARRAY == leaf->parent_type) {
1265
- size += ((*lp)->index < 100) ? 3 : 11;
1266
- }
1267
- }
1268
- path = ALLOCA_N(char, size);
1269
- p = path;
1270
- for (lp = doc->where_path; lp <= doc->where; lp++) {
1271
- leaf = *lp;
1272
- if (T_HASH == leaf->parent_type) {
1273
- p = append_key(p, (*lp)->key);
1274
- } else if (T_ARRAY == leaf->parent_type) {
1275
- p = ulong_fill(p, (*lp)->index);
1276
- }
1277
- *p++ = '/';
1278
- }
1279
- *--p = '\0';
1280
-
1281
- return rb_str_new(path, p - path);
1231
+ Leaf * lp;
1232
+ Leaf leaf;
1233
+ size_t size = 3; // leading / and terminating \0
1234
+ char * path;
1235
+ char * p;
1236
+
1237
+ for (lp = doc->where_path; lp <= doc->where; lp++) {
1238
+ leaf = *lp;
1239
+ if (T_HASH == leaf->parent_type) {
1240
+ size += esc_strlen((*lp)->key) + 1;
1241
+ } else if (T_ARRAY == leaf->parent_type) {
1242
+ size += ((*lp)->index < 100) ? 3 : 11;
1243
+ }
1244
+ }
1245
+ path = ALLOCA_N(char, size);
1246
+ p = path;
1247
+ for (lp = doc->where_path; lp <= doc->where; lp++) {
1248
+ leaf = *lp;
1249
+ if (T_HASH == leaf->parent_type) {
1250
+ p = append_key(p, (*lp)->key);
1251
+ } else if (T_ARRAY == leaf->parent_type) {
1252
+ p = ulong_fill(p, (*lp)->index);
1253
+ }
1254
+ *p++ = '/';
1255
+ }
1256
+ *--p = '\0';
1257
+
1258
+ return rb_str_new(path, p - path);
1282
1259
  }
1283
1260
  }
1284
1261
 
@@ -1286,21 +1263,21 @@ doc_where(VALUE self) {
1286
1263
  *
1287
1264
  * Returns the final key to the current location.
1288
1265
  * @example
1289
- * Oj::Doc.open('[1,2,3]') { |doc| doc.move('/2'); doc.local_key() } #=> 2
1290
- * Oj::Doc.open('{"one":3}') { |doc| doc.move('/one'); doc.local_key() } #=> "one"
1291
- * Oj::Doc.open('[1,2,3]') { |doc| doc.local_key() } #=> nil
1266
+ * Oj::Doc.open('[1,2,3]') { |doc| doc.move('/2'); doc.local_key() } #=> 2
1267
+ * Oj::Doc.open('{"one":3}') { |doc| doc.move('/one'); doc.local_key() } #=>
1268
+ * "one" Oj::Doc.open('[1,2,3]') { |doc| doc.local_key() }
1269
+ * #=> nil
1292
1270
  */
1293
- static VALUE
1294
- doc_local_key(VALUE self) {
1295
- Doc doc = self_doc(self);
1296
- Leaf leaf = *doc->where;
1297
- volatile VALUE key = Qnil;
1271
+ static VALUE doc_local_key(VALUE self) {
1272
+ Doc doc = self_doc(self);
1273
+ Leaf leaf = *doc->where;
1274
+ volatile VALUE key = Qnil;
1298
1275
 
1299
1276
  if (T_HASH == leaf->parent_type) {
1300
- key = rb_str_new2(leaf->key);
1301
- key = oj_encode(key);
1277
+ key = rb_str_new2(leaf->key);
1278
+ key = oj_encode(key);
1302
1279
  } else if (T_ARRAY == leaf->parent_type) {
1303
- key = LONG2NUM(leaf->index);
1280
+ key = LONG2NUM(leaf->index);
1304
1281
  }
1305
1282
  return key;
1306
1283
  }
@@ -1310,14 +1287,14 @@ doc_local_key(VALUE self) {
1310
1287
  * Moves the document marker or location to the hoot or home position. The
1311
1288
  * same operation can be performed with a Oj::Doc.move('/').
1312
1289
  * @example
1313
- * Oj::Doc.open('[1,2,3]') { |doc| doc.move('/2'); doc.home(); doc.where? } #=> '/'
1290
+ * Oj::Doc.open('[1,2,3]') { |doc| doc.move('/2'); doc.home(); doc.where? }
1291
+ * #=> '/'
1314
1292
  */
1315
- static VALUE
1316
- doc_home(VALUE self) {
1317
- Doc doc = self_doc(self);
1293
+ static VALUE doc_home(VALUE self) {
1294
+ Doc doc = self_doc(self);
1318
1295
 
1319
1296
  *doc->where_path = doc->data;
1320
- doc->where = doc->where_path;
1297
+ doc->where = doc->where_path;
1321
1298
 
1322
1299
  return oj_slash_string;
1323
1300
  }
@@ -1333,38 +1310,38 @@ doc_home(VALUE self) {
1333
1310
  * Oj::Doc.open('[1,2]') { |doc| doc.type() } #=> Array
1334
1311
  * Oj::Doc.open('[1,2]') { |doc| doc.type('/1') } #=> Fixnum
1335
1312
  */
1336
- static VALUE
1337
- doc_type(int argc, VALUE *argv, VALUE self) {
1338
- Doc doc = self_doc(self);
1339
- Leaf leaf;
1340
- const char *path = 0;
1341
- VALUE type = Qnil;
1313
+ static VALUE doc_type(int argc, VALUE *argv, VALUE self) {
1314
+ Doc doc = self_doc(self);
1315
+ Leaf leaf;
1316
+ const char *path = 0;
1317
+ VALUE type = Qnil;
1342
1318
 
1343
1319
  if (1 <= argc) {
1344
- Check_Type(*argv, T_STRING);
1345
- path = StringValuePtr(*argv);
1320
+ Check_Type(*argv, T_STRING);
1321
+ path = StringValuePtr(*argv);
1346
1322
  }
1347
1323
  if (0 != (leaf = get_doc_leaf(doc, path))) {
1348
- switch (leaf->rtype) {
1349
- case T_NIL: type = rb_cNilClass; break;
1350
- case T_TRUE: type = rb_cTrueClass; break;
1351
- case T_FALSE: type = rb_cFalseClass; break;
1352
- case T_STRING: type = rb_cString; break;
1324
+ switch (leaf->rtype) {
1325
+ case T_NIL: type = rb_cNilClass; break;
1326
+ case T_TRUE: type = rb_cTrueClass; break;
1327
+ case T_FALSE: type = rb_cFalseClass; break;
1328
+ case T_STRING: type = rb_cString; break;
1353
1329
  #ifdef RUBY_INTEGER_UNIFICATION
1354
- case T_FIXNUM: type = rb_cInteger; break;
1330
+ case T_FIXNUM: type = rb_cInteger; break;
1355
1331
  #else
1356
- case T_FIXNUM: type = rb_cFixnum; break;
1332
+ case T_FIXNUM: type = rb_cFixnum; break;
1357
1333
  #endif
1358
- case T_FLOAT: type = rb_cFloat; break;
1359
- case T_ARRAY: type = rb_cArray; break;
1360
- case T_HASH: type = rb_cHash; break;
1361
- default: break;
1362
- }
1334
+ case T_FLOAT: type = rb_cFloat; break;
1335
+ case T_ARRAY: type = rb_cArray; break;
1336
+ case T_HASH: type = rb_cHash; break;
1337
+ default: break;
1338
+ }
1363
1339
  }
1364
1340
  return type;
1365
1341
  }
1366
1342
 
1367
- /* @overload fetch(path=nil) => nil, true, false, Fixnum, Float, String, Array, Hash
1343
+ /* @overload fetch(path=nil) => nil, true, false, Fixnum, Float, String, Array,
1344
+ * Hash
1368
1345
  *
1369
1346
  * Returns the value at the location identified by the path or the current
1370
1347
  * location if the path is nil or not provided. This method will create and
@@ -1376,23 +1353,22 @@ doc_type(int argc, VALUE *argv, VALUE self) {
1376
1353
  * Oj::Doc.open('[1,2]') { |doc| doc.fetch() } #=> [1, 2]
1377
1354
  * Oj::Doc.open('[1,2]') { |doc| doc.fetch('/1') } #=> 1
1378
1355
  */
1379
- static VALUE
1380
- doc_fetch(int argc, VALUE *argv, VALUE self) {
1381
- Doc doc;
1382
- Leaf leaf;
1383
- volatile VALUE val = Qnil;
1384
- const char *path = 0;
1356
+ static VALUE doc_fetch(int argc, VALUE *argv, VALUE self) {
1357
+ Doc doc;
1358
+ Leaf leaf;
1359
+ volatile VALUE val = Qnil;
1360
+ const char * path = 0;
1385
1361
 
1386
1362
  doc = self_doc(self);
1387
1363
  if (1 <= argc) {
1388
- Check_Type(*argv, T_STRING);
1389
- path = StringValuePtr(*argv);
1390
- if (2 == argc) {
1391
- val = argv[1];
1392
- }
1364
+ Check_Type(*argv, T_STRING);
1365
+ path = StringValuePtr(*argv);
1366
+ if (2 == argc) {
1367
+ val = argv[1];
1368
+ }
1393
1369
  }
1394
1370
  if (0 != (leaf = get_doc_leaf(doc, path))) {
1395
- val = leaf_value(doc, leaf);
1371
+ val = leaf_value(doc, leaf);
1396
1372
  }
1397
1373
  return val;
1398
1374
  }
@@ -1402,7 +1378,8 @@ doc_fetch(int argc, VALUE *argv, VALUE self) {
1402
1378
  * Yields to the provided block for each leaf node with the identified
1403
1379
  * location of the JSON document as the root. The parameter passed to the
1404
1380
  * block on yield is the Doc instance after moving to the child location.
1405
- * @param [String] path if provided it identified the top of the branch to process the leaves of
1381
+ * @param [String] path if provided it identified the top of the branch to
1382
+ * process the leaves of
1406
1383
  * @yieldparam [Doc] Doc at the child location
1407
1384
  * @example
1408
1385
  * Oj::Doc.open('[3,[2,1]]') { |doc|
@@ -1412,36 +1389,35 @@ doc_fetch(int argc, VALUE *argv, VALUE self) {
1412
1389
  * }
1413
1390
  * #=> ["/1" => 3, "/2/1" => 2, "/2/2" => 1]
1414
1391
  */
1415
- static VALUE
1416
- doc_each_leaf(int argc, VALUE *argv, VALUE self) {
1392
+ static VALUE doc_each_leaf(int argc, VALUE *argv, VALUE self) {
1417
1393
  if (rb_block_given_p()) {
1418
- Leaf save_path[MAX_STACK];
1419
- Doc doc = self_doc(self);
1420
- const char *path = 0;
1421
- size_t wlen;
1422
-
1423
- wlen = doc->where - doc->where_path;
1424
- if (0 < wlen) {
1425
- memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1));
1426
- }
1427
- if (1 <= argc) {
1428
- Check_Type(*argv, T_STRING);
1429
- path = StringValuePtr(*argv);
1430
- if ('/' == *path) {
1431
- doc->where = doc->where_path;
1432
- path++;
1433
- }
1434
- if (0 != move_step(doc, path, 1)) {
1435
- if (0 < wlen) {
1436
- memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
1437
- }
1438
- return Qnil;
1439
- }
1440
- }
1441
- each_leaf(doc, self);
1442
- if (0 < wlen) {
1443
- memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
1444
- }
1394
+ Leaf save_path[MAX_STACK];
1395
+ Doc doc = self_doc(self);
1396
+ const char *path = 0;
1397
+ size_t wlen;
1398
+
1399
+ wlen = doc->where - doc->where_path;
1400
+ if (0 < wlen) {
1401
+ memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1));
1402
+ }
1403
+ if (1 <= argc) {
1404
+ Check_Type(*argv, T_STRING);
1405
+ path = StringValuePtr(*argv);
1406
+ if ('/' == *path) {
1407
+ doc->where = doc->where_path;
1408
+ path++;
1409
+ }
1410
+ if (0 != move_step(doc, path, 1)) {
1411
+ if (0 < wlen) {
1412
+ memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
1413
+ }
1414
+ return Qnil;
1415
+ }
1416
+ }
1417
+ each_leaf(doc, self);
1418
+ if (0 < wlen) {
1419
+ memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
1420
+ }
1445
1421
  }
1446
1422
  return Qnil;
1447
1423
  }
@@ -1452,22 +1428,22 @@ doc_each_leaf(int argc, VALUE *argv, VALUE self) {
1452
1428
  * path or a relative path.
1453
1429
  * @param [String] path path to the location to move to
1454
1430
  * @example
1455
- * Oj::Doc.open('{"one":[1,2]') { |doc| doc.move('/one/2'); doc.where? } #=> "/one/2"
1431
+ * Oj::Doc.open('{"one":[1,2]') { |doc| doc.move('/one/2'); doc.where? } #=>
1432
+ * "/one/2"
1456
1433
  */
1457
- static VALUE
1458
- doc_move(VALUE self, VALUE str) {
1459
- Doc doc = self_doc(self);
1460
- const char *path;
1461
- int loc;
1434
+ static VALUE doc_move(VALUE self, VALUE str) {
1435
+ Doc doc = self_doc(self);
1436
+ const char *path;
1437
+ int loc;
1462
1438
 
1463
1439
  Check_Type(str, T_STRING);
1464
1440
  path = StringValuePtr(str);
1465
1441
  if ('/' == *path) {
1466
- doc->where = doc->where_path;
1467
- path++;
1442
+ doc->where = doc->where_path;
1443
+ path++;
1468
1444
  }
1469
1445
  if (0 != (loc = move_step(doc, path, 1))) {
1470
- rb_raise(rb_eArgError, "Failed to locate element %d of the path %s.", loc, path);
1446
+ rb_raise(rb_eArgError, "Failed to locate element %d of the path %s.", loc, path);
1471
1447
  }
1472
1448
  return Qnil;
1473
1449
  }
@@ -1478,7 +1454,8 @@ doc_move(VALUE self, VALUE str) {
1478
1454
  * identified location of the JSON document as the root. The parameter passed
1479
1455
  * to the block on yield is the Doc instance after moving to the child
1480
1456
  * location.
1481
- * @param [String] path if provided it identified the top of the branch to process the chilren of
1457
+ * @param [String] path if provided it identified the top of the branch to
1458
+ * process the chilren of
1482
1459
  * @yieldparam [Doc] Doc at the child location
1483
1460
  * @example
1484
1461
  * Oj::Doc.open('[3,[2,1]]') { |doc|
@@ -1488,46 +1465,45 @@ doc_move(VALUE self, VALUE str) {
1488
1465
  * }
1489
1466
  * #=> ["/2/1", "/2/2"]
1490
1467
  */
1491
- static VALUE
1492
- doc_each_child(int argc, VALUE *argv, VALUE self) {
1468
+ static VALUE doc_each_child(int argc, VALUE *argv, VALUE self) {
1493
1469
  if (rb_block_given_p()) {
1494
- Leaf save_path[MAX_STACK];
1495
- Doc doc = self_doc(self);
1496
- const char *path = 0;
1497
- size_t wlen;
1498
-
1499
- wlen = doc->where - doc->where_path;
1500
- if (0 < wlen) {
1501
- memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1));
1502
- }
1503
- if (1 <= argc) {
1504
- Check_Type(*argv, T_STRING);
1505
- path = StringValuePtr(*argv);
1506
- if ('/' == *path) {
1507
- doc->where = doc->where_path;
1508
- path++;
1509
- }
1510
- if (0 != move_step(doc, path, 1)) {
1511
- if (0 < wlen) {
1512
- memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
1513
- }
1514
- return Qnil;
1515
- }
1516
- }
1517
- if (COL_VAL == (*doc->where)->value_type && 0 != (*doc->where)->elements) {
1518
- Leaf first = (*doc->where)->elements->next;
1519
- Leaf e = first;
1520
-
1521
- doc->where++;
1522
- do {
1523
- *doc->where = e;
1524
- rb_yield(self);
1525
- e = e->next;
1526
- } while (e != first);
1527
- }
1528
- if (0 < wlen) {
1529
- memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
1530
- }
1470
+ Leaf save_path[MAX_STACK];
1471
+ Doc doc = self_doc(self);
1472
+ const char *path = 0;
1473
+ size_t wlen;
1474
+
1475
+ wlen = doc->where - doc->where_path;
1476
+ if (0 < wlen) {
1477
+ memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1));
1478
+ }
1479
+ if (1 <= argc) {
1480
+ Check_Type(*argv, T_STRING);
1481
+ path = StringValuePtr(*argv);
1482
+ if ('/' == *path) {
1483
+ doc->where = doc->where_path;
1484
+ path++;
1485
+ }
1486
+ if (0 != move_step(doc, path, 1)) {
1487
+ if (0 < wlen) {
1488
+ memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
1489
+ }
1490
+ return Qnil;
1491
+ }
1492
+ }
1493
+ if (COL_VAL == (*doc->where)->value_type && 0 != (*doc->where)->elements) {
1494
+ Leaf first = (*doc->where)->elements->next;
1495
+ Leaf e = first;
1496
+
1497
+ doc->where++;
1498
+ do {
1499
+ *doc->where = e;
1500
+ rb_yield(self);
1501
+ e = e->next;
1502
+ } while (e != first);
1503
+ }
1504
+ if (0 < wlen) {
1505
+ memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
1506
+ }
1531
1507
  }
1532
1508
  return Qnil;
1533
1509
  }
@@ -1538,7 +1514,8 @@ doc_each_child(int argc, VALUE *argv, VALUE self) {
1538
1514
  * of the JSON document. The parameter passed to the block on yield is the
1539
1515
  * value of the leaf. Only those leaves below the element specified by the
1540
1516
  * path parameter are processed.
1541
- * @param [String] path if provided it identified the top of the branch to process the leaf values of
1517
+ * @param [String] path if provided it identified the top of the branch to
1518
+ * process the leaf values of
1542
1519
  * @yieldparam [Object] val each leaf value
1543
1520
  * @example
1544
1521
  * Oj::Doc.open('[3,[2,1]]') { |doc|
@@ -1555,20 +1532,19 @@ doc_each_child(int argc, VALUE *argv, VALUE self) {
1555
1532
  * }
1556
1533
  * #=> [2, 1]
1557
1534
  */
1558
- static VALUE
1559
- doc_each_value(int argc, VALUE *argv, VALUE self) {
1535
+ static VALUE doc_each_value(int argc, VALUE *argv, VALUE self) {
1560
1536
  if (rb_block_given_p()) {
1561
- Doc doc = self_doc(self);
1562
- const char *path = 0;
1563
- Leaf leaf;
1564
-
1565
- if (1 <= argc) {
1566
- Check_Type(*argv, T_STRING);
1567
- path = StringValuePtr(*argv);
1568
- }
1569
- if (0 != (leaf = get_doc_leaf(doc, path))) {
1570
- each_value(doc, leaf);
1571
- }
1537
+ Doc doc = self_doc(self);
1538
+ const char *path = 0;
1539
+ Leaf leaf;
1540
+
1541
+ if (1 <= argc) {
1542
+ Check_Type(*argv, T_STRING);
1543
+ path = StringValuePtr(*argv);
1544
+ }
1545
+ if (0 != (leaf = get_doc_leaf(doc, path))) {
1546
+ each_value(doc, leaf);
1547
+ }
1572
1548
  }
1573
1549
  return Qnil;
1574
1550
  }
@@ -1577,52 +1553,53 @@ doc_each_value(int argc, VALUE *argv, VALUE self) {
1577
1553
  *
1578
1554
  * Dumps the document or nodes to a new JSON document. It uses the default
1579
1555
  * options for generating the JSON.
1580
- * @param path [String] if provided it identified the top of the branch to dump to JSON
1581
- * @param filename [String] if provided it is the filename to write the output to
1556
+ * @param path [String] if provided it identified the top of the branch to
1557
+ * dump to JSON
1558
+ * @param filename [String] if provided it is the filename to write the output
1559
+ * to
1582
1560
  * @example
1583
1561
  * Oj::Doc.open('[3,[2,1]]') { |doc|
1584
1562
  * doc.dump('/2')
1585
1563
  * }
1586
1564
  * #=> "[2,1]"
1587
1565
  */
1588
- static VALUE
1589
- doc_dump(int argc, VALUE *argv, VALUE self) {
1590
- Doc doc = self_doc(self);
1591
- Leaf leaf;
1592
- const char *path = 0;
1593
- const char *filename = 0;
1566
+ static VALUE doc_dump(int argc, VALUE *argv, VALUE self) {
1567
+ Doc doc = self_doc(self);
1568
+ Leaf leaf;
1569
+ const char *path = 0;
1570
+ const char *filename = 0;
1594
1571
 
1595
1572
  if (1 <= argc) {
1596
- if (Qnil != *argv) {
1597
- Check_Type(*argv, T_STRING);
1598
- path = StringValuePtr(*argv);
1599
- }
1600
- if (2 <= argc) {
1601
- Check_Type(argv[1], T_STRING);
1602
- filename = StringValuePtr(argv[1]);
1603
- }
1573
+ if (Qnil != *argv) {
1574
+ Check_Type(*argv, T_STRING);
1575
+ path = StringValuePtr(*argv);
1576
+ }
1577
+ if (2 <= argc) {
1578
+ Check_Type(argv[1], T_STRING);
1579
+ filename = StringValuePtr(argv[1]);
1580
+ }
1604
1581
  }
1605
1582
  if (0 != (leaf = get_doc_leaf(doc, path))) {
1606
- volatile VALUE rjson;
1607
-
1608
- if (0 == filename) {
1609
- char buf[4096];
1610
- struct _out out;
1611
-
1612
- out.buf = buf;
1613
- out.end = buf + sizeof(buf) - 10;
1614
- out.allocated = false;
1615
- out.omit_nil = oj_default_options.dump_opts.omit_nil;
1616
- oj_dump_leaf_to_json(leaf, &oj_default_options, &out);
1617
- rjson = rb_str_new2(out.buf);
1618
- if (out.allocated) {
1619
- xfree(out.buf);
1620
- }
1621
- } else {
1622
- oj_write_leaf_to_file(leaf, filename, &oj_default_options);
1623
- rjson = Qnil;
1624
- }
1625
- return rjson;
1583
+ volatile VALUE rjson;
1584
+
1585
+ if (0 == filename) {
1586
+ char buf[4096];
1587
+ struct _out out;
1588
+
1589
+ out.buf = buf;
1590
+ out.end = buf + sizeof(buf) - 10;
1591
+ out.allocated = false;
1592
+ out.omit_nil = oj_default_options.dump_opts.omit_nil;
1593
+ oj_dump_leaf_to_json(leaf, &oj_default_options, &out);
1594
+ rjson = rb_str_new2(out.buf);
1595
+ if (out.allocated) {
1596
+ xfree(out.buf);
1597
+ }
1598
+ } else {
1599
+ oj_write_leaf_to_file(leaf, filename, &oj_default_options);
1600
+ rjson = Qnil;
1601
+ }
1602
+ return rjson;
1626
1603
  }
1627
1604
  return Qnil;
1628
1605
  }
@@ -1635,8 +1612,7 @@ doc_dump(int argc, VALUE *argv, VALUE self) {
1635
1612
  * @example
1636
1613
  * Oj::Doc.open('[1,2,3]') { |doc| doc.size() } #=> 4
1637
1614
  */
1638
- static VALUE
1639
- doc_size(VALUE self) {
1615
+ static VALUE doc_size(VALUE self) {
1640
1616
  return ULONG2NUM(((Doc)DATA_PTR(self))->size);
1641
1617
  }
1642
1618
 
@@ -1649,16 +1625,15 @@ doc_size(VALUE self) {
1649
1625
  * doc.size() #=> 4
1650
1626
  * doc.close()
1651
1627
  */
1652
- static VALUE
1653
- doc_close(VALUE self) {
1654
- Doc doc = self_doc(self);
1628
+ static VALUE doc_close(VALUE self) {
1629
+ Doc doc = self_doc(self);
1655
1630
 
1656
1631
  rb_gc_unregister_address(&doc->self);
1657
1632
  DATA_PTR(doc->self) = 0;
1658
1633
  if (0 != doc) {
1659
- xfree(doc->json);
1660
- doc_free(doc);
1661
- xfree(doc);
1634
+ xfree(doc->json);
1635
+ doc_free(doc);
1636
+ xfree(doc);
1662
1637
  }
1663
1638
  return Qnil;
1664
1639
  }
@@ -1667,8 +1642,7 @@ doc_close(VALUE self) {
1667
1642
  Oj = rb_define_module("Oj");
1668
1643
  #endif
1669
1644
 
1670
- static VALUE
1671
- doc_not_implemented(VALUE self) {
1645
+ static VALUE doc_not_implemented(VALUE self) {
1672
1646
  rb_raise(rb_eNotImpError, "Not implemented.");
1673
1647
  return Qnil;
1674
1648
  }
@@ -1709,18 +1683,14 @@ doc_not_implemented(VALUE self) {
1709
1683
  * # move and get value
1710
1684
  * Oj::Doc.open(json) do |doc|
1711
1685
  * doc.move('/1/two')
1712
- * # doc location is now at the 'two' element of the hash that is the first element of the array.
1713
- * doc.fetch()
1714
- * end
1686
+ * # doc location is now at the 'two' element of the hash that is the first
1687
+ * element of the array. doc.fetch() end
1715
1688
  * #=> 2
1716
1689
  *
1717
- * # Now try again using a path to Oj::Doc.fetch() directly and not using a block.
1718
- * doc = Oj::Doc.open(json)
1719
- * doc.fetch('/2/three') #=> 3
1720
- * doc.close()
1690
+ * # Now try again using a path to Oj::Doc.fetch() directly and not using a
1691
+ * block. doc = Oj::Doc.open(json) doc.fetch('/2/three') #=> 3 doc.close()
1721
1692
  */
1722
- void
1723
- oj_init_doc() {
1693
+ void oj_init_doc() {
1724
1694
  oj_doc_class = rb_define_class_under(Oj, "Doc", rb_cObject);
1725
1695
  rb_define_singleton_method(oj_doc_class, "open", doc_open, 1);
1726
1696
  rb_define_singleton_method(oj_doc_class, "open_file", doc_open_file, 1);