oj 3.7.5 → 3.7.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/oj/buf.h +4 -4
- data/ext/oj/cache8.c +3 -3
- data/ext/oj/cache8.h +4 -4
- data/ext/oj/circarray.c +1 -1
- data/ext/oj/circarray.h +4 -4
- data/ext/oj/code.h +6 -6
- data/ext/oj/compat.c +5 -5
- data/ext/oj/custom.c +15 -13
- data/ext/oj/dump.c +15 -5
- data/ext/oj/dump.h +3 -3
- data/ext/oj/dump_compat.c +15 -11
- data/ext/oj/dump_leaf.c +1 -1
- data/ext/oj/dump_object.c +4 -2
- data/ext/oj/encode.h +3 -3
- data/ext/oj/err.c +1 -1
- data/ext/oj/err.h +5 -5
- data/ext/oj/fast.c +14 -14
- data/ext/oj/hash.c +7 -7
- data/ext/oj/hash.h +4 -4
- data/ext/oj/hash_test.c +2 -2
- data/ext/oj/mimic_json.c +9 -9
- data/ext/oj/object.c +3 -3
- data/ext/oj/odd.c +12 -8
- data/ext/oj/odd.h +5 -5
- data/ext/oj/oj.c +14 -12
- data/ext/oj/oj.h +23 -23
- data/ext/oj/parse.c +3 -3
- data/ext/oj/parse.h +26 -26
- data/ext/oj/rails.c +27 -23
- data/ext/oj/rails.h +3 -3
- data/ext/oj/reader.h +5 -5
- data/ext/oj/resolve.h +3 -3
- data/ext/oj/rxclass.c +5 -5
- data/ext/oj/rxclass.h +7 -7
- data/ext/oj/saj.c +2 -2
- data/ext/oj/scp.c +3 -3
- data/ext/oj/sparse.c +4 -4
- data/ext/oj/stream_writer.c +1 -1
- data/ext/oj/strict.c +6 -6
- data/ext/oj/string_writer.c +1 -1
- data/ext/oj/trace.h +8 -8
- data/ext/oj/val_stack.c +8 -2
- data/ext/oj/val_stack.h +9 -9
- data/ext/oj/wab.c +11 -7
- data/lib/oj/version.rb +1 -1
- data/test/bug.rb +51 -0
- data/test/bug2.rb +10 -0
- data/test/bug3.rb +46 -0
- data/test/bug_fast.rb +32 -0
- data/test/bug_load.rb +24 -0
- data/test/crash.rb +111 -0
- data/test/example.rb +11 -0
- data/test/foo.rb +4 -29
- data/test/io.rb +48 -0
- data/test/isolated/test_mimic_rails_datetime.rb +27 -0
- data/test/mem.rb +12 -27
- data/test/mod.rb +16 -0
- data/test/omit.rb +20 -0
- data/test/rails.rb +50 -0
- data/test/rails_datetime_test.rb +24 -0
- data/test/russian.rb +18 -0
- data/test/struct.rb +29 -0
- data/test/test_serializer.rb +59 -0
- data/test/write_timebars.rb +31 -0
- data/test/x_test.rb +185 -0
- metadata +102 -68
- data/test/big.rb +0 -15
data/ext/oj/rxclass.c
CHANGED
@@ -14,8 +14,8 @@
|
|
14
14
|
|
15
15
|
#include "rxclass.h"
|
16
16
|
|
17
|
-
typedef struct
|
18
|
-
struct
|
17
|
+
typedef struct _rxC {
|
18
|
+
struct _rxC *next;
|
19
19
|
VALUE rrx;
|
20
20
|
#if !IS_WINDOWS
|
21
21
|
regex_t rx;
|
@@ -48,9 +48,9 @@ oj_rxclass_cleanup(RxClass rc) {
|
|
48
48
|
|
49
49
|
void
|
50
50
|
oj_rxclass_rappend(RxClass rc, VALUE rx, VALUE clas) {
|
51
|
-
RxC rxc = ALLOC_N(struct
|
51
|
+
RxC rxc = ALLOC_N(struct _rxC, 1);
|
52
52
|
|
53
|
-
memset(rxc, 0, sizeof(struct
|
53
|
+
memset(rxc, 0, sizeof(struct _rxC));
|
54
54
|
rxc->rrx = rx;
|
55
55
|
rxc->clas = clas;
|
56
56
|
if (NULL == rc->tail) {
|
@@ -73,7 +73,7 @@ oj_rxclass_append(RxClass rc, const char *expr, VALUE clas) {
|
|
73
73
|
snprintf(rc->err, sizeof(rc->err), "expressions must be less than %lu characters", (unsigned long)sizeof(rxc->src));
|
74
74
|
return EINVAL;
|
75
75
|
}
|
76
|
-
rxc = ALLOC_N(struct
|
76
|
+
rxc = ALLOC_N(struct _rxC, 1);
|
77
77
|
rxc->next = 0;
|
78
78
|
rxc->clas = clas;
|
79
79
|
|
data/ext/oj/rxclass.h
CHANGED
@@ -3,17 +3,17 @@
|
|
3
3
|
* All rights reserved.
|
4
4
|
*/
|
5
5
|
|
6
|
-
#ifndef
|
7
|
-
#define
|
6
|
+
#ifndef OJ_RXCLASS_H
|
7
|
+
#define OJ_RXCLASS_H
|
8
8
|
|
9
9
|
#include <stdbool.h>
|
10
10
|
#include "ruby.h"
|
11
11
|
|
12
|
-
struct
|
12
|
+
struct _rxC;
|
13
13
|
|
14
|
-
typedef struct
|
15
|
-
struct
|
16
|
-
struct
|
14
|
+
typedef struct _rxClass {
|
15
|
+
struct _rxC *head;
|
16
|
+
struct _rxC *tail;
|
17
17
|
char err[128];
|
18
18
|
} *RxClass;
|
19
19
|
|
@@ -24,4 +24,4 @@ extern VALUE oj_rxclass_match(RxClass rc, const char *str, int len);
|
|
24
24
|
extern void oj_rxclass_copy(RxClass src, RxClass dest);
|
25
25
|
extern void oj_rxclass_rappend(RxClass rc, VALUE rx, VALUE clas);
|
26
26
|
|
27
|
-
#endif /*
|
27
|
+
#endif /* OJ_RXCLASS_H */
|
data/ext/oj/saj.c
CHANGED
@@ -19,7 +19,7 @@
|
|
19
19
|
#include "oj.h"
|
20
20
|
#include "encode.h"
|
21
21
|
|
22
|
-
typedef struct
|
22
|
+
typedef struct _parseInfo {
|
23
23
|
char *str; /* buffer being read from */
|
24
24
|
char *s; /* current position in buffer */
|
25
25
|
void *stack_min;
|
@@ -605,7 +605,7 @@ read_quoted_value(ParseInfo pi) {
|
|
605
605
|
static void
|
606
606
|
saj_parse(VALUE handler, char *json) {
|
607
607
|
volatile VALUE obj = Qnil;
|
608
|
-
struct
|
608
|
+
struct _parseInfo pi;
|
609
609
|
|
610
610
|
if (0 == json) {
|
611
611
|
if (pi.has_error) {
|
data/ext/oj/scp.c
CHANGED
@@ -36,7 +36,7 @@ noop_add_num(ParseInfo pi, NumInfo ni) {
|
|
36
36
|
}
|
37
37
|
|
38
38
|
static VALUE
|
39
|
-
noop_hash_key(
|
39
|
+
noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
|
40
40
|
return Qundef;
|
41
41
|
}
|
42
42
|
|
@@ -117,7 +117,7 @@ calc_hash_key(ParseInfo pi, Val kval) {
|
|
117
117
|
}
|
118
118
|
|
119
119
|
static VALUE
|
120
|
-
hash_key(
|
120
|
+
hash_key(ParseInfo pi, const char *key, size_t klen) {
|
121
121
|
return rb_funcall(pi->handler, oj_hash_key_id, 1, rb_str_new(key, klen));
|
122
122
|
}
|
123
123
|
|
@@ -159,7 +159,7 @@ array_append_value(ParseInfo pi, VALUE value) {
|
|
159
159
|
|
160
160
|
VALUE
|
161
161
|
oj_sc_parse(int argc, VALUE *argv, VALUE self) {
|
162
|
-
struct
|
162
|
+
struct _parseInfo pi;
|
163
163
|
VALUE input = argv[1];
|
164
164
|
|
165
165
|
parse_info_init(&pi);
|
data/ext/oj/sparse.c
CHANGED
@@ -203,7 +203,7 @@ unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) {
|
|
203
203
|
// entered at backslash
|
204
204
|
static void
|
205
205
|
read_escaped_str(ParseInfo pi) {
|
206
|
-
struct
|
206
|
+
struct _buf buf;
|
207
207
|
char c;
|
208
208
|
uint32_t code;
|
209
209
|
Val parent = stack_peek(&pi->stack);
|
@@ -393,7 +393,7 @@ read_str(ParseInfo pi) {
|
|
393
393
|
|
394
394
|
static void
|
395
395
|
read_num(ParseInfo pi) {
|
396
|
-
struct
|
396
|
+
struct _numInfo ni;
|
397
397
|
char c;
|
398
398
|
|
399
399
|
reader_protect(&pi->rd);
|
@@ -525,7 +525,7 @@ read_num(ParseInfo pi) {
|
|
525
525
|
|
526
526
|
static void
|
527
527
|
read_nan(ParseInfo pi) {
|
528
|
-
struct
|
528
|
+
struct _numInfo ni;
|
529
529
|
char c;
|
530
530
|
|
531
531
|
ni.str = pi->rd.str;
|
@@ -718,7 +718,7 @@ oj_sparse2(ParseInfo pi) {
|
|
718
718
|
return;
|
719
719
|
}
|
720
720
|
} else if ('a' == c) {
|
721
|
-
struct
|
721
|
+
struct _numInfo ni;
|
722
722
|
|
723
723
|
c = reader_get(&pi->rd);
|
724
724
|
if ('N' != c && 'n' != c) {
|
data/ext/oj/stream_writer.c
CHANGED
@@ -94,7 +94,7 @@ stream_writer_new(int argc, VALUE *argv, VALUE self) {
|
|
94
94
|
} else {
|
95
95
|
rb_raise(rb_eArgError, "expected an IO Object.");
|
96
96
|
}
|
97
|
-
sw = ALLOC(struct
|
97
|
+
sw = ALLOC(struct _streamWriter);
|
98
98
|
if (2 == argc && T_HASH == rb_type(argv[1])) {
|
99
99
|
volatile VALUE v;
|
100
100
|
int buf_size = 0;
|
data/ext/oj/strict.c
CHANGED
@@ -15,21 +15,21 @@
|
|
15
15
|
#include "trace.h"
|
16
16
|
|
17
17
|
static void
|
18
|
-
hash_end(
|
18
|
+
hash_end(ParseInfo pi) {
|
19
19
|
if (Yes == pi->options.trace) {
|
20
20
|
oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
|
21
21
|
}
|
22
22
|
}
|
23
23
|
|
24
24
|
static void
|
25
|
-
array_end(
|
25
|
+
array_end(ParseInfo pi) {
|
26
26
|
if (Yes == pi->options.trace) {
|
27
27
|
oj_trace_parse_array_end(pi, __FILE__, __LINE__);
|
28
28
|
}
|
29
29
|
}
|
30
30
|
|
31
31
|
static VALUE
|
32
|
-
noop_hash_key(
|
32
|
+
noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
|
33
33
|
return Qundef;
|
34
34
|
}
|
35
35
|
|
@@ -100,7 +100,7 @@ hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char
|
|
100
100
|
}
|
101
101
|
|
102
102
|
static void
|
103
|
-
hash_set_num(
|
103
|
+
hash_set_num(ParseInfo pi, Val parent, NumInfo ni) {
|
104
104
|
volatile VALUE v;
|
105
105
|
|
106
106
|
if (ni->infinity || ni->nan) {
|
@@ -183,7 +183,7 @@ oj_set_strict_callbacks(ParseInfo pi) {
|
|
183
183
|
|
184
184
|
VALUE
|
185
185
|
oj_strict_parse(int argc, VALUE *argv, VALUE self) {
|
186
|
-
struct
|
186
|
+
struct _parseInfo pi;
|
187
187
|
|
188
188
|
parse_info_init(&pi);
|
189
189
|
pi.options = oj_default_options;
|
@@ -200,7 +200,7 @@ oj_strict_parse(int argc, VALUE *argv, VALUE self) {
|
|
200
200
|
|
201
201
|
VALUE
|
202
202
|
oj_strict_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
|
203
|
-
struct
|
203
|
+
struct _parseInfo pi;
|
204
204
|
|
205
205
|
parse_info_init(&pi);
|
206
206
|
pi.options = oj_default_options;
|
data/ext/oj/string_writer.c
CHANGED
@@ -272,7 +272,7 @@ str_writer_free(void *ptr) {
|
|
272
272
|
*/
|
273
273
|
static VALUE
|
274
274
|
str_writer_new(int argc, VALUE *argv, VALUE self) {
|
275
|
-
StrWriter sw = ALLOC(struct
|
275
|
+
StrWriter sw = ALLOC(struct _strWriter);
|
276
276
|
|
277
277
|
oj_str_writer_init(sw, 0);
|
278
278
|
if (1 == argc) {
|
data/ext/oj/trace.h
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
* All rights reserved.
|
4
4
|
*/
|
5
5
|
|
6
|
-
#ifndef
|
7
|
-
#define
|
6
|
+
#ifndef OJ_TRACE_H
|
7
|
+
#define OJ_TRACE_H
|
8
8
|
|
9
9
|
#include <stdbool.h>
|
10
10
|
#include <ruby.h>
|
@@ -17,12 +17,12 @@ typedef enum {
|
|
17
17
|
TraceRubyOut = '<',
|
18
18
|
} TraceWhere;
|
19
19
|
|
20
|
-
struct
|
20
|
+
struct _parseInfo;
|
21
21
|
|
22
22
|
extern void oj_trace(const char *func, VALUE obj, const char *file, int line, int depth, TraceWhere where);
|
23
|
-
extern void oj_trace_parse_in(const char *func, struct
|
24
|
-
extern void oj_trace_parse_call(const char *func, struct
|
25
|
-
extern void oj_trace_parse_hash_end(struct
|
26
|
-
extern void oj_trace_parse_array_end(struct
|
23
|
+
extern void oj_trace_parse_in(const char *func, struct _parseInfo *pi, const char *file, int line);
|
24
|
+
extern void oj_trace_parse_call(const char *func, struct _parseInfo *pi, const char *file, int line, VALUE obj);
|
25
|
+
extern void oj_trace_parse_hash_end(struct _parseInfo *pi, const char *file, int line);
|
26
|
+
extern void oj_trace_parse_array_end(struct _parseInfo *pi, const char *file, int line);
|
27
27
|
|
28
|
-
#endif /*
|
28
|
+
#endif /* OJ_TRACE_H */
|
data/ext/oj/val_stack.c
CHANGED
@@ -28,6 +28,8 @@
|
|
28
28
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
29
|
*/
|
30
30
|
|
31
|
+
#include <string.h>
|
32
|
+
|
31
33
|
#include "oj.h"
|
32
34
|
#include "val_stack.h"
|
33
35
|
|
@@ -63,12 +65,16 @@ mark(void *ptr) {
|
|
63
65
|
VALUE
|
64
66
|
oj_stack_init(ValStack stack) {
|
65
67
|
#if HAVE_LIBPTHREAD
|
66
|
-
|
68
|
+
int err;
|
69
|
+
|
70
|
+
if (0 != (err = pthread_mutex_init(&stack->mutex, 0))) {
|
71
|
+
rb_raise(rb_eException, "failed to initialize a mutex. %s", strerror(err));
|
72
|
+
}
|
67
73
|
#else
|
68
74
|
stack->mutex = rb_mutex_new();
|
69
75
|
#endif
|
70
76
|
stack->head = stack->base;
|
71
|
-
stack->end = stack->base + sizeof(stack->base) / sizeof(struct
|
77
|
+
stack->end = stack->base + sizeof(stack->base) / sizeof(struct _val);
|
72
78
|
stack->tail = stack->head;
|
73
79
|
stack->head->val = Qundef;
|
74
80
|
stack->head->key = 0;
|
data/ext/oj/val_stack.h
CHANGED
@@ -28,8 +28,8 @@
|
|
28
28
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
29
|
*/
|
30
30
|
|
31
|
-
#ifndef
|
32
|
-
#define
|
31
|
+
#ifndef OJ_VAL_STACK_H
|
32
|
+
#define OJ_VAL_STACK_H
|
33
33
|
|
34
34
|
#include "ruby.h"
|
35
35
|
#include "odd.h"
|
@@ -52,7 +52,7 @@ typedef enum {
|
|
52
52
|
NEXT_HASH_COMMA = 'n',
|
53
53
|
} ValNext;
|
54
54
|
|
55
|
-
typedef struct
|
55
|
+
typedef struct _val {
|
56
56
|
volatile VALUE val;
|
57
57
|
const char *key;
|
58
58
|
char karray[32];
|
@@ -71,8 +71,8 @@ typedef struct _Val {
|
|
71
71
|
char kalloc;
|
72
72
|
} *Val;
|
73
73
|
|
74
|
-
typedef struct
|
75
|
-
struct
|
74
|
+
typedef struct _valStack {
|
75
|
+
struct _val base[STACK_INC];
|
76
76
|
Val head; // current stack
|
77
77
|
Val end; // stack end
|
78
78
|
Val tail; // pointer to one past last element name on stack
|
@@ -109,10 +109,10 @@ stack_push(ValStack stack, VALUE val, ValNext next) {
|
|
109
109
|
// A realloc can trigger a GC so make sure it happens outside the lock
|
110
110
|
// but lock before changing pointers.
|
111
111
|
if (stack->base == stack->head) {
|
112
|
-
head = ALLOC_N(struct
|
113
|
-
memcpy(head, stack->base, sizeof(struct
|
112
|
+
head = ALLOC_N(struct _val, len + STACK_INC);
|
113
|
+
memcpy(head, stack->base, sizeof(struct _val) * len);
|
114
114
|
} else {
|
115
|
-
REALLOC_N(head, struct
|
115
|
+
REALLOC_N(head, struct _val, len + STACK_INC);
|
116
116
|
}
|
117
117
|
#if HAVE_LIBPTHREAD
|
118
118
|
pthread_mutex_lock(&stack->mutex);
|
@@ -185,4 +185,4 @@ stack_pop(ValStack stack) {
|
|
185
185
|
|
186
186
|
extern const char* oj_stack_next_string(ValNext n);
|
187
187
|
|
188
|
-
#endif /*
|
188
|
+
#endif /* OJ_VAL_STACK_H */
|
data/ext/oj/wab.c
CHANGED
@@ -200,10 +200,14 @@ dump_time(VALUE obj, Out out) {
|
|
200
200
|
long long nsec;
|
201
201
|
|
202
202
|
#ifdef HAVE_RB_TIME_TIMESPEC
|
203
|
-
{
|
203
|
+
if (16 <= sizeof(struct timespec)) {
|
204
204
|
struct timespec ts = rb_time_timespec(obj);
|
205
|
+
|
205
206
|
sec = ts.tv_sec;
|
206
207
|
nsec = ts.tv_nsec;
|
208
|
+
} else {
|
209
|
+
sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
210
|
+
nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
207
211
|
}
|
208
212
|
#else
|
209
213
|
sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
@@ -291,21 +295,21 @@ oj_dump_wab_val(VALUE obj, int depth, Out out) {
|
|
291
295
|
///// load functions /////
|
292
296
|
|
293
297
|
static void
|
294
|
-
hash_end(
|
298
|
+
hash_end(ParseInfo pi) {
|
295
299
|
if (Yes == pi->options.trace) {
|
296
300
|
oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
|
297
301
|
}
|
298
302
|
}
|
299
303
|
|
300
304
|
static void
|
301
|
-
array_end(
|
305
|
+
array_end(ParseInfo pi) {
|
302
306
|
if (Yes == pi->options.trace) {
|
303
307
|
oj_trace_parse_array_end(pi, __FILE__, __LINE__);
|
304
308
|
}
|
305
309
|
}
|
306
310
|
|
307
311
|
static VALUE
|
308
|
-
noop_hash_key(
|
312
|
+
noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
|
309
313
|
return Qundef;
|
310
314
|
}
|
311
315
|
|
@@ -516,7 +520,7 @@ hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char
|
|
516
520
|
}
|
517
521
|
|
518
522
|
static void
|
519
|
-
hash_set_num(
|
523
|
+
hash_set_num(ParseInfo pi, Val parent, NumInfo ni) {
|
520
524
|
volatile VALUE rval = Qnil;
|
521
525
|
|
522
526
|
if (ni->infinity || ni->nan) {
|
@@ -598,7 +602,7 @@ oj_set_wab_callbacks(ParseInfo pi) {
|
|
598
602
|
|
599
603
|
VALUE
|
600
604
|
oj_wab_parse(int argc, VALUE *argv, VALUE self) {
|
601
|
-
struct
|
605
|
+
struct _parseInfo pi;
|
602
606
|
|
603
607
|
parse_info_init(&pi);
|
604
608
|
pi.options = oj_default_options;
|
@@ -615,7 +619,7 @@ oj_wab_parse(int argc, VALUE *argv, VALUE self) {
|
|
615
619
|
|
616
620
|
VALUE
|
617
621
|
oj_wab_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
|
618
|
-
struct
|
622
|
+
struct _parseInfo pi;
|
619
623
|
|
620
624
|
parse_info_init(&pi);
|
621
625
|
pi.options = oj_default_options;
|
data/lib/oj/version.rb
CHANGED
data/test/bug.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
$: << File.dirname(__FILE__)
|
5
|
+
|
6
|
+
require 'helper'
|
7
|
+
|
8
|
+
class Handler
|
9
|
+
def initialize
|
10
|
+
@state = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def hash_start
|
14
|
+
@state << {}
|
15
|
+
@state.last
|
16
|
+
end
|
17
|
+
|
18
|
+
def hash_end
|
19
|
+
@state.pop
|
20
|
+
end
|
21
|
+
|
22
|
+
def hash_set(h,k,v)
|
23
|
+
h.store(k,v)
|
24
|
+
end
|
25
|
+
|
26
|
+
def array_start
|
27
|
+
@state << []
|
28
|
+
@state.last
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
def array_end
|
33
|
+
@state.pop
|
34
|
+
end
|
35
|
+
|
36
|
+
def array_append(a,v)
|
37
|
+
a << v
|
38
|
+
end
|
39
|
+
|
40
|
+
def add_value(v)
|
41
|
+
p v
|
42
|
+
end
|
43
|
+
|
44
|
+
def error(message, line, column); p "ERROR: #{message}" end
|
45
|
+
end
|
46
|
+
|
47
|
+
$handler = Handler.new
|
48
|
+
|
49
|
+
IO.popen("cat tst") { |p| puts Oj.sc_parse($handler, p) }
|
50
|
+
|
51
|
+
#File.open('tst', 'r') { |file| Oj.sc_parse($handler, file) }
|