oj 3.11.2 → 3.11.7

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