oj 2.0.0 → 3.0.0
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.
- checksums.yaml +7 -0
- data/LICENSE +17 -23
- data/README.md +74 -425
- data/ext/oj/buf.h +103 -0
- data/ext/oj/cache8.c +4 -0
- data/ext/oj/circarray.c +68 -0
- data/ext/oj/circarray.h +23 -0
- data/ext/oj/code.c +227 -0
- data/ext/oj/code.h +40 -0
- data/ext/oj/compat.c +243 -0
- data/ext/oj/custom.c +1097 -0
- data/ext/oj/dump.c +766 -1534
- data/ext/oj/dump.h +92 -0
- data/ext/oj/dump_compat.c +937 -0
- data/ext/oj/dump_leaf.c +254 -0
- data/ext/oj/dump_object.c +810 -0
- data/ext/oj/dump_rails.c +329 -0
- data/ext/oj/dump_strict.c +416 -0
- data/ext/oj/encode.h +51 -0
- data/ext/oj/err.c +57 -0
- data/ext/oj/err.h +70 -0
- data/ext/oj/extconf.rb +17 -7
- data/ext/oj/fast.c +213 -180
- data/ext/oj/hash.c +163 -0
- data/ext/oj/hash.h +46 -0
- data/ext/oj/hash_test.c +512 -0
- data/ext/oj/mimic_json.c +817 -0
- data/ext/oj/mimic_rails.c +806 -0
- data/ext/oj/mimic_rails.h +17 -0
- data/ext/oj/object.c +752 -0
- data/ext/oj/odd.c +230 -0
- data/ext/oj/odd.h +44 -0
- data/ext/oj/oj.c +1288 -929
- data/ext/oj/oj.h +240 -69
- data/ext/oj/parse.c +1014 -0
- data/ext/oj/parse.h +92 -0
- data/ext/oj/reader.c +223 -0
- data/ext/oj/reader.h +151 -0
- data/ext/oj/resolve.c +127 -0
- data/ext/oj/{cache.h → resolve.h} +6 -13
- data/ext/oj/rxclass.c +133 -0
- data/ext/oj/rxclass.h +27 -0
- data/ext/oj/saj.c +77 -175
- data/ext/oj/scp.c +224 -0
- data/ext/oj/sparse.c +911 -0
- data/ext/oj/stream_writer.c +301 -0
- data/ext/oj/strict.c +162 -0
- data/ext/oj/string_writer.c +480 -0
- data/ext/oj/val_stack.c +98 -0
- data/ext/oj/val_stack.h +188 -0
- data/lib/oj/active_support_helper.rb +41 -0
- data/lib/oj/bag.rb +6 -10
- data/lib/oj/easy_hash.rb +52 -0
- data/lib/oj/json.rb +172 -0
- data/lib/oj/mimic.rb +260 -5
- data/lib/oj/saj.rb +13 -10
- data/lib/oj/schandler.rb +142 -0
- data/lib/oj/state.rb +131 -0
- data/lib/oj/version.rb +1 -1
- data/lib/oj.rb +11 -23
- data/pages/Advanced.md +22 -0
- data/pages/Compatibility.md +25 -0
- data/pages/Custom.md +23 -0
- data/pages/Encoding.md +65 -0
- data/pages/JsonGem.md +79 -0
- data/pages/Modes.md +140 -0
- data/pages/Options.md +250 -0
- data/pages/Rails.md +60 -0
- data/pages/Security.md +20 -0
- data/test/_test_active.rb +76 -0
- data/test/_test_active_mimic.rb +96 -0
- data/test/_test_mimic_rails.rb +126 -0
- data/test/activesupport4/decoding_test.rb +105 -0
- data/test/activesupport4/encoding_test.rb +531 -0
- data/test/activesupport4/test_helper.rb +41 -0
- data/test/activesupport5/decoding_test.rb +125 -0
- data/test/activesupport5/encoding_test.rb +483 -0
- data/test/activesupport5/encoding_test_cases.rb +90 -0
- data/test/activesupport5/test_helper.rb +50 -0
- data/test/activesupport5/time_zone_test_helpers.rb +24 -0
- data/test/helper.rb +27 -0
- data/test/isolated/shared.rb +310 -0
- data/test/isolated/test_mimic_after.rb +13 -0
- data/test/isolated/test_mimic_alone.rb +12 -0
- data/test/isolated/test_mimic_as_json.rb +45 -0
- data/test/isolated/test_mimic_before.rb +13 -0
- data/test/isolated/test_mimic_define.rb +28 -0
- data/test/isolated/test_mimic_rails_after.rb +22 -0
- data/test/isolated/test_mimic_rails_before.rb +21 -0
- data/test/isolated/test_mimic_redefine.rb +15 -0
- data/test/json_gem/json_addition_test.rb +216 -0
- data/test/json_gem/json_common_interface_test.rb +143 -0
- data/test/json_gem/json_encoding_test.rb +109 -0
- data/test/json_gem/json_ext_parser_test.rb +20 -0
- data/test/json_gem/json_fixtures_test.rb +35 -0
- data/test/json_gem/json_generator_test.rb +383 -0
- data/test/json_gem/json_generic_object_test.rb +90 -0
- data/test/json_gem/json_parser_test.rb +470 -0
- data/test/json_gem/json_string_matching_test.rb +42 -0
- data/test/json_gem/test_helper.rb +18 -0
- data/test/perf_compat.rb +130 -0
- data/test/perf_fast.rb +9 -9
- data/test/perf_file.rb +64 -0
- data/test/{perf_obj.rb → perf_object.rb} +24 -10
- data/test/perf_scp.rb +151 -0
- data/test/perf_strict.rb +32 -113
- data/test/sample.rb +2 -3
- data/test/test_compat.rb +474 -0
- data/test/test_custom.rb +355 -0
- data/test/test_debian.rb +53 -0
- data/test/test_fast.rb +66 -16
- data/test/test_file.rb +237 -0
- data/test/test_gc.rb +49 -0
- data/test/test_hash.rb +29 -0
- data/test/test_null.rb +376 -0
- data/test/test_object.rb +1010 -0
- data/test/test_saj.rb +16 -16
- data/test/test_scp.rb +417 -0
- data/test/test_strict.rb +410 -0
- data/test/test_various.rb +815 -0
- data/test/test_writer.rb +308 -0
- data/test/tests.rb +9 -902
- data/test/tests_mimic.rb +14 -0
- data/test/tests_mimic_addition.rb +7 -0
- metadata +253 -38
- data/ext/oj/cache.c +0 -148
- data/ext/oj/foo.rb +0 -6
- data/ext/oj/load.c +0 -1049
- data/test/a.rb +0 -38
- data/test/perf1.rb +0 -64
- data/test/perf2.rb +0 -76
- data/test/perf_obj_old.rb +0 -213
- data/test/test_mimic.rb +0 -208
data/ext/oj/parse.h
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/* parse.h
|
|
2
|
+
* Copyright (c) 2011, Peter Ohler
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#ifndef __OJ_PARSE_H__
|
|
7
|
+
#define __OJ_PARSE_H__
|
|
8
|
+
|
|
9
|
+
#include <stdarg.h>
|
|
10
|
+
#include <stdio.h>
|
|
11
|
+
#include <string.h>
|
|
12
|
+
|
|
13
|
+
#include "ruby.h"
|
|
14
|
+
#include "oj.h"
|
|
15
|
+
#include "val_stack.h"
|
|
16
|
+
#include "circarray.h"
|
|
17
|
+
#include "reader.h"
|
|
18
|
+
#include "rxclass.h"
|
|
19
|
+
|
|
20
|
+
struct _RxClass;
|
|
21
|
+
|
|
22
|
+
typedef struct _NumInfo {
|
|
23
|
+
int64_t i;
|
|
24
|
+
int64_t num;
|
|
25
|
+
int64_t div;
|
|
26
|
+
int64_t di;
|
|
27
|
+
const char *str;
|
|
28
|
+
size_t len;
|
|
29
|
+
long exp;
|
|
30
|
+
int big;
|
|
31
|
+
int infinity;
|
|
32
|
+
int nan;
|
|
33
|
+
int neg;
|
|
34
|
+
int hasExp;
|
|
35
|
+
int no_big;
|
|
36
|
+
} *NumInfo;
|
|
37
|
+
|
|
38
|
+
typedef struct _ParseInfo {
|
|
39
|
+
// used for the string parser
|
|
40
|
+
const char *json;
|
|
41
|
+
const char *cur;
|
|
42
|
+
const char *end;
|
|
43
|
+
// used for the stream parser
|
|
44
|
+
struct _Reader rd;
|
|
45
|
+
|
|
46
|
+
struct _Err err;
|
|
47
|
+
struct _Options options;
|
|
48
|
+
VALUE handler;
|
|
49
|
+
struct _ValStack stack;
|
|
50
|
+
CircArray circ_array;
|
|
51
|
+
struct _RxClass str_rx;
|
|
52
|
+
int expect_value;
|
|
53
|
+
int max_depth; // just for the json gem
|
|
54
|
+
VALUE proc;
|
|
55
|
+
VALUE (*start_hash)(struct _ParseInfo *pi);
|
|
56
|
+
void (*end_hash)(struct _ParseInfo *pi);
|
|
57
|
+
VALUE (*hash_key)(struct _ParseInfo *pi, const char *key, size_t klen);
|
|
58
|
+
void (*hash_set_cstr)(struct _ParseInfo *pi, Val kval, const char *str, size_t len, const char *orig);
|
|
59
|
+
void (*hash_set_num)(struct _ParseInfo *pi, Val kval, NumInfo ni);
|
|
60
|
+
void (*hash_set_value)(struct _ParseInfo *pi, Val kval, VALUE value);
|
|
61
|
+
|
|
62
|
+
VALUE (*start_array)(struct _ParseInfo *pi);
|
|
63
|
+
void (*end_array)(struct _ParseInfo *pi);
|
|
64
|
+
void (*array_append_cstr)(struct _ParseInfo *pi, const char *str, size_t len, const char *orig);
|
|
65
|
+
void (*array_append_num)(struct _ParseInfo *pi, NumInfo ni);
|
|
66
|
+
void (*array_append_value)(struct _ParseInfo *pi, VALUE value);
|
|
67
|
+
|
|
68
|
+
void (*add_cstr)(struct _ParseInfo *pi, const char *str, size_t len, const char *orig);
|
|
69
|
+
void (*add_num)(struct _ParseInfo *pi, NumInfo ni);
|
|
70
|
+
void (*add_value)(struct _ParseInfo *pi, VALUE val);
|
|
71
|
+
VALUE err_class;
|
|
72
|
+
bool has_callbacks;
|
|
73
|
+
} *ParseInfo;
|
|
74
|
+
|
|
75
|
+
extern void oj_parse2(ParseInfo pi);
|
|
76
|
+
extern void oj_set_error_at(ParseInfo pi, VALUE err_clas, const char* file, int line, const char *format, ...);
|
|
77
|
+
extern VALUE oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yieldOk);
|
|
78
|
+
extern VALUE oj_num_as_value(NumInfo ni);
|
|
79
|
+
|
|
80
|
+
extern void oj_set_strict_callbacks(ParseInfo pi);
|
|
81
|
+
extern void oj_set_object_callbacks(ParseInfo pi);
|
|
82
|
+
extern void oj_set_compat_callbacks(ParseInfo pi);
|
|
83
|
+
|
|
84
|
+
extern void oj_sparse2(ParseInfo pi);
|
|
85
|
+
extern VALUE oj_pi_sparse(int argc, VALUE *argv, ParseInfo pi, int fd);
|
|
86
|
+
|
|
87
|
+
static inline void
|
|
88
|
+
parse_info_init(ParseInfo pi) {
|
|
89
|
+
memset(pi, 0, sizeof(struct _ParseInfo));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
#endif /* __OJ_PARSE_H__ */
|
data/ext/oj/reader.c
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/* reader.c
|
|
2
|
+
* Copyright (c) 2011, Peter Ohler
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#include <stdlib.h>
|
|
7
|
+
#include <errno.h>
|
|
8
|
+
#include <stdio.h>
|
|
9
|
+
#include <strings.h>
|
|
10
|
+
#include <sys/types.h>
|
|
11
|
+
#if NEEDS_UIO
|
|
12
|
+
#include <sys/uio.h>
|
|
13
|
+
#endif
|
|
14
|
+
#include <unistd.h>
|
|
15
|
+
#include <time.h>
|
|
16
|
+
|
|
17
|
+
#include "ruby.h"
|
|
18
|
+
#include "oj.h"
|
|
19
|
+
#include "reader.h"
|
|
20
|
+
|
|
21
|
+
#define BUF_PAD 4
|
|
22
|
+
|
|
23
|
+
static VALUE rescue_cb(VALUE rdr, VALUE err);
|
|
24
|
+
static VALUE io_cb(VALUE rdr);
|
|
25
|
+
static VALUE partial_io_cb(VALUE rdr);
|
|
26
|
+
static int read_from_io(Reader reader);
|
|
27
|
+
static int read_from_fd(Reader reader);
|
|
28
|
+
static int read_from_io_partial(Reader reader);
|
|
29
|
+
//static int read_from_str(Reader reader);
|
|
30
|
+
|
|
31
|
+
void
|
|
32
|
+
oj_reader_init(Reader reader, VALUE io, int fd) {
|
|
33
|
+
VALUE io_class = rb_obj_class(io);
|
|
34
|
+
VALUE stat;
|
|
35
|
+
VALUE ftype;
|
|
36
|
+
|
|
37
|
+
reader->head = reader->base;
|
|
38
|
+
*((char*)reader->head) = '\0';
|
|
39
|
+
reader->end = reader->head + sizeof(reader->base) - BUF_PAD;
|
|
40
|
+
reader->tail = reader->head;
|
|
41
|
+
reader->read_end = reader->head;
|
|
42
|
+
reader->pro = 0;
|
|
43
|
+
reader->str = 0;
|
|
44
|
+
reader->pos = 0;
|
|
45
|
+
reader->line = 1;
|
|
46
|
+
reader->col = 0;
|
|
47
|
+
reader->free_head = 0;
|
|
48
|
+
|
|
49
|
+
if (0 != fd) {
|
|
50
|
+
reader->read_func = read_from_fd;
|
|
51
|
+
reader->fd = fd;
|
|
52
|
+
} else if (rb_cString == io_class) {
|
|
53
|
+
reader->read_func = 0;
|
|
54
|
+
reader->in_str = StringValuePtr(io);
|
|
55
|
+
reader->head = (char*)reader->in_str;
|
|
56
|
+
reader->tail = reader->head;
|
|
57
|
+
reader->read_end = reader->head + RSTRING_LEN(io);
|
|
58
|
+
} else if (oj_stringio_class == io_class) {
|
|
59
|
+
VALUE s = rb_funcall2(io, oj_string_id, 0, 0);
|
|
60
|
+
|
|
61
|
+
reader->read_func = 0;
|
|
62
|
+
reader->in_str = StringValuePtr(s);
|
|
63
|
+
reader->head = (char*)reader->in_str;
|
|
64
|
+
reader->tail = reader->head;
|
|
65
|
+
reader->read_end = reader->head + RSTRING_LEN(s);
|
|
66
|
+
} else if (rb_cFile == io_class &&
|
|
67
|
+
Qnil != (stat = rb_funcall(io, oj_stat_id, 0)) &&
|
|
68
|
+
Qnil != (ftype = rb_funcall(stat, oj_ftype_id, 0)) &&
|
|
69
|
+
0 == strcmp("file", StringValuePtr(ftype)) &&
|
|
70
|
+
0 == FIX2INT(rb_funcall(io, oj_pos_id, 0))) {
|
|
71
|
+
reader->read_func = read_from_fd;
|
|
72
|
+
reader->fd = FIX2INT(rb_funcall(io, oj_fileno_id, 0));
|
|
73
|
+
} else if (rb_respond_to(io, oj_readpartial_id)) {
|
|
74
|
+
reader->read_func = read_from_io_partial;
|
|
75
|
+
reader->io = io;
|
|
76
|
+
} else if (rb_respond_to(io, oj_read_id)) {
|
|
77
|
+
reader->read_func = read_from_io;
|
|
78
|
+
reader->io = io;
|
|
79
|
+
} else {
|
|
80
|
+
rb_raise(rb_eArgError, "parser io argument must be a String or respond to readpartial() or read().\n");
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
int
|
|
85
|
+
oj_reader_read(Reader reader) {
|
|
86
|
+
int err;
|
|
87
|
+
size_t shift = 0;
|
|
88
|
+
|
|
89
|
+
if (0 == reader->read_func) {
|
|
90
|
+
return -1;
|
|
91
|
+
}
|
|
92
|
+
// if there is not much room to read into, shift or realloc a larger buffer.
|
|
93
|
+
if (reader->head < reader->tail && 4096 > reader->end - reader->tail) {
|
|
94
|
+
if (0 == reader->pro) {
|
|
95
|
+
shift = reader->tail - reader->head;
|
|
96
|
+
} else {
|
|
97
|
+
shift = reader->pro - reader->head - 1; // leave one character so we can backup one
|
|
98
|
+
}
|
|
99
|
+
if (0 >= shift) { /* no space left so allocate more */
|
|
100
|
+
const char *old = reader->head;
|
|
101
|
+
size_t size = reader->end - reader->head + BUF_PAD;
|
|
102
|
+
|
|
103
|
+
if (reader->head == reader->base) {
|
|
104
|
+
reader->head = ALLOC_N(char, size * 2);
|
|
105
|
+
memcpy((char*)reader->head, old, size);
|
|
106
|
+
} else {
|
|
107
|
+
REALLOC_N(reader->head, char, size * 2);
|
|
108
|
+
}
|
|
109
|
+
reader->free_head = 1;
|
|
110
|
+
reader->end = reader->head + size * 2 - BUF_PAD;
|
|
111
|
+
reader->tail = reader->head + (reader->tail - old);
|
|
112
|
+
reader->read_end = reader->head + (reader->read_end - old);
|
|
113
|
+
if (0 != reader->pro) {
|
|
114
|
+
reader->pro = reader->head + (reader->pro - old);
|
|
115
|
+
}
|
|
116
|
+
if (0 != reader->str) {
|
|
117
|
+
reader->str = reader->head + (reader->str - old);
|
|
118
|
+
}
|
|
119
|
+
} else {
|
|
120
|
+
memmove((char*)reader->head, reader->head + shift, reader->read_end - (reader->head + shift));
|
|
121
|
+
reader->tail -= shift;
|
|
122
|
+
reader->read_end -= shift;
|
|
123
|
+
if (0 != reader->pro) {
|
|
124
|
+
reader->pro -= shift;
|
|
125
|
+
}
|
|
126
|
+
if (0 != reader->str) {
|
|
127
|
+
reader->str -= shift;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
err = reader->read_func(reader);
|
|
132
|
+
*(char*)reader->read_end = '\0';
|
|
133
|
+
|
|
134
|
+
return err;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
static VALUE
|
|
138
|
+
rescue_cb(VALUE rbuf, VALUE err) {
|
|
139
|
+
VALUE clas = rb_obj_class(err);
|
|
140
|
+
|
|
141
|
+
if (rb_eTypeError != clas && rb_eEOFError != clas) {
|
|
142
|
+
Reader reader = (Reader)rbuf;
|
|
143
|
+
|
|
144
|
+
rb_raise(clas, "at line %d, column %d\n", reader->line, reader->col);
|
|
145
|
+
}
|
|
146
|
+
return Qfalse;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
static VALUE
|
|
150
|
+
partial_io_cb(VALUE rbuf) {
|
|
151
|
+
Reader reader = (Reader)rbuf;
|
|
152
|
+
VALUE args[1];
|
|
153
|
+
VALUE rstr;
|
|
154
|
+
char *str;
|
|
155
|
+
size_t cnt;
|
|
156
|
+
|
|
157
|
+
args[0] = ULONG2NUM(reader->end - reader->tail);
|
|
158
|
+
rstr = rb_funcall2(reader->io, oj_readpartial_id, 1, args);
|
|
159
|
+
if (Qnil == rstr) {
|
|
160
|
+
return Qfalse;
|
|
161
|
+
}
|
|
162
|
+
str = StringValuePtr(rstr);
|
|
163
|
+
cnt = RSTRING_LEN(rstr);
|
|
164
|
+
//printf("*** partial read %lu bytes, str: '%s'\n", cnt, str);
|
|
165
|
+
strcpy(reader->tail, str);
|
|
166
|
+
reader->read_end = reader->tail + cnt;
|
|
167
|
+
|
|
168
|
+
return Qtrue;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
static VALUE
|
|
172
|
+
io_cb(VALUE rbuf) {
|
|
173
|
+
Reader reader = (Reader)rbuf;
|
|
174
|
+
VALUE args[1];
|
|
175
|
+
VALUE rstr;
|
|
176
|
+
char *str;
|
|
177
|
+
size_t cnt;
|
|
178
|
+
|
|
179
|
+
args[0] = ULONG2NUM(reader->end - reader->tail);
|
|
180
|
+
rstr = rb_funcall2(reader->io, oj_read_id, 1, args);
|
|
181
|
+
if (Qnil == rstr) {
|
|
182
|
+
return Qfalse;
|
|
183
|
+
}
|
|
184
|
+
str = StringValuePtr(rstr);
|
|
185
|
+
cnt = RSTRING_LEN(rstr);
|
|
186
|
+
//printf("*** read %lu bytes, str: '%s'\n", cnt, str);
|
|
187
|
+
strcpy(reader->tail, str);
|
|
188
|
+
reader->read_end = reader->tail + cnt;
|
|
189
|
+
|
|
190
|
+
return Qtrue;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
static int
|
|
194
|
+
read_from_io_partial(Reader reader) {
|
|
195
|
+
return (Qfalse == rb_rescue(partial_io_cb, (VALUE)reader, rescue_cb, (VALUE)reader));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
static int
|
|
199
|
+
read_from_io(Reader reader) {
|
|
200
|
+
return (Qfalse == rb_rescue(io_cb, (VALUE)reader, rescue_cb, (VALUE)reader));
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
static int
|
|
204
|
+
read_from_fd(Reader reader) {
|
|
205
|
+
ssize_t cnt;
|
|
206
|
+
size_t max = reader->end - reader->tail;
|
|
207
|
+
|
|
208
|
+
cnt = read(reader->fd, reader->tail, max);
|
|
209
|
+
if (cnt <= 0) {
|
|
210
|
+
return -1;
|
|
211
|
+
} else if (0 != cnt) {
|
|
212
|
+
reader->read_end = reader->tail + cnt;
|
|
213
|
+
}
|
|
214
|
+
return 0;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// This is only called when the end of the string is reached so just return -1.
|
|
218
|
+
/*
|
|
219
|
+
static int
|
|
220
|
+
read_from_str(Reader reader) {
|
|
221
|
+
return -1;
|
|
222
|
+
}
|
|
223
|
+
*/
|
data/ext/oj/reader.h
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/* reader.h
|
|
2
|
+
* Copyright (c) 2011, Peter Ohler
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#ifndef __OJ_READER_H__
|
|
7
|
+
#define __OJ_READER_H__
|
|
8
|
+
|
|
9
|
+
typedef struct _Reader {
|
|
10
|
+
char base[0x00001000];
|
|
11
|
+
char *head;
|
|
12
|
+
char *end;
|
|
13
|
+
char *tail;
|
|
14
|
+
char *read_end; /* one past last character read */
|
|
15
|
+
char *pro; /* protection start, buffer can not slide past this point */
|
|
16
|
+
char *str; /* start of current string being read */
|
|
17
|
+
long pos;
|
|
18
|
+
int line;
|
|
19
|
+
int col;
|
|
20
|
+
int free_head;
|
|
21
|
+
int (*read_func)(struct _Reader *reader);
|
|
22
|
+
union {
|
|
23
|
+
int fd;
|
|
24
|
+
VALUE io;
|
|
25
|
+
const char *in_str;
|
|
26
|
+
};
|
|
27
|
+
} *Reader;
|
|
28
|
+
|
|
29
|
+
extern void oj_reader_init(Reader reader, VALUE io, int fd);
|
|
30
|
+
extern int oj_reader_read(Reader reader);
|
|
31
|
+
|
|
32
|
+
static inline char
|
|
33
|
+
reader_get(Reader reader) {
|
|
34
|
+
//printf("*** drive get from '%s' from start: %ld buf: %p from read_end: %ld\n", reader->tail, reader->tail - reader->head, reader->head, reader->read_end - reader->tail);
|
|
35
|
+
if (reader->read_end <= reader->tail) {
|
|
36
|
+
if (0 != oj_reader_read(reader)) {
|
|
37
|
+
return '\0';
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if ('\n' == *reader->tail) {
|
|
41
|
+
reader->line++;
|
|
42
|
+
reader->col = 0;
|
|
43
|
+
}
|
|
44
|
+
reader->col++;
|
|
45
|
+
reader->pos++;
|
|
46
|
+
|
|
47
|
+
return *reader->tail++;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
static inline void
|
|
51
|
+
reader_backup(Reader reader) {
|
|
52
|
+
reader->tail--;
|
|
53
|
+
reader->col--;
|
|
54
|
+
reader->pos--;
|
|
55
|
+
if (0 >= reader->col) {
|
|
56
|
+
reader->line--;
|
|
57
|
+
// allow col to be negative since we never backup twice in a row
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
static inline void
|
|
62
|
+
reader_protect(Reader reader) {
|
|
63
|
+
reader->pro = reader->tail;
|
|
64
|
+
reader->str = reader->tail; // can't have str before pro
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static inline void
|
|
68
|
+
reader_release(Reader reader) {
|
|
69
|
+
reader->pro = 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* Starts by reading a character so it is safe to use with an empty or
|
|
73
|
+
* compacted buffer.
|
|
74
|
+
*/
|
|
75
|
+
static inline char
|
|
76
|
+
reader_next_non_white(Reader reader) {
|
|
77
|
+
char c;
|
|
78
|
+
|
|
79
|
+
while ('\0' != (c = reader_get(reader))) {
|
|
80
|
+
switch(c) {
|
|
81
|
+
case ' ':
|
|
82
|
+
case '\t':
|
|
83
|
+
case '\f':
|
|
84
|
+
case '\n':
|
|
85
|
+
case '\r':
|
|
86
|
+
break;
|
|
87
|
+
default:
|
|
88
|
+
return c;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return '\0';
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/* Starts by reading a character so it is safe to use with an empty or
|
|
95
|
+
* compacted buffer.
|
|
96
|
+
*/
|
|
97
|
+
static inline char
|
|
98
|
+
reader_next_white(Reader reader) {
|
|
99
|
+
char c;
|
|
100
|
+
|
|
101
|
+
while ('\0' != (c = reader_get(reader))) {
|
|
102
|
+
switch(c) {
|
|
103
|
+
case ' ':
|
|
104
|
+
case '\t':
|
|
105
|
+
case '\f':
|
|
106
|
+
case '\n':
|
|
107
|
+
case '\r':
|
|
108
|
+
case '\0':
|
|
109
|
+
return c;
|
|
110
|
+
default:
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return '\0';
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
static inline int
|
|
118
|
+
reader_expect(Reader reader, const char *s) {
|
|
119
|
+
for (; '\0' != *s; s++) {
|
|
120
|
+
if (reader_get(reader) != *s) {
|
|
121
|
+
return -1;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return 0;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
static inline void
|
|
128
|
+
reader_cleanup(Reader reader) {
|
|
129
|
+
if (reader->free_head && 0 != reader->head) {
|
|
130
|
+
xfree((char*)reader->head);
|
|
131
|
+
reader->head = 0;
|
|
132
|
+
reader->free_head = 0;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
static inline int
|
|
137
|
+
is_white(char c) {
|
|
138
|
+
switch(c) {
|
|
139
|
+
case ' ':
|
|
140
|
+
case '\t':
|
|
141
|
+
case '\f':
|
|
142
|
+
case '\n':
|
|
143
|
+
case '\r':
|
|
144
|
+
return 1;
|
|
145
|
+
default:
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
return 0;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
#endif /* __OJ_READER_H__ */
|
data/ext/oj/resolve.c
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/* resolve.c
|
|
2
|
+
* Copyright (c) 2012, Peter Ohler
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
*
|
|
5
|
+
* Redistribution and use in source and binary forms, with or without
|
|
6
|
+
* modification, are permitted provided that the following conditions are met:
|
|
7
|
+
*
|
|
8
|
+
* - Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
* list of conditions and the following disclaimer.
|
|
10
|
+
*
|
|
11
|
+
* - Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
* this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
* and/or other materials provided with the distribution.
|
|
14
|
+
*
|
|
15
|
+
* - Neither the name of Peter Ohler nor the names of its contributors may be
|
|
16
|
+
* used to endorse or promote products derived from this software without
|
|
17
|
+
* specific prior written permission.
|
|
18
|
+
*
|
|
19
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
#include <stdlib.h>
|
|
32
|
+
#include <stdio.h>
|
|
33
|
+
#include <string.h>
|
|
34
|
+
#if USE_PTHREAD_MUTEX
|
|
35
|
+
#include <pthread.h>
|
|
36
|
+
#endif
|
|
37
|
+
|
|
38
|
+
#include "oj.h"
|
|
39
|
+
#include "err.h"
|
|
40
|
+
#include "parse.h"
|
|
41
|
+
#include "hash.h"
|
|
42
|
+
|
|
43
|
+
inline static VALUE
|
|
44
|
+
resolve_classname(VALUE mod, const char *classname, int auto_define) {
|
|
45
|
+
VALUE clas;
|
|
46
|
+
ID ci = rb_intern(classname);
|
|
47
|
+
|
|
48
|
+
if (rb_const_defined_at(mod, ci)) {
|
|
49
|
+
clas = rb_const_get_at(mod, ci);
|
|
50
|
+
} else if (auto_define) {
|
|
51
|
+
clas = rb_define_class_under(mod, classname, oj_bag_class);
|
|
52
|
+
} else {
|
|
53
|
+
clas = Qundef;
|
|
54
|
+
}
|
|
55
|
+
return clas;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
static VALUE
|
|
59
|
+
resolve_classpath(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class) {
|
|
60
|
+
char class_name[1024];
|
|
61
|
+
VALUE clas;
|
|
62
|
+
char *end = class_name + sizeof(class_name) - 1;
|
|
63
|
+
char *s;
|
|
64
|
+
const char *n = name;
|
|
65
|
+
|
|
66
|
+
clas = rb_cObject;
|
|
67
|
+
for (s = class_name; 0 < len; n++, len--) {
|
|
68
|
+
if (':' == *n) {
|
|
69
|
+
*s = '\0';
|
|
70
|
+
n++;
|
|
71
|
+
len--;
|
|
72
|
+
if (':' != *n) {
|
|
73
|
+
return Qundef;
|
|
74
|
+
}
|
|
75
|
+
if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
|
|
76
|
+
return Qundef;
|
|
77
|
+
}
|
|
78
|
+
s = class_name;
|
|
79
|
+
} else if (end <= s) {
|
|
80
|
+
return Qundef;
|
|
81
|
+
} else {
|
|
82
|
+
*s++ = *n;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
*s = '\0';
|
|
86
|
+
if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
|
|
87
|
+
oj_set_error_at(pi, error_class, __FILE__, __LINE__, "class %s is not defined", name);
|
|
88
|
+
if (Qnil != error_class) {
|
|
89
|
+
pi->err_class = error_class;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return clas;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
VALUE
|
|
96
|
+
oj_name2class(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class) {
|
|
97
|
+
VALUE clas;
|
|
98
|
+
VALUE *slot;
|
|
99
|
+
|
|
100
|
+
if (No == pi->options.class_cache) {
|
|
101
|
+
return resolve_classpath(pi, name, len, auto_define, error_class);
|
|
102
|
+
}
|
|
103
|
+
#if USE_PTHREAD_MUTEX
|
|
104
|
+
pthread_mutex_lock(&oj_cache_mutex);
|
|
105
|
+
#elif USE_RB_MUTEX
|
|
106
|
+
rb_mutex_lock(oj_cache_mutex);
|
|
107
|
+
#endif
|
|
108
|
+
if (Qnil == (clas = oj_class_hash_get(name, len, &slot))) {
|
|
109
|
+
if (Qundef != (clas = resolve_classpath(pi, name, len, auto_define, error_class))) {
|
|
110
|
+
*slot = clas;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
#if USE_PTHREAD_MUTEX
|
|
114
|
+
pthread_mutex_unlock(&oj_cache_mutex);
|
|
115
|
+
#elif USE_RB_MUTEX
|
|
116
|
+
rb_mutex_unlock(oj_cache_mutex);
|
|
117
|
+
#endif
|
|
118
|
+
return clas;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
VALUE
|
|
122
|
+
oj_name2struct(ParseInfo pi, VALUE nameVal, VALUE error_class) {
|
|
123
|
+
size_t len = RSTRING_LEN(nameVal);
|
|
124
|
+
const char *str = StringValuePtr(nameVal);
|
|
125
|
+
|
|
126
|
+
return resolve_classpath(pi, str, len, 0, error_class);
|
|
127
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*
|
|
1
|
+
/* resolve.h
|
|
2
2
|
* Copyright (c) 2011, Peter Ohler
|
|
3
3
|
* All rights reserved.
|
|
4
4
|
*
|
|
@@ -28,19 +28,12 @@
|
|
|
28
28
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
-
#ifndef
|
|
32
|
-
#define
|
|
33
|
-
|
|
34
|
-
#define RSTRING_NOT_MODIFIED
|
|
31
|
+
#ifndef __OJ_RESOLVE_H__
|
|
32
|
+
#define __OJ_RESOLVE_H__
|
|
35
33
|
|
|
36
34
|
#include "ruby.h"
|
|
37
35
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
extern void oj_cache_new(Cache *cache);
|
|
41
|
-
|
|
42
|
-
extern VALUE oj_cache_get(Cache cache, const char *key, VALUE **slot);
|
|
43
|
-
|
|
44
|
-
extern void oj_cache_print(Cache cache);
|
|
36
|
+
extern VALUE oj_name2class(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class);
|
|
37
|
+
extern VALUE oj_name2struct(ParseInfo pi, VALUE nameVal, VALUE error_class);
|
|
45
38
|
|
|
46
|
-
#endif /*
|
|
39
|
+
#endif /* __OJ_RESOLVE_H__ */
|