iodine 0.6.5 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of iodine might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +4 -4
- data/SPEC-Websocket-Draft.md +3 -6
- data/bin/mustache.rb +128 -0
- data/examples/test_template.mustache +16 -0
- data/ext/iodine/fio.c +9397 -0
- data/ext/iodine/fio.h +4723 -0
- data/ext/iodine/fio_ary.h +353 -54
- data/ext/iodine/fio_cli.c +351 -361
- data/ext/iodine/fio_cli.h +84 -105
- data/ext/iodine/fio_hashmap.h +70 -16
- data/ext/iodine/fio_json_parser.h +35 -24
- data/ext/iodine/fio_siphash.c +104 -4
- data/ext/iodine/fio_siphash.h +18 -2
- data/ext/iodine/fio_str.h +1218 -0
- data/ext/iodine/fio_tmpfile.h +1 -1
- data/ext/iodine/fiobj.h +13 -8
- data/ext/iodine/fiobj4sock.h +6 -8
- data/ext/iodine/fiobj_ary.c +107 -17
- data/ext/iodine/fiobj_ary.h +36 -4
- data/ext/iodine/fiobj_data.c +146 -127
- data/ext/iodine/fiobj_data.h +25 -23
- data/ext/iodine/fiobj_hash.c +7 -7
- data/ext/iodine/fiobj_hash.h +6 -5
- data/ext/iodine/fiobj_json.c +20 -17
- data/ext/iodine/fiobj_json.h +5 -5
- data/ext/iodine/fiobj_mem.h +71 -0
- data/ext/iodine/fiobj_mustache.c +310 -0
- data/ext/iodine/fiobj_mustache.h +40 -0
- data/ext/iodine/fiobj_numbers.c +199 -94
- data/ext/iodine/fiobj_numbers.h +7 -7
- data/ext/iodine/fiobj_str.c +142 -333
- data/ext/iodine/fiobj_str.h +65 -55
- data/ext/iodine/fiobject.c +49 -11
- data/ext/iodine/fiobject.h +40 -39
- data/ext/iodine/http.c +382 -190
- data/ext/iodine/http.h +124 -80
- data/ext/iodine/http1.c +99 -127
- data/ext/iodine/http1.h +5 -5
- data/ext/iodine/http1_parser.c +3 -2
- data/ext/iodine/http1_parser.h +2 -2
- data/ext/iodine/http_internal.c +14 -12
- data/ext/iodine/http_internal.h +25 -19
- data/ext/iodine/iodine.c +37 -18
- data/ext/iodine/iodine.h +4 -0
- data/ext/iodine/iodine_caller.c +9 -2
- data/ext/iodine/iodine_caller.h +2 -0
- data/ext/iodine/iodine_connection.c +82 -117
- data/ext/iodine/iodine_defer.c +57 -50
- data/ext/iodine/iodine_defer.h +0 -1
- data/ext/iodine/iodine_fiobj2rb.h +4 -2
- data/ext/iodine/iodine_helpers.c +4 -4
- data/ext/iodine/iodine_http.c +25 -32
- data/ext/iodine/iodine_json.c +2 -1
- data/ext/iodine/iodine_mustache.c +423 -0
- data/ext/iodine/iodine_mustache.h +6 -0
- data/ext/iodine/iodine_pubsub.c +48 -153
- data/ext/iodine/iodine_pubsub.h +5 -4
- data/ext/iodine/iodine_rack_io.c +7 -5
- data/ext/iodine/iodine_store.c +16 -13
- data/ext/iodine/iodine_tcp.c +26 -34
- data/ext/iodine/mustache_parser.h +1085 -0
- data/ext/iodine/redis_engine.c +740 -646
- data/ext/iodine/redis_engine.h +13 -15
- data/ext/iodine/resp_parser.h +11 -5
- data/ext/iodine/websocket_parser.h +13 -13
- data/ext/iodine/websockets.c +240 -393
- data/ext/iodine/websockets.h +52 -113
- data/lib/iodine.rb +1 -1
- data/lib/iodine/mustache.rb +140 -0
- data/lib/iodine/version.rb +1 -1
- metadata +15 -28
- data/ext/iodine/defer.c +0 -566
- data/ext/iodine/defer.h +0 -148
- data/ext/iodine/evio.c +0 -26
- data/ext/iodine/evio.h +0 -161
- data/ext/iodine/evio_callbacks.c +0 -26
- data/ext/iodine/evio_epoll.c +0 -251
- data/ext/iodine/evio_kqueue.c +0 -194
- data/ext/iodine/facil.c +0 -2325
- data/ext/iodine/facil.h +0 -616
- data/ext/iodine/fio_base64.c +0 -277
- data/ext/iodine/fio_base64.h +0 -71
- data/ext/iodine/fio_llist.h +0 -257
- data/ext/iodine/fio_mem.c +0 -675
- data/ext/iodine/fio_mem.h +0 -143
- data/ext/iodine/fio_random.c +0 -248
- data/ext/iodine/fio_random.h +0 -45
- data/ext/iodine/fio_sha1.c +0 -362
- data/ext/iodine/fio_sha1.h +0 -107
- data/ext/iodine/fio_sha2.c +0 -842
- data/ext/iodine/fio_sha2.h +0 -169
- data/ext/iodine/pubsub.c +0 -867
- data/ext/iodine/pubsub.h +0 -221
- data/ext/iodine/sock.c +0 -1366
- data/ext/iodine/sock.h +0 -566
- data/ext/iodine/spnlock.inc +0 -111
data/ext/iodine/fiobj_data.h
CHANGED
@@ -16,17 +16,17 @@ License: MIT
|
|
16
16
|
*/
|
17
17
|
#define H_FIOBJ_IO_H
|
18
18
|
|
19
|
-
#include
|
19
|
+
#include <fiobject.h>
|
20
20
|
|
21
21
|
#ifdef __cplusplus
|
22
22
|
extern "C" {
|
23
23
|
#endif
|
24
24
|
|
25
25
|
/* *****************************************************************************
|
26
|
-
Creating the
|
26
|
+
Creating the Data Stream object
|
27
27
|
***************************************************************************** */
|
28
28
|
|
29
|
-
/** Creates a new local in-memory
|
29
|
+
/** Creates a new local in-memory Data Stream object */
|
30
30
|
FIOBJ fiobj_data_newstr(void);
|
31
31
|
|
32
32
|
/**
|
@@ -37,20 +37,20 @@ FIOBJ fiobj_data_newstr(void);
|
|
37
37
|
FIOBJ fiobj_data_newstr2(void *buffer, uintptr_t length,
|
38
38
|
void (*dealloc)(void *));
|
39
39
|
|
40
|
-
/** Creates a new local tempfile
|
40
|
+
/** Creates a new local tempfile Data Stream object */
|
41
41
|
FIOBJ fiobj_data_newtmpfile(void);
|
42
42
|
|
43
|
-
/** Creates a new local file
|
43
|
+
/** Creates a new local file Data Stream object */
|
44
44
|
FIOBJ fiobj_data_newfd(int fd);
|
45
45
|
|
46
46
|
/** Creates a slice from an existing Data object. */
|
47
47
|
FIOBJ fiobj_data_slice(FIOBJ parent, intptr_t offset, uintptr_t length);
|
48
48
|
|
49
49
|
/* *****************************************************************************
|
50
|
-
Saving the
|
50
|
+
Saving the Data Stream object
|
51
51
|
***************************************************************************** */
|
52
52
|
|
53
|
-
/** Creates a new local file
|
53
|
+
/** Creates a new local file Data Stream object */
|
54
54
|
int fiobj_data_save(FIOBJ io, const char *filename);
|
55
55
|
|
56
56
|
/* *****************************************************************************
|
@@ -65,9 +65,9 @@ Reading API
|
|
65
65
|
* input backwards (0 == EOF).
|
66
66
|
*
|
67
67
|
* The C string object will be invalidate the next time a function call to the
|
68
|
-
*
|
68
|
+
* Data Stream object is made.
|
69
69
|
*/
|
70
|
-
|
70
|
+
fio_str_info_s fiobj_data_read(FIOBJ io, intptr_t length);
|
71
71
|
|
72
72
|
/**
|
73
73
|
* Reads until the `token` byte is encountered or until the end of the stream.
|
@@ -78,9 +78,9 @@ fio_cstr_s fiobj_data_read(FIOBJ io, intptr_t length);
|
|
78
78
|
* stream might be loaded into the memory.
|
79
79
|
*
|
80
80
|
* The C string object will be invalidate the next time a function call to the
|
81
|
-
*
|
81
|
+
* Data Stream object is made.
|
82
82
|
*/
|
83
|
-
|
83
|
+
fio_str_info_s fiobj_data_read2ch(FIOBJ io, uint8_t token);
|
84
84
|
|
85
85
|
/**
|
86
86
|
* Reads a line (until the '\n' byte is encountered) or until the end of the
|
@@ -93,7 +93,7 @@ fio_cstr_s fiobj_data_read2ch(FIOBJ io, uint8_t token);
|
|
93
93
|
* might be loaded into the memory.
|
94
94
|
*
|
95
95
|
* The C string object will be invalidate the next time a function call to the
|
96
|
-
*
|
96
|
+
* Data Stream object is made.
|
97
97
|
*/
|
98
98
|
#define fiobj_data_gets(io) fiobj_data_read2ch((io), '\n');
|
99
99
|
|
@@ -118,38 +118,40 @@ void fiobj_data_seek(FIOBJ io, intptr_t position);
|
|
118
118
|
* position is ignored and unchanged.
|
119
119
|
*
|
120
120
|
* The C string object will be invalidate the next time a function call to the
|
121
|
-
*
|
121
|
+
* Data Stream object is made.
|
122
122
|
*/
|
123
|
-
|
123
|
+
fio_str_info_s fiobj_data_pread(FIOBJ io, intptr_t start_at, uintptr_t length);
|
124
124
|
|
125
125
|
/* *****************************************************************************
|
126
126
|
Writing API
|
127
127
|
***************************************************************************** */
|
128
128
|
|
129
129
|
/**
|
130
|
-
* Writes `length` bytes at the end of the
|
131
|
-
* position.
|
130
|
+
* Writes `length` bytes at the end of the Data Stream stream, ignoring the
|
131
|
+
* reading position.
|
132
132
|
*
|
133
133
|
* Behaves and returns the same value as the system call `write`.
|
134
134
|
*/
|
135
135
|
intptr_t fiobj_data_write(FIOBJ io, void *buffer, uintptr_t length);
|
136
136
|
|
137
137
|
/**
|
138
|
-
* Writes `length` bytes at the end of the
|
139
|
-
* position, adding an EOL marker ("\r\n") to the end of the stream.
|
138
|
+
* Writes `length` bytes at the end of the Data Stream stream, ignoring the
|
139
|
+
* reading position, adding an EOL marker ("\r\n") to the end of the stream.
|
140
140
|
*
|
141
141
|
* Behaves and returns the same value as the system call `write`.
|
142
142
|
*/
|
143
143
|
intptr_t fiobj_data_puts(FIOBJ io, void *buffer, uintptr_t length);
|
144
144
|
|
145
145
|
/**
|
146
|
-
* Makes sure the
|
146
|
+
* Makes sure the Data Stream object isn't attached to a static or external
|
147
|
+
* string.
|
147
148
|
*
|
148
|
-
* If the
|
149
|
-
* copied to a new memory block.
|
149
|
+
* If the Data Stream object is attached to a static or external string, the
|
150
|
+
* data will be copied to a new memory block.
|
150
151
|
*
|
151
|
-
* If the
|
152
|
-
* and the type of
|
152
|
+
* If the Data Stream object is a slice from another Data Stream object, the
|
153
|
+
* data will be copied and the type of Data Stream object (memory vs. tmpfile)
|
154
|
+
* will be inherited.
|
153
155
|
*/
|
154
156
|
void fiobj_data_assert_dynamic(FIOBJ io);
|
155
157
|
|
data/ext/iodine/fiobj_hash.c
CHANGED
@@ -3,17 +3,17 @@ Copyright: Boaz Segev, 2017-2018
|
|
3
3
|
License: MIT
|
4
4
|
*/
|
5
5
|
|
6
|
-
#include
|
6
|
+
#include <fiobject.h>
|
7
7
|
|
8
8
|
#define FIO_OVERRIDE_MALLOC 1
|
9
|
-
#include
|
9
|
+
#include <fiobj_mem.h>
|
10
10
|
|
11
11
|
#if !FIO_FORCE_MALLOC
|
12
12
|
#define FIO_HASH_REALLOC(ptr, original_size, size, valid_data_length) \
|
13
13
|
fio_realloc2((ptr), (size), (valid_data_length))
|
14
14
|
#endif
|
15
15
|
|
16
|
-
#include
|
16
|
+
#include <fiobj_hash.h>
|
17
17
|
|
18
18
|
#include <assert.h>
|
19
19
|
|
@@ -38,7 +38,7 @@ static void hash_key_free(hash_key_s key) { fiobj_free(key.key); }
|
|
38
38
|
#define FIO_HASH_KEY_COPY(k) hash_key_copy(k)
|
39
39
|
#define FIO_HASH_KEY_DESTROY(k) hash_key_free(k)
|
40
40
|
|
41
|
-
#include
|
41
|
+
#include <fio_hashmap.h>
|
42
42
|
|
43
43
|
#include <errno.h>
|
44
44
|
|
@@ -133,7 +133,7 @@ static size_t fiobj_hash_is_true(const FIOBJ o) {
|
|
133
133
|
return fiobj_hash_count(o) != 0;
|
134
134
|
}
|
135
135
|
|
136
|
-
|
136
|
+
fio_str_info_s fiobject___noop_to_str(const FIOBJ o);
|
137
137
|
intptr_t fiobject___noop_to_i(const FIOBJ o);
|
138
138
|
double fiobject___noop_to_f(const FIOBJ o);
|
139
139
|
|
@@ -190,7 +190,7 @@ FIOBJ fiobj_hash_new2(size_t capa) {
|
|
190
190
|
|
191
191
|
/**
|
192
192
|
* Returns a temporary theoretical Hash map capacity.
|
193
|
-
* This could be used for
|
193
|
+
* This could be used for testing performance and memory consumption.
|
194
194
|
*/
|
195
195
|
size_t fiobj_hash_capa(const FIOBJ hash) {
|
196
196
|
assert(hash && FIOBJ_TYPE_IS(hash, FIOBJ_T_HASH));
|
@@ -321,7 +321,7 @@ FIOBJ fiobj_hash_get(const FIOBJ hash, FIOBJ key) {
|
|
321
321
|
* This function takes a `uintptr_t` Hash value (see `fio_siphash`) to
|
322
322
|
* perform a lookup in the HashMap.
|
323
323
|
*
|
324
|
-
* Returns NULL if no object is
|
324
|
+
* Returns NULL if no object is associated with this hashed key value.
|
325
325
|
*/
|
326
326
|
FIOBJ fiobj_hash_get2(const FIOBJ hash, uint64_t key_hash) {
|
327
327
|
assert(hash && FIOBJ_TYPE_IS(hash, FIOBJ_T_HASH));
|
data/ext/iodine/fiobj_hash.h
CHANGED
@@ -16,10 +16,11 @@ License: MIT
|
|
16
16
|
*/
|
17
17
|
#define H_FIOBJ_HASH_H
|
18
18
|
|
19
|
-
#include
|
19
|
+
#include <fiobject.h>
|
20
|
+
|
21
|
+
#include <fio_siphash.h>
|
22
|
+
#include <fiobj_str.h>
|
20
23
|
|
21
|
-
#include "fio_siphash.h"
|
22
|
-
#include "fiobj_str.h"
|
23
24
|
#include <errno.h>
|
24
25
|
|
25
26
|
#ifdef __cplusplus
|
@@ -58,7 +59,7 @@ Hash properties and state
|
|
58
59
|
|
59
60
|
/**
|
60
61
|
* Returns a temporary theoretical Hash map capacity.
|
61
|
-
* This could be used for
|
62
|
+
* This could be used for testing performance and memory consumption.
|
62
63
|
*/
|
63
64
|
size_t fiobj_hash_capa(const FIOBJ hash);
|
64
65
|
|
@@ -150,7 +151,7 @@ FIOBJ fiobj_hash_get(const FIOBJ hash, FIOBJ key);
|
|
150
151
|
* perform a lookup in the HashMap, which is slightly faster than the other
|
151
152
|
* variations.
|
152
153
|
*
|
153
|
-
* Returns FIOBJ_INVALID if no object is
|
154
|
+
* Returns FIOBJ_INVALID if no object is associated with this hashed key value.
|
154
155
|
*/
|
155
156
|
FIOBJ fiobj_hash_get2(const FIOBJ hash, uint64_t key_hash);
|
156
157
|
|
data/ext/iodine/fiobj_json.c
CHANGED
@@ -2,10 +2,10 @@
|
|
2
2
|
Copyright: Boaz Segev, 2017-2018
|
3
3
|
License: MIT
|
4
4
|
*/
|
5
|
-
#include
|
6
|
-
#include "fio_json_parser.h"
|
5
|
+
#include <fiobj_json.h>
|
7
6
|
|
8
|
-
#include
|
7
|
+
#include <fio_ary.h>
|
8
|
+
#include <fio_json_parser.h>
|
9
9
|
|
10
10
|
#include <assert.h>
|
11
11
|
#include <ctype.h>
|
@@ -162,8 +162,8 @@ JSON formatting
|
|
162
162
|
|
163
163
|
/** Writes a JSON friendly version of the src String */
|
164
164
|
static void write_safe_str(FIOBJ dest, const FIOBJ str) {
|
165
|
-
|
166
|
-
|
165
|
+
fio_str_info_s s = fiobj_obj2cstr(str);
|
166
|
+
fio_str_info_s t = fiobj_obj2cstr(dest);
|
167
167
|
t.data[t.len] = '"';
|
168
168
|
t.len++;
|
169
169
|
fiobj_str_resize(dest, t.len);
|
@@ -181,7 +181,7 @@ static void write_safe_str(FIOBJ dest, const FIOBJ str) {
|
|
181
181
|
} else {
|
182
182
|
capa = fiobj_str_capa_assert(dest, (end + s.len + 64));
|
183
183
|
}
|
184
|
-
|
184
|
+
fio_str_info_s tmp = fiobj_obj2cstr(dest);
|
185
185
|
t = tmp;
|
186
186
|
}
|
187
187
|
while (len) {
|
@@ -264,7 +264,7 @@ typedef struct {
|
|
264
264
|
uint8_t pretty;
|
265
265
|
} obj2json_data_s;
|
266
266
|
|
267
|
-
static int
|
267
|
+
static int fiobj_obj2json_task(FIOBJ o, void *data_) {
|
268
268
|
obj2json_data_s *data = data_;
|
269
269
|
uint8_t add_seperator = 1;
|
270
270
|
if (fiobj_hash_key_in_loop()) {
|
@@ -327,10 +327,10 @@ static int fiobj_fiobj_obj2json_task(FIOBJ o, void *data_) {
|
|
327
327
|
uintptr_t indent = fio_ary_count(data->stack) - 1;
|
328
328
|
fiobj_str_capa_assert(data->dest,
|
329
329
|
fiobj_obj2cstr(data->dest).len + (indent * 2));
|
330
|
-
|
330
|
+
fio_str_info_s buf = fiobj_obj2cstr(data->dest);
|
331
331
|
while (indent--) {
|
332
|
-
buf.
|
333
|
-
buf.
|
332
|
+
buf.data[buf.len++] = ' ';
|
333
|
+
buf.data[buf.len++] = ' ';
|
334
334
|
}
|
335
335
|
fiobj_str_resize(data->dest, buf.len);
|
336
336
|
}
|
@@ -413,23 +413,26 @@ FIOBJ fiobj_obj2json2(FIOBJ dest, FIOBJ o, uint8_t pretty) {
|
|
413
413
|
fiobj_str_write(dest, "null", 4);
|
414
414
|
return 0;
|
415
415
|
}
|
416
|
-
fio_ary_s stack;
|
416
|
+
fio_ary_s stack = FIO_ARY_INIT;
|
417
417
|
obj2json_data_s data = {
|
418
|
-
.dest = dest,
|
418
|
+
.dest = dest,
|
419
|
+
.stack = &stack,
|
420
|
+
.pretty = pretty,
|
421
|
+
.count = 1,
|
419
422
|
};
|
420
423
|
if (!o || !FIOBJ_IS_ALLOCATED(o) || !FIOBJECT2VTBL(o)->each) {
|
421
|
-
|
424
|
+
fiobj_obj2json_task(o, &data);
|
422
425
|
return dest;
|
423
426
|
}
|
424
427
|
fio_ary_new(&stack, 0);
|
425
|
-
fiobj_each2(o,
|
428
|
+
fiobj_each2(o, fiobj_obj2json_task, &data);
|
426
429
|
fio_ary_free(&stack);
|
427
430
|
return dest;
|
428
431
|
}
|
429
432
|
|
430
433
|
/* Formats an object into a JSON string. Remember to `fiobj_free`. */
|
431
434
|
FIOBJ fiobj_obj2json(FIOBJ obj, uint8_t pretty) {
|
432
|
-
return fiobj_obj2json2(fiobj_str_buf(
|
435
|
+
return fiobj_obj2json2(fiobj_str_buf(128), obj, pretty);
|
433
436
|
}
|
434
437
|
|
435
438
|
/* *****************************************************************************
|
@@ -442,7 +445,7 @@ void fiobj_test_json(void) {
|
|
442
445
|
#define TEST_ASSERT(cond, ...) \
|
443
446
|
if (!(cond)) { \
|
444
447
|
fprintf(stderr, "* " __VA_ARGS__); \
|
445
|
-
fprintf(stderr, "Testing failed
|
448
|
+
fprintf(stderr, "\n !!! Testing failed !!!\n"); \
|
446
449
|
exit(-1); \
|
447
450
|
}
|
448
451
|
char json_str[] = "{\"array\":[1,2,3,\"boom\"],\"my\":{\"secret\":42},"
|
@@ -538,7 +541,7 @@ void fiobj_test_json(void) {
|
|
538
541
|
fprintf(stderr, "* passed.\n");
|
539
542
|
fprintf(stderr, "=== Testing JSON formatting (simple test)\n");
|
540
543
|
tmp = fiobj_obj2json(o, 0);
|
541
|
-
fprintf(stderr, "* data (%p):\n%.*s\n", fiobj_obj2cstr(tmp).
|
544
|
+
fprintf(stderr, "* data (%p):\n%.*s\n", (void *)fiobj_obj2cstr(tmp).data,
|
542
545
|
(int)fiobj_obj2cstr(tmp).len, fiobj_obj2cstr(tmp).data);
|
543
546
|
if (!strcmp(fiobj_obj2cstr(tmp).data, json_str))
|
544
547
|
fprintf(stderr, "* Stringify == Original.\n");
|
data/ext/iodine/fiobj_json.h
CHANGED
@@ -6,11 +6,11 @@ Copyright: Boaz Segev, 2017-2018
|
|
6
6
|
License: MIT
|
7
7
|
*/
|
8
8
|
|
9
|
-
#include
|
10
|
-
#include
|
11
|
-
#include
|
12
|
-
#include
|
13
|
-
#include
|
9
|
+
#include <fiobj_ary.h>
|
10
|
+
#include <fiobj_hash.h>
|
11
|
+
#include <fiobj_numbers.h>
|
12
|
+
#include <fiobj_str.h>
|
13
|
+
#include <fiobject.h>
|
14
14
|
|
15
15
|
#ifdef __cplusplus
|
16
16
|
extern "C" {
|
@@ -0,0 +1,71 @@
|
|
1
|
+
/*
|
2
|
+
Copyright: Boaz Segev, 2018
|
3
|
+
License: MIT
|
4
|
+
|
5
|
+
Feel free to copy, use and enjoy according to the license provided.
|
6
|
+
*/
|
7
|
+
#ifndef H_FIOBJ_MEM_H
|
8
|
+
|
9
|
+
/**
|
10
|
+
* This is a placeholder for facil.io memory allocator functions in fio.h.
|
11
|
+
*
|
12
|
+
* In cases where the FIOBJ library is extracted from facil.io, these functions
|
13
|
+
* will call the system's memory allocator (`malloc`, `free`, etc').
|
14
|
+
*/
|
15
|
+
#define H_FIOBJ_MEM_H
|
16
|
+
|
17
|
+
#include <stdlib.h>
|
18
|
+
|
19
|
+
/**
|
20
|
+
* Allocates memory using a per-CPU core block memory pool.
|
21
|
+
* Memory is zeroed out.
|
22
|
+
*
|
23
|
+
* Allocations above FIO_MEMORY_BLOCK_ALLOC_LIMIT (12,288 bytes when using 32Kb
|
24
|
+
* blocks) will be redirected to `mmap`, as if `fio_mmap` was called.
|
25
|
+
*/
|
26
|
+
void *fio_malloc(size_t size);
|
27
|
+
|
28
|
+
/**
|
29
|
+
* same as calling `fio_malloc(size_per_unit * unit_count)`;
|
30
|
+
*
|
31
|
+
* Allocations above FIO_MEMORY_BLOCK_ALLOC_LIMIT (12,288 bytes when using 32Kb
|
32
|
+
* blocks) will be redirected to `mmap`, as if `fio_mmap` was called.
|
33
|
+
*/
|
34
|
+
void *fio_calloc(size_t size_per_unit, size_t unit_count);
|
35
|
+
|
36
|
+
/** Frees memory that was allocated using this library. */
|
37
|
+
void fio_free(void *ptr);
|
38
|
+
|
39
|
+
/**
|
40
|
+
* Re-allocates memory. An attept to avoid copying the data is made only for big
|
41
|
+
* memory allocations (larger than FIO_MEMORY_BLOCK_ALLOC_LIMIT).
|
42
|
+
*/
|
43
|
+
void *fio_realloc(void *ptr, size_t new_size);
|
44
|
+
|
45
|
+
/**
|
46
|
+
* Re-allocates memory. An attept to avoid copying the data is made only for big
|
47
|
+
* memory allocations (larger than FIO_MEMORY_BLOCK_ALLOC_LIMIT).
|
48
|
+
*
|
49
|
+
* This variation is slightly faster as it might copy less data.
|
50
|
+
*/
|
51
|
+
void *fio_realloc2(void *ptr, size_t new_size, size_t copy_length);
|
52
|
+
|
53
|
+
/**
|
54
|
+
* Allocates memory directly using `mmap`, this is prefered for objects that
|
55
|
+
* both require almost a page of memory (or more) and expect a long lifetime.
|
56
|
+
*
|
57
|
+
* However, since this allocation will invoke the system call (`mmap`), it will
|
58
|
+
* be inherently slower.
|
59
|
+
*
|
60
|
+
* `fio_free` can be used for deallocating the memory.
|
61
|
+
*/
|
62
|
+
void *fio_mmap(size_t size);
|
63
|
+
|
64
|
+
#if FIO_OVERRIDE_MALLOC
|
65
|
+
#define malloc fio_malloc
|
66
|
+
#define free fio_free
|
67
|
+
#define realloc fio_realloc
|
68
|
+
#define calloc fio_calloc
|
69
|
+
#endif
|
70
|
+
|
71
|
+
#endif /* H_FIOBJ_MEM_H */
|
@@ -0,0 +1,310 @@
|
|
1
|
+
#define INCLUDE_MUSTACHE_IMPLEMENTATION 1
|
2
|
+
#include <mustache_parser.h>
|
3
|
+
|
4
|
+
#include <fiobj_ary.h>
|
5
|
+
#include <fiobj_hash.h>
|
6
|
+
#include <fiobj_mustache.h>
|
7
|
+
#include <fiobj_str.h>
|
8
|
+
|
9
|
+
/**
|
10
|
+
* Loads a mustache template, converting it into an opaque instruction array.
|
11
|
+
*
|
12
|
+
* Returns a pointer to the instruction array.
|
13
|
+
*
|
14
|
+
* The `folder` argument should contain the template's root folder which would
|
15
|
+
* also be used to search for any required partial templates.
|
16
|
+
*
|
17
|
+
* The `filename` argument should contain the template's file name.
|
18
|
+
*/
|
19
|
+
mustache_s *fiobj_mustache_load(fio_str_info_s filename) {
|
20
|
+
return mustache_load(.filename = filename.data, .filename_len = filename.len);
|
21
|
+
}
|
22
|
+
|
23
|
+
/** Free the mustache template */
|
24
|
+
void fiobj_mustache_free(mustache_s *mustache) { mustache_free(mustache); }
|
25
|
+
|
26
|
+
/**
|
27
|
+
* Renders a template into an existing FIOBJ String (`dest`'s end), using the
|
28
|
+
* information in the `data` object.
|
29
|
+
*
|
30
|
+
* Returns FIOBJ_INVALID if an error occured and a FIOBJ String on success.
|
31
|
+
*/
|
32
|
+
FIOBJ fiobj_mustache_build2(FIOBJ dest, mustache_s *mustache, FIOBJ data) {
|
33
|
+
mustache_build(mustache, .udata1 = (void *)dest, .udata2 = (void *)data);
|
34
|
+
return dest;
|
35
|
+
}
|
36
|
+
|
37
|
+
/**
|
38
|
+
* Creates a FIOBJ String containing the rendered template using the information
|
39
|
+
* in the `data` object.
|
40
|
+
*
|
41
|
+
* Returns FIOBJ_INVALID if an error occured and a FIOBJ String on success.
|
42
|
+
*/
|
43
|
+
FIOBJ fiobj_mustache_build(mustache_s *mustache, FIOBJ data) {
|
44
|
+
if (!mustache)
|
45
|
+
return FIOBJ_INVALID;
|
46
|
+
return fiobj_mustache_build2(fiobj_str_buf(mustache->u.read_only.data_length),
|
47
|
+
mustache, data);
|
48
|
+
}
|
49
|
+
|
50
|
+
/* *****************************************************************************
|
51
|
+
Mustache Callbacks
|
52
|
+
***************************************************************************** */
|
53
|
+
|
54
|
+
/** HTML ecape table, created using the following Ruby Script:
|
55
|
+
a = []
|
56
|
+
256.times {|i| a[i] = "&\#x#{ i < 16 ? "0#{i.to_s(16)}" : i.to_s(16)};"}
|
57
|
+
('a'.ord..'z'.ord).each {|i| a[i] = i.chr }
|
58
|
+
('A'.ord..'Z'.ord).each {|i| a[i] = i.chr }
|
59
|
+
('0'.ord..'9'.ord).each {|i| a[i] = i.chr }
|
60
|
+
a['<'.ord] = "<"
|
61
|
+
a['>'.ord] = ">"
|
62
|
+
a['&'.ord] = "&"
|
63
|
+
a['"'.ord] = """
|
64
|
+
|
65
|
+
b = a.map {|s| s.length }
|
66
|
+
puts "static char *html_escape_strs[] = {", a.to_s.slice(1..-2) ,"};",
|
67
|
+
"static uint8_t html_escape_len[] = {", b.to_s.slice(1..-2),"};"
|
68
|
+
*/
|
69
|
+
static char *html_escape_strs[] = {
|
70
|
+
"�", "", "", "", "", "", "",
|
71
|
+
"", "", "	", "
", "", "", "
",
|
72
|
+
"", "", "", "", "", "", "",
|
73
|
+
"", "", "", "", "", "", "",
|
74
|
+
"", "", "", "", " ", "!", """,
|
75
|
+
"#", "$", "%", "&", "'", "(", ")",
|
76
|
+
"*", "+", ",", "-", ".", "/", "0",
|
77
|
+
"1", "2", "3", "4", "5", "6", "7",
|
78
|
+
"8", "9", ":", ";", "<", "=", ">",
|
79
|
+
"?", "@", "A", "B", "C", "D", "E",
|
80
|
+
"F", "G", "H", "I", "J", "K", "L",
|
81
|
+
"M", "N", "O", "P", "Q", "R", "S",
|
82
|
+
"T", "U", "V", "W", "X", "Y", "Z",
|
83
|
+
"[", "\", "]", "^", "_", "`", "a",
|
84
|
+
"b", "c", "d", "e", "f", "g", "h",
|
85
|
+
"i", "j", "k", "l", "m", "n", "o",
|
86
|
+
"p", "q", "r", "s", "t", "u", "v",
|
87
|
+
"w", "x", "y", "z", "{", "|", "}",
|
88
|
+
"~", "", "€", "", "‚", "ƒ", "„",
|
89
|
+
"…", "†", "‡", "ˆ", "‰", "Š", "‹",
|
90
|
+
"Œ", "", "Ž", "", "", "‘", "’",
|
91
|
+
"“", "”", "•", "–", "—", "˜", "™",
|
92
|
+
"š", "›", "œ", "", "ž", "Ÿ", " ",
|
93
|
+
"¡", "¢", "£", "¤", "¥", "¦", "§",
|
94
|
+
"¨", "©", "ª", "«", "¬", "­", "®",
|
95
|
+
"¯", "°", "±", "²", "³", "´", "µ",
|
96
|
+
"¶", "·", "¸", "¹", "º", "»", "¼",
|
97
|
+
"½", "¾", "¿", "À", "Á", "Â", "Ã",
|
98
|
+
"Ä", "Å", "Æ", "Ç", "È", "É", "Ê",
|
99
|
+
"Ë", "Ì", "Í", "Î", "Ï", "Ð", "Ñ",
|
100
|
+
"Ò", "Ó", "Ô", "Õ", "Ö", "×", "Ø",
|
101
|
+
"Ù", "Ú", "Û", "Ü", "Ý", "Þ", "ß",
|
102
|
+
"à", "á", "â", "ã", "ä", "å", "æ",
|
103
|
+
"ç", "è", "é", "ê", "ë", "ì", "í",
|
104
|
+
"î", "ï", "ð", "ñ", "ò", "ó", "ô",
|
105
|
+
"õ", "ö", "÷", "ø", "ù", "ú", "û",
|
106
|
+
"ü", "ý", "þ", "ÿ"};
|
107
|
+
static uint8_t html_escape_len[] = {
|
108
|
+
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
109
|
+
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
110
|
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 4, 6, 4, 6, 6, 1, 1, 1, 1, 1, 1, 1,
|
111
|
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6,
|
112
|
+
6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
113
|
+
1, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
114
|
+
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
115
|
+
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
116
|
+
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
117
|
+
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
118
|
+
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6};
|
119
|
+
|
120
|
+
static inline FIOBJ fiobj_mustache_find_obj(mustache_section_s *section,
|
121
|
+
const char *name,
|
122
|
+
uint32_t name_len) {
|
123
|
+
FIOBJ key = fiobj_str_tmp();
|
124
|
+
fiobj_str_write(key, name, name_len);
|
125
|
+
FIOBJ o = FIOBJ_INVALID;
|
126
|
+
do {
|
127
|
+
if (!FIOBJ_TYPE_IS((FIOBJ)section->udata2, FIOBJ_T_HASH))
|
128
|
+
continue;
|
129
|
+
o = fiobj_hash_get((FIOBJ)section->udata2, key);
|
130
|
+
section = section->parent;
|
131
|
+
} while (o == FIOBJ_INVALID && section);
|
132
|
+
return o;
|
133
|
+
}
|
134
|
+
/**
|
135
|
+
* Called when an argument name was detected in the current section.
|
136
|
+
*
|
137
|
+
* A conforming implementation will search for the named argument both in the
|
138
|
+
* existing section and all of it's parents (walking backwards towards the root)
|
139
|
+
* until a value is detected.
|
140
|
+
*
|
141
|
+
* A missing value should be treated the same as an empty string.
|
142
|
+
*
|
143
|
+
* A conforming implementation will output the named argument's value (either
|
144
|
+
* HTML escaped or not, depending on the `escape` flag) as a string.
|
145
|
+
*/
|
146
|
+
static int mustache_on_arg(mustache_section_s *section, const char *name,
|
147
|
+
uint32_t name_len, unsigned char escape) {
|
148
|
+
FIOBJ o = fiobj_mustache_find_obj(section, name, name_len);
|
149
|
+
if (!o)
|
150
|
+
return 0;
|
151
|
+
if (!escape || !FIOBJ_TYPE_IS(o, FIOBJ_T_STRING)) {
|
152
|
+
fiobj_str_join((FIOBJ)section->udata1, o);
|
153
|
+
return 0;
|
154
|
+
}
|
155
|
+
/* TODO: html escape */
|
156
|
+
fio_str_info_s str = fiobj_obj2cstr(o);
|
157
|
+
if (!str.len)
|
158
|
+
return 0;
|
159
|
+
fio_str_info_s i = fiobj_obj2cstr(o);
|
160
|
+
i.capa = fiobj_str_capa_assert((FIOBJ)section->udata1, i.len + str.len + 64);
|
161
|
+
do {
|
162
|
+
if (i.len + 6 >= i.capa)
|
163
|
+
i.capa = fiobj_str_capa_assert((FIOBJ)section->udata1, i.capa + 64);
|
164
|
+
i.len = fiobj_str_write((FIOBJ)section->udata1,
|
165
|
+
html_escape_strs[(uint8_t)str.data[0]],
|
166
|
+
html_escape_len[(uint8_t)str.data[0]]);
|
167
|
+
--str.len;
|
168
|
+
++str.data;
|
169
|
+
} while (str.len);
|
170
|
+
(void)section;
|
171
|
+
(void)name;
|
172
|
+
(void)name_len;
|
173
|
+
(void)escape;
|
174
|
+
return 0;
|
175
|
+
}
|
176
|
+
|
177
|
+
/**
|
178
|
+
* Called when simple template text (string) is detected.
|
179
|
+
*
|
180
|
+
* A conforming implementation will output data as a string (no escaping).
|
181
|
+
*/
|
182
|
+
static int mustache_on_text(mustache_section_s *section, const char *data,
|
183
|
+
uint32_t data_len) {
|
184
|
+
FIOBJ dest = (FIOBJ)section->udata1;
|
185
|
+
fiobj_str_write(dest, data, data_len);
|
186
|
+
return 0;
|
187
|
+
}
|
188
|
+
|
189
|
+
/**
|
190
|
+
* Called for nested sections, must return the number of objects in the new
|
191
|
+
* subsection (depending on the argument's name).
|
192
|
+
*
|
193
|
+
* Arrays should return the number of objects in the array.
|
194
|
+
*
|
195
|
+
* `true` values should return 1.
|
196
|
+
*
|
197
|
+
* `false` values should return 0.
|
198
|
+
*
|
199
|
+
* A return value of -1 will stop processing with an error.
|
200
|
+
*
|
201
|
+
* Please note, this will handle both normal and inverted sections.
|
202
|
+
*/
|
203
|
+
static int32_t mustache_on_section_test(mustache_section_s *section,
|
204
|
+
const char *name, uint32_t name_len) {
|
205
|
+
FIOBJ o = fiobj_mustache_find_obj(section, name, name_len);
|
206
|
+
if (!o)
|
207
|
+
return 0;
|
208
|
+
if (FIOBJ_TYPE_IS(o, FIOBJ_T_ARRAY))
|
209
|
+
return fiobj_ary_count(o);
|
210
|
+
return 1;
|
211
|
+
}
|
212
|
+
|
213
|
+
/**
|
214
|
+
* Called when entering a nested section.
|
215
|
+
*
|
216
|
+
* `index` is a zero based index indicating the number of repetitions that
|
217
|
+
* occurred so far (same as the array index for arrays).
|
218
|
+
*
|
219
|
+
* A return value of -1 will stop processing with an error.
|
220
|
+
*
|
221
|
+
* Note: this is a good time to update the subsection's `udata` with the value
|
222
|
+
* of the array index. The `udata` will always contain the value or the parent's
|
223
|
+
* `udata`.
|
224
|
+
*/
|
225
|
+
static int mustache_on_section_start(mustache_section_s *section,
|
226
|
+
char const *name, uint32_t name_len,
|
227
|
+
uint32_t index) {
|
228
|
+
FIOBJ o = fiobj_mustache_find_obj(section, name, name_len);
|
229
|
+
if (!o)
|
230
|
+
return -1;
|
231
|
+
if (FIOBJ_TYPE_IS(o, FIOBJ_T_ARRAY))
|
232
|
+
section->udata2 = (void *)fiobj_ary_index(o, index);
|
233
|
+
else
|
234
|
+
section->udata2 = (void *)o;
|
235
|
+
return 0;
|
236
|
+
}
|
237
|
+
|
238
|
+
/**
|
239
|
+
* Called for cleanup in case of error.
|
240
|
+
*/
|
241
|
+
static void mustache_on_formatting_error(void *udata1, void *udata2) {
|
242
|
+
(void)udata1;
|
243
|
+
(void)udata2;
|
244
|
+
}
|
245
|
+
|
246
|
+
/* *****************************************************************************
|
247
|
+
Testing
|
248
|
+
***************************************************************************** */
|
249
|
+
|
250
|
+
#if DEBUG
|
251
|
+
static inline void mustache_save2file(char const *filename, char const *data,
|
252
|
+
size_t length) {
|
253
|
+
int fd = open(filename, O_CREAT | O_RDWR, 0);
|
254
|
+
if (fd == -1) {
|
255
|
+
perror("Couldn't open / create file for template testing");
|
256
|
+
exit(-1);
|
257
|
+
}
|
258
|
+
fchmod(fd, 0777);
|
259
|
+
if (pwrite(fd, data, length, 0) != (ssize_t)length) {
|
260
|
+
perror("Mustache template write error");
|
261
|
+
exit(-1);
|
262
|
+
}
|
263
|
+
close(fd);
|
264
|
+
}
|
265
|
+
|
266
|
+
void fiobj_mustache_test(void) {
|
267
|
+
#define TEST_ASSERT(cond, ...) \
|
268
|
+
if (!(cond)) { \
|
269
|
+
fprintf(stderr, "* " __VA_ARGS__); \
|
270
|
+
fprintf(stderr, "\n !!! Testing failed !!!\n"); \
|
271
|
+
exit(-1); \
|
272
|
+
}
|
273
|
+
|
274
|
+
char const *template = "{{=<< >>=}}* Users:\r\n<<#users>><<id>>. <<& name>> "
|
275
|
+
"(<<name>>)\r\n<</users>>";
|
276
|
+
char const *template_name = "mustache_test_template.mustache";
|
277
|
+
mustache_save2file(template_name, template, strlen(template));
|
278
|
+
// mustache_error_en err = MUSTACHE_OK;
|
279
|
+
mustache_s *m =
|
280
|
+
fiobj_mustache_load((fio_str_info_s){.data = (char *)template_name});
|
281
|
+
unlink(template_name);
|
282
|
+
TEST_ASSERT(m, "fiobj_mustache_load failed.\n");
|
283
|
+
FIOBJ data = fiobj_hash_new();
|
284
|
+
FIOBJ key = fiobj_str_new("users", 5);
|
285
|
+
FIOBJ ary = fiobj_ary_new2(4);
|
286
|
+
fiobj_hash_set(data, key, ary);
|
287
|
+
fiobj_free(key);
|
288
|
+
for (int i = 0; i < 4; ++i) {
|
289
|
+
FIOBJ id = fiobj_str_buf(4);
|
290
|
+
fiobj_str_write_i(id, i);
|
291
|
+
FIOBJ name = fiobj_str_buf(4);
|
292
|
+
fiobj_str_write(name, "User ", 5);
|
293
|
+
fiobj_str_write_i(name, i);
|
294
|
+
FIOBJ usr = fiobj_hash_new2(2);
|
295
|
+
key = fiobj_str_new("id", 2);
|
296
|
+
fiobj_hash_set(usr, key, id);
|
297
|
+
fiobj_free(key);
|
298
|
+
key = fiobj_str_new("name", 4);
|
299
|
+
fiobj_hash_set(usr, key, name);
|
300
|
+
fiobj_free(key);
|
301
|
+
fiobj_ary_push(ary, usr);
|
302
|
+
}
|
303
|
+
key = fiobj_mustache_build(m, data);
|
304
|
+
fiobj_free(data);
|
305
|
+
TEST_ASSERT(key, "fiobj_mustache_build failed!\n");
|
306
|
+
fprintf(stderr, "%s\n", fiobj_obj2cstr(key).data);
|
307
|
+
fiobj_free(key);
|
308
|
+
}
|
309
|
+
|
310
|
+
#endif
|