Skip to content

Commit a733607

Browse files
committed
Update rebar.config
2 parents fa539da + 6f8b166 commit a733607

File tree

5 files changed

+542
-1
lines changed

5 files changed

+542
-1
lines changed

c_src/jstream.c

Lines changed: 367 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,367 @@
1+
// Copyright 2013 Yuriy Iskra <iskra.yw@gmail.com>
2+
3+
#include <string.h>
4+
#include <ctype.h>
5+
#include <assert.h>
6+
#include <errno.h>
7+
#include "erl_nif.h"
8+
#include "jsonx_str.h"
9+
10+
typedef struct{
11+
ERL_NIF_TERM am_true;
12+
ERL_NIF_TERM am_false;
13+
ERL_NIF_TERM am_ok;
14+
15+
ERL_NIF_TERM am_null;
16+
ERL_NIF_TERM am_start_map;
17+
ERL_NIF_TERM am_map_key;
18+
ERL_NIF_TERM am_end_map;
19+
ERL_NIF_TERM am_start_array;
20+
ERL_NIF_TERM am_end_array;
21+
ERL_NIF_TERM am_parse_buf;
22+
ERL_NIF_TERM am_parse_end;
23+
24+
ERL_NIF_TERM am_error;
25+
ERL_NIF_TERM am_erange;
26+
ERL_NIF_TERM am_estr;
27+
ERL_NIF_TERM am_esyntax;
28+
}PrivData;
29+
30+
#define ERROR 0
31+
#define START 1
32+
#define COMPLETTE 2
33+
#define COMMA 3
34+
#define KEY_COMPLETTE 4
35+
36+
typedef struct{
37+
ErlNifEnv *env;
38+
ErlNifBinary bin;
39+
unsigned char *cur;
40+
unsigned char *top;
41+
PrivData *priv;
42+
int m_state;
43+
}State;
44+
45+
ErlNifResourceType* stream_RSTYPE;
46+
47+
static void
48+
stream_rt_dtor(ErlNifEnv* env, void* obj){
49+
State *entry = (void*)obj;
50+
enif_release_binary(&entry->bin);
51+
entry->bin.data = NULL;
52+
entry->bin.size = 0;
53+
}
54+
55+
static int
56+
load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info){
57+
58+
PrivData *pdata = enif_alloc(sizeof(PrivData));
59+
if(pdata == NULL) return 1;
60+
61+
stream_RSTYPE = enif_open_resource_type(env, NULL,
62+
"stream_RSTYPE",
63+
stream_rt_dtor,
64+
ERL_NIF_RT_CREATE, NULL);
65+
if (stream_RSTYPE == NULL) return 1;
66+
67+
if(!enif_make_existing_atom(env, "true", &(pdata->am_true), ERL_NIF_LATIN1)) return 1;
68+
if(!enif_make_existing_atom(env, "false", &(pdata->am_false), ERL_NIF_LATIN1)) return 1;
69+
if(!enif_make_existing_atom(env, "ok", &(pdata->am_ok), ERL_NIF_LATIN1)) return 1;
70+
71+
if(!enif_make_existing_atom(env, "null", &(pdata->am_null), ERL_NIF_LATIN1)) return 1;
72+
if(!enif_make_existing_atom(env, "start_map", &(pdata->am_start_map), ERL_NIF_LATIN1)) return 1;
73+
if(!enif_make_existing_atom(env, "map_key", &(pdata->am_map_key), ERL_NIF_LATIN1)) return 1;
74+
if(!enif_make_existing_atom(env, "end_map", &(pdata->am_end_map), ERL_NIF_LATIN1)) return 1;
75+
if(!enif_make_existing_atom(env, "start_array", &(pdata->am_start_array), ERL_NIF_LATIN1)) return 1;
76+
if(!enif_make_existing_atom(env, "end_array", &(pdata->am_end_array), ERL_NIF_LATIN1)) return 1;
77+
if(!enif_make_existing_atom(env, "parse_buf", &(pdata->am_parse_buf), ERL_NIF_LATIN1)) return 1;
78+
if(!enif_make_existing_atom(env, "parse_end", &(pdata->am_parse_end), ERL_NIF_LATIN1)) return 1;
79+
80+
if(!enif_make_existing_atom(env, "error", &(pdata->am_error), ERL_NIF_LATIN1)) return 1;
81+
if(!enif_make_existing_atom(env, "big_num", &(pdata->am_erange), ERL_NIF_LATIN1)) return 1;
82+
if(!enif_make_existing_atom(env, "invalid_string", &(pdata->am_estr), ERL_NIF_LATIN1)) return 1;
83+
if(!enif_make_existing_atom(env, "invalid_json", &(pdata->am_esyntax), ERL_NIF_LATIN1)) return 1;
84+
85+
*priv_data = (void*)pdata;
86+
87+
return 0;
88+
}
89+
90+
static int
91+
reload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info){
92+
return 0;
93+
}
94+
95+
static int
96+
upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info){
97+
return 0;
98+
}
99+
static void
100+
unload(ErlNifEnv* env, void* priv_data){
101+
return;
102+
}
103+
104+
105+
static inline unsigned char
106+
look_ah(State *st){
107+
while(isspace(*st->cur))
108+
st->cur++;
109+
return *(st->cur);
110+
}
111+
112+
static inline ERL_NIF_TERM
113+
make_error(State* st, ERL_NIF_TERM resume){
114+
st->m_state = ERROR;
115+
*st->top = 'e';
116+
return enif_make_tuple2(st->env, st->priv->am_error, resume);
117+
}
118+
119+
static inline ERL_NIF_TERM
120+
parse_string(State* st){
121+
unsigned char *endptr;
122+
unsigned char *endstr;
123+
unsigned char *dst;
124+
ERL_NIF_TERM ret;
125+
if(check_noescaped_jstr(st->cur, &endptr)){
126+
if(*endptr == '"'){
127+
dst = enif_make_new_binary(st->env, endptr - st->cur - 1, &ret);
128+
memcpy(dst, st->cur + 1, endptr - st->cur - 1);
129+
st->cur = endptr + 1;
130+
return ret;
131+
}else if(*endptr == '\\'){
132+
if(check_with_unescape_jstr(endptr, &endstr, &endptr)){
133+
dst = enif_make_new_binary(st->env, endstr - st->cur - 1, &ret);
134+
memcpy(dst, st->cur + 1, endstr - st->cur - 1);
135+
st->cur = endptr + 1;
136+
return ret;
137+
}
138+
}
139+
}
140+
return make_error(st, st->priv->am_estr);
141+
}
142+
143+
static inline ERL_NIF_TERM
144+
parse_number(State *st){
145+
long long int_num;
146+
double float_num;
147+
char *endptr;
148+
errno = 0;
149+
150+
int_num = strtoll((char *)st->cur, &endptr, 10);
151+
if((char*)st->cur == endptr){
152+
return (ERL_NIF_TERM)0;
153+
}else if(errno == ERANGE){
154+
return make_error(st, st->priv->am_erange);
155+
}
156+
157+
if(*endptr == '.' || *endptr == 'e' || *endptr == 'E'){
158+
float_num = strtod((char *)st->cur, &endptr);
159+
if(errno != ERANGE){
160+
st->cur = (unsigned char*)endptr;
161+
return enif_make_double(st->env, float_num);
162+
}
163+
else{
164+
return make_error(st, st->priv->am_erange);
165+
}
166+
}
167+
else{
168+
st->cur = (unsigned char*)endptr;
169+
return enif_make_int64(st->env, int_num);
170+
}
171+
}
172+
173+
static inline ERL_NIF_TERM
174+
parse_true(State* st){
175+
if(!(strncmp("rue", (char*)(++st->cur), 3))){
176+
st->cur = st->cur + 3;
177+
return st->priv->am_true;
178+
}
179+
return make_error(st, st->priv->am_esyntax);
180+
}
181+
182+
static inline ERL_NIF_TERM
183+
parse_false(State* st){
184+
if(!(strncmp("alse", (char*)(++st->cur), 4))){
185+
st->cur = st->cur + 4;
186+
return st->priv->am_false;
187+
}
188+
return make_error(st, st->priv->am_esyntax);
189+
}
190+
191+
static inline ERL_NIF_TERM
192+
parse_null(State* st){
193+
if(!(strncmp("ull", (char*)(++st->cur), 3))){
194+
st->cur = st->cur + 3;
195+
return st->priv->am_null;
196+
}
197+
return make_error(st, st->priv->am_esyntax);
198+
}
199+
200+
201+
static inline ERL_NIF_TERM
202+
parse_key(State *st){
203+
ERL_NIF_TERM key;
204+
switch(look_ah(st)){
205+
case '\"' :
206+
key = parse_string(st);
207+
if(st->m_state == ERROR)
208+
return key;
209+
if(look_ah(st) == ':'){
210+
st->m_state = KEY_COMPLETTE;
211+
st->cur++;
212+
return enif_make_tuple2(st->env, st->priv->am_map_key, key);
213+
}
214+
case '\0' :
215+
return st->priv->am_parse_buf;
216+
default :
217+
return make_error(st, st->priv->am_esyntax);
218+
}
219+
}
220+
221+
static inline ERL_NIF_TERM
222+
parse0(State *st){
223+
switch(look_ah(st)){
224+
case '\"' : st->m_state = COMPLETTE; return parse_string(st);
225+
case 't' : st->m_state = COMPLETTE; return parse_true(st);
226+
case 'f' : st->m_state = COMPLETTE; return parse_false(st);
227+
case 'n' : st->m_state = COMPLETTE; return parse_null(st);
228+
case '-' : case '0' : case '1' : case '2' :
229+
case '3' : case '4' : case '5' : case '6' :
230+
case '7' : case '8' : case '9' :
231+
st->m_state = COMPLETTE; return parse_number(st);
232+
case '[' :
233+
st->m_state = START;
234+
*(++st->top) = '['; st->cur++;
235+
return st->priv->am_start_array;
236+
case '{' :
237+
st->m_state = START;
238+
*(++st->top) = '{'; st->cur++;
239+
return st->priv->am_start_map;
240+
case '\0' :
241+
return st->priv->am_parse_buf;
242+
default:
243+
st->m_state = ERROR;
244+
*(st->top) = 'e';
245+
return make_error(st, st->priv->am_esyntax);
246+
}
247+
}
248+
249+
ERL_NIF_TERM
250+
get_event_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]){
251+
State *st;
252+
assert(enif_get_resource(env, argv[0], stream_RSTYPE, (void**)&st));
253+
switch(*st->top){
254+
case '[' :
255+
if(st->m_state == COMPLETTE){
256+
switch(look_ah(st)){
257+
case ',' : st->m_state = COMMA; st->cur++; return parse0(st);
258+
case '\0': st->cur++; return st->priv->am_parse_buf;
259+
case ']' : st->m_state = COMPLETTE; st->cur++; st->top--; return st->priv->am_end_array;
260+
}
261+
}else if(st->m_state == COMMA){
262+
return parse0(st);
263+
}else if(st->m_state == START){
264+
switch(look_ah(st)){
265+
case '\0': st->cur++; return st->priv->am_parse_buf;
266+
case ']' : st->m_state = COMPLETTE; st->cur++; st->top--; return st->priv->am_end_array;
267+
default: return parse0(st);
268+
}
269+
}
270+
break;
271+
case '{' :
272+
if(st->m_state == COMPLETTE){
273+
switch(look_ah(st)){
274+
case ',' : st->m_state = COMMA; st->cur++; return parse_key(st);
275+
case '}' : st->m_state = COMPLETTE; st->cur++; st->top--; return st->priv->am_end_map;
276+
case '\0': st->cur++; return st->priv->am_parse_buf;
277+
}
278+
}else if(st->m_state == KEY_COMPLETTE){
279+
return parse0(st);
280+
}else if(st->m_state == COMMA){
281+
return parse_key(st);
282+
}else if(st->m_state == START){
283+
switch(look_ah(st)){
284+
case '\0': st->cur++; return st->priv->am_parse_buf;
285+
case '}' : st->m_state = COMPLETTE; st->cur++; st->top--; return st->priv->am_end_map;
286+
default: return parse_key(st);
287+
}
288+
}
289+
break;
290+
case '\0':
291+
if(st->m_state == COMPLETTE){
292+
ERL_NIF_TERM rest;
293+
look_ah(st);
294+
size_t size = strlen((char*)st->cur);
295+
unsigned char *nb = enif_make_new_binary(env, size, &rest);
296+
memcpy(nb, st->cur, size);
297+
return enif_make_tuple2(env, st->priv->am_parse_end, rest);
298+
return st->priv->am_parse_end;
299+
}else{
300+
return parse0(st);
301+
}
302+
break;
303+
case 'e':
304+
default :
305+
break;
306+
}
307+
return make_error(st, st->priv->am_esyntax);
308+
}
309+
310+
ERL_NIF_TERM
311+
update_decoder_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]){
312+
State *st;
313+
ErlNifBinary input;
314+
if(!enif_inspect_binary(env, argv[1], &input)){
315+
return enif_make_badarg(env);
316+
}
317+
assert(enif_get_resource(env, argv[0], stream_RSTYPE, (void**)&st));
318+
size_t stack_size = (st->top + 1 - st->bin.data);
319+
320+
size_t free = st->bin.size - stack_size - sizeof(ERL_NIF_TERM);
321+
if(input.size > free){
322+
enif_realloc_binary(&st->bin, input.size + stack_size + sizeof(ERL_NIF_TERM));
323+
st->top = st->bin.data + stack_size - 1;
324+
st->cur = st->top + 1;
325+
memcpy(st->cur, input.data, input.size);
326+
*((ERL_NIF_TERM*)(st->cur + input.size)) = 0U;
327+
}else{
328+
st->cur = st->top + 1;
329+
memcpy(st->cur, input.data, input.size);
330+
*((ERL_NIF_TERM*)(st->cur + input.size)) = 0U;
331+
}
332+
return st->priv->am_ok;
333+
}
334+
335+
ERL_NIF_TERM
336+
make_stream_resource_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]){
337+
ErlNifBinary input;
338+
if(!enif_inspect_binary(env, argv[0], &input)){
339+
return enif_make_badarg(env);
340+
}
341+
size_t alloc_size = input.size + 2 * sizeof(ERL_NIF_TERM);
342+
State *st = (State*)enif_alloc_resource(stream_RSTYPE, sizeof(State));
343+
st->env = env;
344+
st->priv = (PrivData*)enif_priv_data(env);
345+
st->m_state = START;
346+
347+
enif_alloc_binary(alloc_size , &st->bin);
348+
st->cur = st->bin.data + sizeof(ERL_NIF_TERM);
349+
memcpy(st->cur, input.data, input.size);
350+
*((ERL_NIF_TERM*)st->bin.data) = 0U;
351+
*((ERL_NIF_TERM*)(st->bin.data + input.size + sizeof(ERL_NIF_TERM))) = 0U;
352+
st->top = st->cur - 1;
353+
354+
ERL_NIF_TERM ret = enif_make_resource(env, (void *)st);
355+
enif_release_resource(st);
356+
return ret;
357+
}
358+
359+
static ErlNifFunc
360+
nif_funcs[] = {
361+
{"new_decoder", 1, make_stream_resource_nif},
362+
{"update_decoder", 2, update_decoder_nif},
363+
{"get_event", 1, get_event_nif}
364+
};
365+
366+
ERL_NIF_INIT(jstream, nif_funcs, load, reload, upgrade, unload);
367+

rebar.config

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
{port_specs, [
2222
{"priv/jsonx.so", ["c_src/jsonx.c", "c_src/decoder.c", "c_src/encoder.c"]}
23+
,{"priv/jstream.so",["c_src/jstream.c"]}
2324
]}.
2425

2526
{port_env, [

src/jsonx.app.src

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
{application, jsonx,
44
[
55
{description, "JSON library for Erlang writen in C"},
6-
{vsn, "2.0"},
6+
{vsn, "3.0"},
77
{applications, [
88
kernel,
99
stdlib

0 commit comments

Comments
 (0)