oj 3.11.1 → 3.11.6

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