jsonsl 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,14 @@
1
+ --- jsonsl.h.orig 2018-08-08 22:32:20.688856662 +0300
2
+ +++ jsonsl.h 2018-08-08 22:34:01.616759720 +0300
3
+ @@ -12,6 +12,11 @@
4
+ #ifndef JSONSL_H_
5
+ #define JSONSL_H_
6
+
7
+ +#include <ruby.h>
8
+ +#define JSONSL_STATE_USER_FIELDS \
9
+ + VALUE val; \
10
+ + VALUE pkey;
11
+ +
12
+ #include <stdio.h>
13
+ #include <stdlib.h>
14
+ #include <stddef.h>
@@ -0,0 +1 @@
1
+ 684b60f9af68b8c397422e74d0c2dd206de16a2c
@@ -0,0 +1,164 @@
1
+ /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Author:: Couchbase <info@couchbase.com>
4
+ * Copyright:: 2018 Couchbase, Inc.
5
+ * License:: Apache License, Version 2.0
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the "License");
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ */
19
+
20
+ #include "jsonsl_ext.h"
21
+
22
+ VALUE jsl_mJSONSL;
23
+ VALUE jsl_eError;
24
+
25
+ void jsl_raise_at(jsonsl_error_t code, const char *message, const char *file, int line)
26
+ {
27
+ VALUE exc, str;
28
+
29
+ str = rb_str_new_cstr(message);
30
+ if (code > 0) {
31
+ rb_str_catf(str, ": (0x%02x) \"%s\"", (int)code, jsonsl_strerror(code));
32
+ }
33
+ rb_str_buf_cat_ascii(str, " [");
34
+ while (*file == '.' || *file == '/') {
35
+ file++;
36
+ }
37
+ rb_str_buf_cat_ascii(str, file);
38
+ rb_str_catf(str, ":%d]", line);
39
+ exc = rb_exc_new3(jsl_eError, str);
40
+ rb_ivar_set(exc, rb_intern("@code"), INT2FIX(code));
41
+ rb_exc_raise(exc);
42
+ }
43
+
44
+ static int jsl_jsonsl_error_callback(jsonsl_t jsn, jsonsl_error_t err, struct jsonsl_state_st *state, char *at)
45
+ {
46
+ char buf[30] = {0};
47
+ sprintf(buf, "error at %d position", (int)jsn->pos);
48
+ jsl_raise(err, buf);
49
+ (void)at;
50
+ (void)state;
51
+ return 0;
52
+ }
53
+
54
+ static void jsl_jsonsl_push_callback(jsonsl_t jsn, jsonsl_action_t action, struct jsonsl_state_st *state,
55
+ const jsonsl_char_t *at)
56
+ {
57
+ switch (state->type) {
58
+ case JSONSL_T_SPECIAL:
59
+ case JSONSL_T_STRING:
60
+ break;
61
+ case JSONSL_T_HKEY:
62
+ break;
63
+ case JSONSL_T_LIST:
64
+ state->val = rb_ary_new();
65
+ break;
66
+ case JSONSL_T_OBJECT:
67
+ state->val = rb_hash_new();
68
+ break;
69
+ default:
70
+ jsl_raise_msg("unexpected state type in POP callback");
71
+ break;
72
+ }
73
+ (void)at;
74
+ (void)jsn;
75
+ (void)action;
76
+ }
77
+
78
+ static void jsl_jsonsl_pop_callback(jsonsl_t jsn, jsonsl_action_t action, struct jsonsl_state_st *state,
79
+ const jsonsl_char_t *at)
80
+ {
81
+ struct jsonsl_state_st *last_state = jsonsl_last_state(jsn, state);
82
+ VALUE val = Qnil;
83
+
84
+ switch (state->type) {
85
+ case JSONSL_T_SPECIAL:
86
+ if (state->special_flags & JSONSL_SPECIALf_NUMNOINT) {
87
+ val = rb_float_new(strtod((char *)jsn->base + state->pos_begin, NULL));
88
+ } else if (state->special_flags & JSONSL_SPECIALf_NUMERIC) {
89
+ val = rb_cstr2inum((char *)jsn->base + state->pos_begin, 10);
90
+ } else if (state->special_flags & JSONSL_SPECIALf_TRUE) {
91
+ val = Qtrue;
92
+ } else if (state->special_flags & JSONSL_SPECIALf_FALSE) {
93
+ val = Qfalse;
94
+ } else if (state->special_flags & JSONSL_SPECIALf_NULL) {
95
+ val = Qnil;
96
+ } else {
97
+ jsl_raise_msg("invalid special value");
98
+ }
99
+ break;
100
+ case JSONSL_T_STRING:
101
+ val = rb_str_new((char *)jsn->base + state->pos_begin + 1, at - ((char *)jsn->base + state->pos_begin + 1));
102
+ break;
103
+ case JSONSL_T_HKEY:
104
+ val = rb_str_new((char *)jsn->base + state->pos_begin + 1, at - ((char *)jsn->base + state->pos_begin + 1));
105
+ break;
106
+ case JSONSL_T_LIST:
107
+ case JSONSL_T_OBJECT:
108
+ val = (VALUE)state->val;
109
+ break;
110
+ default:
111
+ jsl_raise_msg("unexpected state type in PUSH callback");
112
+ }
113
+ if (!last_state) {
114
+ jsn->data = (void *)val;
115
+ } else if (last_state->type == JSONSL_T_LIST) {
116
+ rb_ary_push(last_state->val, val);
117
+ } else if (last_state->type == JSONSL_T_OBJECT) {
118
+ Check_Type(last_state->val, T_HASH);
119
+ if (state->type == JSONSL_T_HKEY) {
120
+ last_state->pkey = val;
121
+ } else {
122
+ rb_hash_aset(last_state->val, last_state->pkey, val);
123
+ }
124
+ } else {
125
+ jsl_raise_msg("unable to add value to non container type");
126
+ }
127
+ (void)action;
128
+ }
129
+
130
+ static VALUE jsl_jsonsl_parse(int argc, VALUE *argv, VALUE self)
131
+ {
132
+ jsonsl_t jsn;
133
+ VALUE nlevels = Qnil, str = Qnil;
134
+
135
+ rb_scan_args(argc, argv, "11", &str, &nlevels);
136
+ Check_Type(str, T_STRING);
137
+ if (nlevels != Qnil) {
138
+ Check_Type(nlevels, T_FIXNUM);
139
+ jsn = jsonsl_new(FIX2INT(nlevels));
140
+ } else {
141
+ jsn = jsonsl_new(JSONSL_MAX_LEVELS);
142
+ }
143
+ jsonsl_reset(jsn);
144
+ jsn->data = (void *)Qnil;
145
+ jsonsl_enable_all_callbacks(jsn);
146
+ jsn->action_callback_PUSH = jsl_jsonsl_push_callback;
147
+ jsn->action_callback_POP = jsl_jsonsl_pop_callback;
148
+ jsn->error_callback = jsl_jsonsl_error_callback;
149
+ jsonsl_feed(jsn, RSTRING_PTR(str), RSTRING_LEN(str));
150
+ if (jsn->level != 0) {
151
+ jsl_raise_msg("unexpected end of data");
152
+ }
153
+ (void)self;
154
+ return (VALUE)jsn->data;
155
+ }
156
+
157
+ void Init_jsonsl_ext()
158
+ {
159
+ jsl_mJSONSL = rb_define_module("JSONSL");
160
+ rb_define_const(jsl_mJSONSL, "REVISION", rb_str_freeze(rb_str_new_cstr(JSONSL_REVISION)));
161
+ jsl_eError = rb_const_get(jsl_mJSONSL, rb_intern("Error"));
162
+ rb_define_singleton_method(jsl_mJSONSL, "parse", jsl_jsonsl_parse, -1);
163
+ jsl_row_parser_init();
164
+ }
@@ -0,0 +1,36 @@
1
+ /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Author:: Couchbase <info@couchbase.com>
4
+ * Copyright:: 2018 Couchbase, Inc.
5
+ * License:: Apache License, Version 2.0
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the "License");
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ */
19
+
20
+ #include <ruby.h>
21
+
22
+ #include "jsonsl.h"
23
+
24
+ #ifndef JSONSL_EXT_H
25
+ #define JSONSL_EXT_H
26
+
27
+ extern VALUE jsl_mJSONSL;
28
+ extern VALUE jsl_eError;
29
+
30
+ void jsl_raise_at(jsonsl_error_t code, const char *message, const char *file, int line);
31
+ #define jsl_raise(code, message) jsl_raise_at(code, message, __FILE__, __LINE__)
32
+ #define jsl_raise_msg(message) jsl_raise_at(0, message, __FILE__, __LINE__)
33
+
34
+ void jsl_row_parser_init();
35
+
36
+ #endif
@@ -0,0 +1,271 @@
1
+ /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Author:: Couchbase <info@couchbase.com>
4
+ * Copyright:: 2018 Couchbase, Inc.
5
+ * License:: Apache License, Version 2.0
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the "License");
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ */
19
+
20
+ #include "jsonsl_ext.h"
21
+
22
+ VALUE jsl_cRowParser;
23
+
24
+ ID jsl_id_call;
25
+ ID jsl_sym_root;
26
+ ID jsl_sym_rows;
27
+
28
+ typedef struct jsl_PARSER {
29
+ jsonsl_t jsn;
30
+ jsonsl_jpr_t ptr;
31
+ VALUE buffer;
32
+ VALUE proc;
33
+ VALUE last_key;
34
+ int initialized;
35
+ size_t last_row_endpos;
36
+ size_t header_len;
37
+ int rowcount;
38
+ } jsl_PARSER;
39
+
40
+ static void jsl_parser_mark(void *ptr)
41
+ {
42
+ jsl_PARSER *parser = ptr;
43
+ if (parser) {
44
+ rb_gc_mark_maybe(parser->buffer);
45
+ rb_gc_mark_maybe(parser->proc);
46
+ rb_gc_mark_maybe(parser->last_key);
47
+ }
48
+ }
49
+
50
+ static void jsl_parser_free(void *ptr)
51
+ {
52
+ jsl_PARSER *parser = ptr;
53
+ if (parser) {
54
+ if (parser->jsn) {
55
+ jsonsl_destroy(parser->jsn);
56
+ }
57
+ parser->jsn = NULL;
58
+ if (parser->ptr) {
59
+ jsonsl_jpr_destroy(parser->ptr);
60
+ }
61
+ parser->ptr = NULL;
62
+ ruby_xfree(parser);
63
+ }
64
+ }
65
+
66
+ static VALUE jsl_parser_alloc(VALUE klass)
67
+ {
68
+ VALUE obj;
69
+ jsl_PARSER *parser;
70
+
71
+ obj = Data_Make_Struct(klass, jsl_PARSER, jsl_parser_mark, jsl_parser_free, parser);
72
+ return obj;
73
+ }
74
+
75
+ static int jsl_parser_error_callback(jsonsl_t jsn, jsonsl_error_t err, struct jsonsl_state_st *state, char *at)
76
+ {
77
+ char buf[30] = {0};
78
+ sprintf(buf, "error at %d position", (int)jsn->pos);
79
+ jsl_raise(err, buf);
80
+ (void)at;
81
+ (void)state;
82
+ return 0;
83
+ }
84
+
85
+ static void jsl_parser_cover_push_callback(jsonsl_t jsn, jsonsl_action_t action, struct jsonsl_state_st *state,
86
+ const jsonsl_char_t *at)
87
+ {
88
+ jsl_PARSER *parser = (jsl_PARSER *)jsn->data;
89
+ parser->header_len = state->pos_begin;
90
+ jsn->action_callback_PUSH = NULL;
91
+ (void)action;
92
+ (void)at;
93
+ }
94
+
95
+ static void jsl_parser_reset(jsl_PARSER *parser)
96
+ {
97
+ if (parser) {
98
+ parser->buffer = Qnil;
99
+ parser->last_key = Qnil;
100
+ }
101
+ }
102
+
103
+ static void jsl_parser_cover_pop_callback(jsonsl_t jsn, jsonsl_action_t action, struct jsonsl_state_st *state,
104
+ const jsonsl_char_t *at)
105
+ {
106
+ jsl_PARSER *parser = (jsl_PARSER *)jsn->data;
107
+ VALUE cover;
108
+
109
+ if (state->val != jsl_sym_root) {
110
+ return;
111
+ }
112
+ cover = rb_str_new(RSTRING_PTR(parser->buffer), parser->header_len);
113
+ rb_str_cat(cover, RSTRING_PTR(parser->buffer) + parser->last_row_endpos,
114
+ RSTRING_LEN(parser->buffer) - parser->last_row_endpos);
115
+ rb_funcall(parser->proc, jsl_id_call, 1, cover);
116
+ jsl_parser_reset(parser);
117
+ (void)action;
118
+ (void)at;
119
+ }
120
+
121
+ static void jsl_parser_row_pop_callback(jsonsl_t jsn, jsonsl_action_t action, struct jsonsl_state_st *state,
122
+ const jsonsl_char_t *at)
123
+ {
124
+ jsl_PARSER *parser = (jsl_PARSER *)jsn->data;
125
+ parser->last_row_endpos = jsn->pos;
126
+
127
+ if (state->val == jsl_sym_rows) {
128
+ jsn->action_callback_POP = jsl_parser_cover_pop_callback;
129
+ jsn->action_callback_PUSH = NULL;
130
+ return;
131
+ }
132
+
133
+ const char *ptr = RSTRING_PTR(parser->buffer) + state->pos_begin;
134
+ size_t len = jsn->pos - state->pos_begin + 1;
135
+ if (state->type == JSONSL_T_SPECIAL) {
136
+ len--;
137
+ }
138
+ rb_funcall(parser->proc, jsl_id_call, 2, INT2FIX(parser->rowcount), rb_str_new(ptr, len));
139
+ parser->rowcount++;
140
+
141
+ (void)action;
142
+ (void)at;
143
+ }
144
+
145
+ static void jsl_parser_initial_push_callback(jsonsl_t jsn, jsonsl_action_t action, struct jsonsl_state_st *state,
146
+ const jsonsl_char_t *at)
147
+ {
148
+ jsl_PARSER *parser = (jsl_PARSER *)jsn->data;
149
+ jsonsl_jpr_match_t match = JSONSL_MATCH_UNKNOWN;
150
+ if (JSONSL_STATE_IS_CONTAINER(state)) {
151
+ jsonsl_jpr_match_state(jsn, state, RSTRING_PTR(parser->last_key), RSTRING_LEN(parser->last_key), &match);
152
+ }
153
+ if (parser->initialized == 0) {
154
+ if (state->type != JSONSL_T_OBJECT) {
155
+ jsl_raise_msg("expected root to be an object");
156
+ }
157
+ if (match != JSONSL_MATCH_POSSIBLE) {
158
+ jsl_raise_msg("root does not match JSON pointer");
159
+ }
160
+ state->val = jsl_sym_root;
161
+ parser->initialized = 1;
162
+ }
163
+
164
+ if (state->type == JSONSL_T_LIST && match == JSONSL_MATCH_POSSIBLE) {
165
+ state->val = jsl_sym_rows;
166
+ jsn->action_callback_POP = jsl_parser_row_pop_callback;
167
+ jsn->action_callback_PUSH = jsl_parser_cover_push_callback;
168
+ }
169
+ (void)action;
170
+ (void)at;
171
+ }
172
+
173
+ static void jsl_parser_initial_pop_callback(jsonsl_t jsn, jsonsl_action_t action, struct jsonsl_state_st *state,
174
+ const jsonsl_char_t *at)
175
+ {
176
+ jsl_PARSER *parser = (jsl_PARSER *)jsn->data;
177
+ if (state->type == JSONSL_T_HKEY) {
178
+ const char *key_str = RSTRING_PTR(parser->buffer) + state->pos_begin + 1;
179
+ size_t len = jsn->pos - state->pos_begin - 1;
180
+ parser->last_key = rb_str_new(key_str, len);
181
+ }
182
+ (void)action;
183
+ (void)at;
184
+ }
185
+
186
+ static VALUE jsl_parser_init(int argc, VALUE *argv, VALUE self)
187
+ {
188
+ jsl_PARSER *parser = DATA_PTR(self);
189
+ VALUE nlevels = Qnil;
190
+ VALUE jptr = Qnil;
191
+ VALUE proc = Qnil;
192
+ jsonsl_error_t rc = JSONSL_ERROR_SUCCESS;
193
+
194
+ rb_scan_args(argc, argv, "11&", &jptr, &nlevels, &proc);
195
+ if (proc == Qnil) {
196
+ rb_raise(rb_eArgError, "tried to create Parser object without a block");
197
+ }
198
+
199
+ Check_Type(jptr, T_STRING);
200
+ parser->ptr = jsonsl_jpr_new(RSTRING_PTR(jptr), &rc);
201
+ if (rc != JSONSL_ERROR_SUCCESS) {
202
+ jsl_raise(rc, "invalid JSON pointer");
203
+ }
204
+ if (nlevels != Qnil) {
205
+ Check_Type(nlevels, T_FIXNUM);
206
+ parser->jsn = jsonsl_new(FIX2INT(nlevels));
207
+ } else {
208
+ parser->jsn = jsonsl_new(JSONSL_MAX_LEVELS);
209
+ }
210
+ parser->initialized = 0;
211
+ parser->buffer = rb_str_buf_new(100);
212
+ parser->last_key = rb_str_new_cstr("");
213
+ parser->proc = proc;
214
+ parser->jsn->data = parser;
215
+ parser->jsn->max_callback_level = 4;
216
+ jsonsl_jpr_match_state_init(parser->jsn, &parser->ptr, 1);
217
+ jsonsl_reset(parser->jsn);
218
+ parser->jsn->error_callback = jsl_parser_error_callback;
219
+ parser->jsn->action_callback_PUSH = jsl_parser_initial_push_callback;
220
+ parser->jsn->action_callback_POP = jsl_parser_initial_pop_callback;
221
+ jsonsl_enable_all_callbacks(parser->jsn);
222
+ return self;
223
+ }
224
+
225
+ static VALUE jsl_parser_inspect(VALUE self)
226
+ {
227
+ jsl_PARSER *parser = DATA_PTR(self);
228
+ VALUE str;
229
+
230
+ str = rb_str_buf_new2("#<");
231
+ rb_str_buf_cat2(str, rb_obj_classname(self));
232
+ rb_str_catf(str, ":%p", (void *)self);
233
+ if (parser->buffer != Qnil) {
234
+ rb_str_catf(str, " buflen=%lu", (long int)RSTRING_LEN(parser->buffer));
235
+ }
236
+ if (parser->ptr && parser->ptr->orig) {
237
+ VALUE tmp = rb_inspect(rb_str_new_cstr(parser->ptr->orig));
238
+ rb_str_catf(str, " ptr=%s", RSTRING_PTR(tmp));
239
+ }
240
+ rb_str_buf_cat_ascii(str, ">");
241
+
242
+ return str;
243
+ }
244
+
245
+ static VALUE jsl_parser_feed(VALUE self, VALUE data)
246
+ {
247
+ jsl_PARSER *parser = DATA_PTR(self);
248
+ size_t old_len = RSTRING_LEN(parser->buffer);
249
+
250
+ if (NIL_P(parser->buffer)) {
251
+ jsl_raise_msg("unable to feed completed parser");
252
+ }
253
+ Check_Type(data, T_STRING);
254
+ rb_str_buf_append(parser->buffer, data);
255
+ jsonsl_feed(parser->jsn, RSTRING_PTR(parser->buffer) + old_len, RSTRING_LEN(data));
256
+
257
+ return self;
258
+ }
259
+
260
+ void jsl_row_parser_init()
261
+ {
262
+ jsl_id_call = rb_intern("call");
263
+ jsl_sym_root = ID2SYM(rb_intern("root"));
264
+ jsl_sym_rows = ID2SYM(rb_intern("row"));
265
+
266
+ jsl_cRowParser = rb_define_class_under(jsl_mJSONSL, "RowParser", rb_cObject);
267
+ rb_define_alloc_func(jsl_cRowParser, jsl_parser_alloc);
268
+ rb_define_method(jsl_cRowParser, "initialize", jsl_parser_init, -1);
269
+ rb_define_method(jsl_cRowParser, "inspect", jsl_parser_inspect, 0);
270
+ rb_define_method(jsl_cRowParser, "feed", jsl_parser_feed, 1);
271
+ }