oj 3.14.1 → 3.14.2
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/CHANGELOG.md +4 -0
- data/ext/oj/buf.h +6 -5
- data/ext/oj/cache.c +11 -10
- data/ext/oj/cache8.c +3 -2
- data/ext/oj/circarray.c +6 -5
- data/ext/oj/compat.c +2 -1
- data/ext/oj/custom.c +3 -2
- data/ext/oj/dump.c +4 -3
- data/ext/oj/dump_object.c +3 -2
- data/ext/oj/fast.c +11 -10
- data/ext/oj/intern.c +7 -5
- data/ext/oj/mem.c +324 -0
- data/ext/oj/mem.h +53 -0
- data/ext/oj/mimic_json.c +3 -2
- data/ext/oj/object.c +2 -2
- data/ext/oj/odd.c +7 -6
- data/ext/oj/oj.c +12 -5
- data/ext/oj/parse.c +14 -12
- data/ext/oj/parser.c +6 -6
- data/ext/oj/rails.c +9 -8
- data/ext/oj/reader.c +3 -2
- data/ext/oj/reader.h +3 -1
- data/ext/oj/rxclass.c +5 -4
- data/ext/oj/saj.c +6 -5
- data/ext/oj/saj2.c +6 -5
- data/ext/oj/sparse.c +5 -4
- data/ext/oj/stream_writer.c +5 -4
- data/ext/oj/string_writer.c +7 -6
- data/ext/oj/usual.c +28 -27
- data/ext/oj/val_stack.h +4 -3
- data/lib/oj/version.rb +1 -1
- data/test/foo.rb +48 -3
- data/test/perf_parser.rb +1 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 35277d429b423f078c9c259bc2f7d8fd5714f55bb67def193b2b58c1352f3d11
|
4
|
+
data.tar.gz: 337ca936375237d94a5e6a6ece01abd28ce367119fbb72b53dc41c3248c9e136
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e41c8ef241150e82943a92becc0ca0ec501d3ea9f9a2729abcb2529f2f5ac4360bb0a7684d46fd2357c0edb81d9347b5a6228129536c24157df5b0a788a4fc22
|
7
|
+
data.tar.gz: 6b69fcd20fe9956826865a8fafbca921ae0d9d39f43fbb3aa713b8411381852bcbfa16f7b3a3557e0c24e0545fb0a82c120c93c24bcd81ea8616b89fb6db2b47
|
data/CHANGELOG.md
CHANGED
data/ext/oj/buf.h
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
#define OJ_BUF_H
|
6
6
|
|
7
7
|
#include "ruby.h"
|
8
|
+
#include "mem.h"
|
8
9
|
|
9
10
|
typedef struct _buf {
|
10
11
|
char *head;
|
@@ -25,7 +26,7 @@ inline static void buf_reset(Buf buf) {
|
|
25
26
|
|
26
27
|
inline static void buf_cleanup(Buf buf) {
|
27
28
|
if (buf->base != buf->head) {
|
28
|
-
|
29
|
+
OJ_R_FREE(buf->head);
|
29
30
|
}
|
30
31
|
}
|
31
32
|
|
@@ -49,10 +50,10 @@ inline static void buf_append_string(Buf buf, const char *s, size_t slen) {
|
|
49
50
|
size_t new_len = len + slen + len / 2;
|
50
51
|
|
51
52
|
if (buf->base == buf->head) {
|
52
|
-
buf->head =
|
53
|
+
buf->head = OJ_R_ALLOC_N(char, new_len);
|
53
54
|
memcpy(buf->head, buf->base, len);
|
54
55
|
} else {
|
55
|
-
|
56
|
+
OJ_R_REALLOC_N(buf->head, char, new_len);
|
56
57
|
}
|
57
58
|
buf->tail = buf->head + toff;
|
58
59
|
buf->end = buf->head + new_len - 1;
|
@@ -68,10 +69,10 @@ inline static void buf_append(Buf buf, char c) {
|
|
68
69
|
size_t new_len = len + len / 2;
|
69
70
|
|
70
71
|
if (buf->base == buf->head) {
|
71
|
-
buf->head =
|
72
|
+
buf->head = OJ_R_ALLOC_N(char, new_len);
|
72
73
|
memcpy(buf->head, buf->base, len);
|
73
74
|
} else {
|
74
|
-
|
75
|
+
OJ_R_REALLOC_N(buf->head, char, new_len);
|
75
76
|
}
|
76
77
|
buf->tail = buf->head + toff;
|
77
78
|
buf->end = buf->head + new_len - 1;
|
data/ext/oj/cache.c
CHANGED
@@ -6,6 +6,7 @@
|
|
6
6
|
#endif
|
7
7
|
#include <stdlib.h>
|
8
8
|
|
9
|
+
#include "mem.h"
|
9
10
|
#include "cache.h"
|
10
11
|
|
11
12
|
// The stdlib calloc, realloc, and free are used instead of the Ruby ALLOC,
|
@@ -100,7 +101,7 @@ static void rehash(Cache c) {
|
|
100
101
|
osize = c->size;
|
101
102
|
c->size = osize * 4;
|
102
103
|
c->mask = c->size - 1;
|
103
|
-
c->slots =
|
104
|
+
c->slots = OJ_REALLOC((void *)c->slots, sizeof(Slot) * c->size);
|
104
105
|
memset((Slot *)c->slots + osize, 0, sizeof(Slot) * osize * 3);
|
105
106
|
end = (Slot *)c->slots + osize;
|
106
107
|
for (sp = (Slot *)c->slots; sp < end; sp++) {
|
@@ -128,7 +129,7 @@ static VALUE lockless_intern(Cache c, const char *key, size_t len) {
|
|
128
129
|
while (REUSE_MAX < c->rcnt) {
|
129
130
|
if (NULL != (b = c->reuse)) {
|
130
131
|
c->reuse = b->next;
|
131
|
-
|
132
|
+
OJ_FREE(b);
|
132
133
|
c->rcnt--;
|
133
134
|
} else {
|
134
135
|
// An accounting error occured somewhere so correct it.
|
@@ -143,7 +144,7 @@ static VALUE lockless_intern(Cache c, const char *key, size_t len) {
|
|
143
144
|
}
|
144
145
|
rkey = c->form(key, len);
|
145
146
|
if (NULL == (b = c->reuse)) {
|
146
|
-
b =
|
147
|
+
b = OJ_CALLOC(1, sizeof(struct _slot));
|
147
148
|
} else {
|
148
149
|
c->reuse = b->next;
|
149
150
|
c->rcnt--;
|
@@ -174,7 +175,7 @@ static VALUE locking_intern(Cache c, const char *key, size_t len) {
|
|
174
175
|
while (REUSE_MAX < c->rcnt) {
|
175
176
|
if (NULL != (b = c->reuse)) {
|
176
177
|
c->reuse = b->next;
|
177
|
-
|
178
|
+
OJ_FREE(b);
|
178
179
|
c->rcnt--;
|
179
180
|
} else {
|
180
181
|
// An accounting error occured somewhere so correct it.
|
@@ -200,7 +201,7 @@ static VALUE locking_intern(Cache c, const char *key, size_t len) {
|
|
200
201
|
}
|
201
202
|
CACHE_UNLOCK(c);
|
202
203
|
if (NULL == b) {
|
203
|
-
b =
|
204
|
+
b = OJ_CALLOC(1, sizeof(struct _slot));
|
204
205
|
}
|
205
206
|
rkey = c->form(key, len);
|
206
207
|
b->hash = h;
|
@@ -228,7 +229,7 @@ static VALUE locking_intern(Cache c, const char *key, size_t len) {
|
|
228
229
|
}
|
229
230
|
|
230
231
|
Cache cache_create(size_t size, VALUE (*form)(const char *str, size_t len), bool mark, bool locking) {
|
231
|
-
Cache c =
|
232
|
+
Cache c = OJ_CALLOC(1, sizeof(struct _cache));
|
232
233
|
int shift = 0;
|
233
234
|
|
234
235
|
for (; REHASH_LIMIT < size; size /= 2, shift++) {
|
@@ -243,7 +244,7 @@ Cache cache_create(size_t size, VALUE (*form)(const char *str, size_t len), bool
|
|
243
244
|
#endif
|
244
245
|
c->size = 1 << shift;
|
245
246
|
c->mask = c->size - 1;
|
246
|
-
c->slots =
|
247
|
+
c->slots = OJ_CALLOC(c->size, sizeof(Slot));
|
247
248
|
c->form = form;
|
248
249
|
c->xrate = 1; // low
|
249
250
|
c->mark = mark;
|
@@ -268,11 +269,11 @@ void cache_free(Cache c) {
|
|
268
269
|
|
269
270
|
for (s = c->slots[i]; NULL != s; s = next) {
|
270
271
|
next = s->next;
|
271
|
-
|
272
|
+
OJ_FREE(s);
|
272
273
|
}
|
273
274
|
}
|
274
|
-
|
275
|
-
|
275
|
+
OJ_FREE((void *)c->slots);
|
276
|
+
OJ_FREE(c);
|
276
277
|
}
|
277
278
|
|
278
279
|
void cache_mark(Cache c) {
|
data/ext/oj/cache8.c
CHANGED
@@ -9,6 +9,7 @@
|
|
9
9
|
#include <stdlib.h>
|
10
10
|
#include <string.h>
|
11
11
|
|
12
|
+
#include "mem.h"
|
12
13
|
#include "ruby.h"
|
13
14
|
|
14
15
|
#define BITS 4
|
@@ -32,7 +33,7 @@ void oj_cache8_new(Cache8 *cache) {
|
|
32
33
|
Bucket *b;
|
33
34
|
int i;
|
34
35
|
|
35
|
-
*cache =
|
36
|
+
*cache = OJ_R_ALLOC(struct _cache8);
|
36
37
|
for (i = SLOT_CNT, b = (*cache)->buckets; 0 < i; i--, b++) {
|
37
38
|
b->value = 0;
|
38
39
|
}
|
@@ -51,7 +52,7 @@ static void cache8_delete(Cache8 cache, int depth) {
|
|
51
52
|
}
|
52
53
|
}
|
53
54
|
}
|
54
|
-
|
55
|
+
OJ_R_FREE(cache);
|
55
56
|
}
|
56
57
|
|
57
58
|
slot_t oj_cache8_get(Cache8 cache, sid_t key, slot_t **slot) {
|
data/ext/oj/circarray.c
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
// Copyright (c) 2012 Peter Ohler. All rights reserved.
|
2
2
|
// Licensed under the MIT License. See LICENSE file in the project root for license details.
|
3
3
|
|
4
|
+
#include "mem.h"
|
4
5
|
#include "circarray.h"
|
5
6
|
|
6
7
|
CircArray oj_circ_array_new(void) {
|
7
8
|
CircArray ca;
|
8
9
|
|
9
|
-
if (0 == (ca =
|
10
|
+
if (0 == (ca = OJ_R_ALLOC(struct _circArray))) {
|
10
11
|
rb_raise(rb_eNoMemError, "not enough memory\n");
|
11
12
|
}
|
12
13
|
ca->objs = ca->obj_array;
|
@@ -18,9 +19,9 @@ CircArray oj_circ_array_new(void) {
|
|
18
19
|
|
19
20
|
void oj_circ_array_free(CircArray ca) {
|
20
21
|
if (ca->objs != ca->obj_array) {
|
21
|
-
|
22
|
+
OJ_R_FREE(ca->objs);
|
22
23
|
}
|
23
|
-
|
24
|
+
OJ_R_FREE(ca);
|
24
25
|
}
|
25
26
|
|
26
27
|
void oj_circ_array_set(CircArray ca, VALUE obj, unsigned long id) {
|
@@ -31,12 +32,12 @@ void oj_circ_array_set(CircArray ca, VALUE obj, unsigned long id) {
|
|
31
32
|
unsigned long cnt = id + 512;
|
32
33
|
|
33
34
|
if (ca->objs == ca->obj_array) {
|
34
|
-
if (0 == (ca->objs =
|
35
|
+
if (0 == (ca->objs = OJ_R_ALLOC_N(VALUE, cnt))) {
|
35
36
|
rb_raise(rb_eNoMemError, "not enough memory\n");
|
36
37
|
}
|
37
38
|
memcpy(ca->objs, ca->obj_array, sizeof(VALUE) * ca->cnt);
|
38
39
|
} else {
|
39
|
-
|
40
|
+
OJ_R_REALLOC_N(ca->objs, VALUE, cnt);
|
40
41
|
}
|
41
42
|
ca->size = cnt;
|
42
43
|
}
|
data/ext/oj/compat.c
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
|
4
4
|
#include <stdio.h>
|
5
5
|
|
6
|
+
#include "mem.h"
|
6
7
|
#include "encode.h"
|
7
8
|
#include "err.h"
|
8
9
|
#include "intern.h"
|
@@ -85,7 +86,7 @@ static void end_hash(struct _parseInfo *pi) {
|
|
85
86
|
}
|
86
87
|
}
|
87
88
|
if (0 != parent->classname) {
|
88
|
-
|
89
|
+
OJ_R_FREE((char *)parent->classname);
|
89
90
|
parent->classname = 0;
|
90
91
|
}
|
91
92
|
}
|
data/ext/oj/custom.c
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
#include <stdint.h>
|
5
5
|
#include <stdio.h>
|
6
6
|
|
7
|
+
#include "mem.h"
|
7
8
|
#include "code.h"
|
8
9
|
#include "dump.h"
|
9
10
|
#include "encode.h"
|
@@ -437,7 +438,7 @@ static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
|
|
437
438
|
ID i;
|
438
439
|
|
439
440
|
if (sizeof(nbuf) <= nlen) {
|
440
|
-
if (NULL == (n2 =
|
441
|
+
if (NULL == (n2 = OJ_STRDUP(name))) {
|
441
442
|
rb_raise(rb_eNoMemError, "for attribute name.");
|
442
443
|
}
|
443
444
|
} else {
|
@@ -454,7 +455,7 @@ static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
|
|
454
455
|
i = rb_intern(n);
|
455
456
|
v = rb_funcall(v, i, 0);
|
456
457
|
if (nbuf != n2) {
|
457
|
-
|
458
|
+
OJ_FREE(n2);
|
458
459
|
}
|
459
460
|
}
|
460
461
|
fill_indent(out, d2);
|
data/ext/oj/dump.c
CHANGED
@@ -14,6 +14,7 @@
|
|
14
14
|
#include <poll.h>
|
15
15
|
#endif
|
16
16
|
|
17
|
+
#include "mem.h"
|
17
18
|
#include "cache8.h"
|
18
19
|
#include "odd.h"
|
19
20
|
#include "oj.h"
|
@@ -948,7 +949,7 @@ void oj_out_init(Out out) {
|
|
948
949
|
|
949
950
|
void oj_out_free(Out out) {
|
950
951
|
if (out->allocated) {
|
951
|
-
|
952
|
+
OJ_R_FREE(out->buf); // TBD
|
952
953
|
}
|
953
954
|
}
|
954
955
|
|
@@ -962,9 +963,9 @@ void oj_grow_out(Out out, size_t len) {
|
|
962
963
|
size += len;
|
963
964
|
}
|
964
965
|
if (out->allocated) {
|
965
|
-
|
966
|
+
OJ_R_REALLOC_N(buf, char, (size + BUFFER_EXTRA));
|
966
967
|
} else {
|
967
|
-
buf =
|
968
|
+
buf = OJ_R_ALLOC_N(char, (size + BUFFER_EXTRA));
|
968
969
|
out->allocated = true;
|
969
970
|
memcpy(buf, out->buf, out->end - out->buf + BUFFER_EXTRA);
|
970
971
|
}
|
data/ext/oj/dump_object.c
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
// Copyright (c) 2012, 2017 Peter Ohler. All rights reserved.
|
2
2
|
// Licensed under the MIT License. See LICENSE file in the project root for license details.
|
3
3
|
|
4
|
+
#include "mem.h"
|
4
5
|
#include "dump.h"
|
5
6
|
#include "odd.h"
|
6
7
|
#include "trace.h"
|
@@ -422,7 +423,7 @@ static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
|
|
422
423
|
ID i;
|
423
424
|
|
424
425
|
if (sizeof(nbuf) <= nlen) {
|
425
|
-
if (NULL == (n2 =
|
426
|
+
if (NULL == (n2 = OJ_STRDUP(name))) {
|
426
427
|
rb_raise(rb_eNoMemError, "for attribute name.");
|
427
428
|
}
|
428
429
|
} else {
|
@@ -439,7 +440,7 @@ static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
|
|
439
440
|
i = rb_intern(n);
|
440
441
|
v = rb_funcall(v, i, 0);
|
441
442
|
if (nbuf != n2) {
|
442
|
-
|
443
|
+
OJ_FREE(n2);
|
443
444
|
}
|
444
445
|
}
|
445
446
|
fill_indent(out, d2);
|
data/ext/oj/fast.c
CHANGED
@@ -11,6 +11,7 @@
|
|
11
11
|
#include <stdlib.h>
|
12
12
|
#include <string.h>
|
13
13
|
|
14
|
+
#include "mem.h"
|
14
15
|
#include "encode.h"
|
15
16
|
#include "oj.h"
|
16
17
|
#include "dump.h"
|
@@ -160,7 +161,7 @@ inline static Leaf leaf_new(Doc doc, int type) {
|
|
160
161
|
Leaf leaf;
|
161
162
|
|
162
163
|
if (0 == doc->batches || BATCH_SIZE == doc->batches->next_avail) {
|
163
|
-
Batch b =
|
164
|
+
Batch b = OJ_R_ALLOC(struct _batch);
|
164
165
|
|
165
166
|
// Initializes all leaves with a NO_VAL value_type
|
166
167
|
memset(b, 0, sizeof(struct _batch));
|
@@ -648,11 +649,11 @@ static void doc_free(Doc doc) {
|
|
648
649
|
while (0 != (b = doc->batches)) {
|
649
650
|
doc->batches = doc->batches->next;
|
650
651
|
if (&doc->batch0 != b) {
|
651
|
-
|
652
|
+
OJ_R_FREE(b);
|
652
653
|
}
|
653
654
|
}
|
654
|
-
|
655
|
-
|
655
|
+
OJ_R_FREE(doc->json);
|
656
|
+
OJ_R_FREE(doc);
|
656
657
|
}
|
657
658
|
}
|
658
659
|
|
@@ -756,7 +757,7 @@ static VALUE parse_json(VALUE clas, char *json, bool given) {
|
|
756
757
|
int ex = 0;
|
757
758
|
volatile VALUE self;
|
758
759
|
|
759
|
-
doc =
|
760
|
+
doc = OJ_R_ALLOC_N(struct _doc, 1);
|
760
761
|
|
761
762
|
// skip UTF-8 BOM if present
|
762
763
|
if (0xEF == (uint8_t)*json && 0xBB == (uint8_t)json[1] && 0xBF == (uint8_t)json[2]) {
|
@@ -793,7 +794,7 @@ static VALUE parse_json(VALUE clas, char *json, bool given) {
|
|
793
794
|
/*
|
794
795
|
doc_free(pi.doc);
|
795
796
|
if (0 != ex) { // will jump so caller will not free
|
796
|
-
|
797
|
+
OJ_R_FREE(json);
|
797
798
|
}
|
798
799
|
*/
|
799
800
|
} else {
|
@@ -1092,14 +1093,14 @@ static VALUE doc_open(VALUE clas, VALUE str) {
|
|
1092
1093
|
|
1093
1094
|
Check_Type(str, T_STRING);
|
1094
1095
|
len = (int)RSTRING_LEN(str) + 1;
|
1095
|
-
json =
|
1096
|
+
json = OJ_R_ALLOC_N(char, len);
|
1096
1097
|
|
1097
1098
|
memcpy(json, StringValuePtr(str), len);
|
1098
1099
|
obj = parse_json(clas, json, given);
|
1099
1100
|
// TBD is this needed
|
1100
1101
|
/*
|
1101
1102
|
if (given) {
|
1102
|
-
|
1103
|
+
OJ_R_FREE(json);
|
1103
1104
|
}
|
1104
1105
|
*/
|
1105
1106
|
return obj;
|
@@ -1139,7 +1140,7 @@ static VALUE doc_open_file(VALUE clas, VALUE filename) {
|
|
1139
1140
|
}
|
1140
1141
|
fseek(f, 0, SEEK_END);
|
1141
1142
|
len = ftell(f);
|
1142
|
-
json =
|
1143
|
+
json = OJ_R_ALLOC_N(char, len + 1);
|
1143
1144
|
|
1144
1145
|
fseek(f, 0, SEEK_SET);
|
1145
1146
|
if (len != fread(json, 1, len, f)) {
|
@@ -1155,7 +1156,7 @@ static VALUE doc_open_file(VALUE clas, VALUE filename) {
|
|
1155
1156
|
// TBD is this needed
|
1156
1157
|
/*
|
1157
1158
|
if (given) {
|
1158
|
-
|
1159
|
+
OJ_R_FREE(json);
|
1159
1160
|
}
|
1160
1161
|
*/
|
1161
1162
|
return obj;
|
data/ext/oj/intern.c
CHANGED
@@ -8,6 +8,8 @@
|
|
8
8
|
#if HAVE_PTHREAD_MUTEX_INIT
|
9
9
|
#include <pthread.h>
|
10
10
|
#endif
|
11
|
+
|
12
|
+
#include "mem.h"
|
11
13
|
#include "cache.h"
|
12
14
|
#include "parse.h"
|
13
15
|
|
@@ -55,7 +57,7 @@ static VALUE form_attr(const char *str, size_t len) {
|
|
55
57
|
char buf[256];
|
56
58
|
|
57
59
|
if (sizeof(buf) - 2 <= len) {
|
58
|
-
char *b =
|
60
|
+
char *b = OJ_R_ALLOC_N(char, len + 2);
|
59
61
|
ID id;
|
60
62
|
|
61
63
|
if ('~' == *str) {
|
@@ -68,7 +70,7 @@ static VALUE form_attr(const char *str, size_t len) {
|
|
68
70
|
b[len + 1] = '\0';
|
69
71
|
}
|
70
72
|
id = rb_intern3(buf, len + 1, oj_utf8_encoding);
|
71
|
-
|
73
|
+
OJ_R_FREE(b);
|
72
74
|
return id;
|
73
75
|
}
|
74
76
|
if ('~' == *str) {
|
@@ -246,7 +248,7 @@ VALUE oj_class_intern(const char *key, size_t len, bool safe, ParseInfo pi, int
|
|
246
248
|
}
|
247
249
|
bucket = b;
|
248
250
|
}
|
249
|
-
b =
|
251
|
+
b = OJ_R_ALLOC(struct _keyVal);
|
250
252
|
b->next = NULL;
|
251
253
|
bucket->next = b;
|
252
254
|
bucket = b;
|
@@ -267,7 +269,7 @@ VALUE oj_class_intern(const char *key, size_t len, bool safe, ParseInfo pi, int
|
|
267
269
|
}
|
268
270
|
bucket = b;
|
269
271
|
}
|
270
|
-
b =
|
272
|
+
b = OJ_R_ALLOC(struct _keyVal);
|
271
273
|
b->next = NULL;
|
272
274
|
bucket->next = b;
|
273
275
|
bucket = b;
|
@@ -281,7 +283,7 @@ VALUE oj_class_intern(const char *key, size_t len, bool safe, ParseInfo pi, int
|
|
281
283
|
}
|
282
284
|
|
283
285
|
char *oj_strndup(const char *s, size_t len) {
|
284
|
-
char *d =
|
286
|
+
char *d = OJ_R_ALLOC_N(char, len + 1);
|
285
287
|
|
286
288
|
memcpy(d, s, len);
|
287
289
|
d[len] = '\0';
|