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.

Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/README.md +4 -4
  4. data/SPEC-Websocket-Draft.md +3 -6
  5. data/bin/mustache.rb +128 -0
  6. data/examples/test_template.mustache +16 -0
  7. data/ext/iodine/fio.c +9397 -0
  8. data/ext/iodine/fio.h +4723 -0
  9. data/ext/iodine/fio_ary.h +353 -54
  10. data/ext/iodine/fio_cli.c +351 -361
  11. data/ext/iodine/fio_cli.h +84 -105
  12. data/ext/iodine/fio_hashmap.h +70 -16
  13. data/ext/iodine/fio_json_parser.h +35 -24
  14. data/ext/iodine/fio_siphash.c +104 -4
  15. data/ext/iodine/fio_siphash.h +18 -2
  16. data/ext/iodine/fio_str.h +1218 -0
  17. data/ext/iodine/fio_tmpfile.h +1 -1
  18. data/ext/iodine/fiobj.h +13 -8
  19. data/ext/iodine/fiobj4sock.h +6 -8
  20. data/ext/iodine/fiobj_ary.c +107 -17
  21. data/ext/iodine/fiobj_ary.h +36 -4
  22. data/ext/iodine/fiobj_data.c +146 -127
  23. data/ext/iodine/fiobj_data.h +25 -23
  24. data/ext/iodine/fiobj_hash.c +7 -7
  25. data/ext/iodine/fiobj_hash.h +6 -5
  26. data/ext/iodine/fiobj_json.c +20 -17
  27. data/ext/iodine/fiobj_json.h +5 -5
  28. data/ext/iodine/fiobj_mem.h +71 -0
  29. data/ext/iodine/fiobj_mustache.c +310 -0
  30. data/ext/iodine/fiobj_mustache.h +40 -0
  31. data/ext/iodine/fiobj_numbers.c +199 -94
  32. data/ext/iodine/fiobj_numbers.h +7 -7
  33. data/ext/iodine/fiobj_str.c +142 -333
  34. data/ext/iodine/fiobj_str.h +65 -55
  35. data/ext/iodine/fiobject.c +49 -11
  36. data/ext/iodine/fiobject.h +40 -39
  37. data/ext/iodine/http.c +382 -190
  38. data/ext/iodine/http.h +124 -80
  39. data/ext/iodine/http1.c +99 -127
  40. data/ext/iodine/http1.h +5 -5
  41. data/ext/iodine/http1_parser.c +3 -2
  42. data/ext/iodine/http1_parser.h +2 -2
  43. data/ext/iodine/http_internal.c +14 -12
  44. data/ext/iodine/http_internal.h +25 -19
  45. data/ext/iodine/iodine.c +37 -18
  46. data/ext/iodine/iodine.h +4 -0
  47. data/ext/iodine/iodine_caller.c +9 -2
  48. data/ext/iodine/iodine_caller.h +2 -0
  49. data/ext/iodine/iodine_connection.c +82 -117
  50. data/ext/iodine/iodine_defer.c +57 -50
  51. data/ext/iodine/iodine_defer.h +0 -1
  52. data/ext/iodine/iodine_fiobj2rb.h +4 -2
  53. data/ext/iodine/iodine_helpers.c +4 -4
  54. data/ext/iodine/iodine_http.c +25 -32
  55. data/ext/iodine/iodine_json.c +2 -1
  56. data/ext/iodine/iodine_mustache.c +423 -0
  57. data/ext/iodine/iodine_mustache.h +6 -0
  58. data/ext/iodine/iodine_pubsub.c +48 -153
  59. data/ext/iodine/iodine_pubsub.h +5 -4
  60. data/ext/iodine/iodine_rack_io.c +7 -5
  61. data/ext/iodine/iodine_store.c +16 -13
  62. data/ext/iodine/iodine_tcp.c +26 -34
  63. data/ext/iodine/mustache_parser.h +1085 -0
  64. data/ext/iodine/redis_engine.c +740 -646
  65. data/ext/iodine/redis_engine.h +13 -15
  66. data/ext/iodine/resp_parser.h +11 -5
  67. data/ext/iodine/websocket_parser.h +13 -13
  68. data/ext/iodine/websockets.c +240 -393
  69. data/ext/iodine/websockets.h +52 -113
  70. data/lib/iodine.rb +1 -1
  71. data/lib/iodine/mustache.rb +140 -0
  72. data/lib/iodine/version.rb +1 -1
  73. metadata +15 -28
  74. data/ext/iodine/defer.c +0 -566
  75. data/ext/iodine/defer.h +0 -148
  76. data/ext/iodine/evio.c +0 -26
  77. data/ext/iodine/evio.h +0 -161
  78. data/ext/iodine/evio_callbacks.c +0 -26
  79. data/ext/iodine/evio_epoll.c +0 -251
  80. data/ext/iodine/evio_kqueue.c +0 -194
  81. data/ext/iodine/facil.c +0 -2325
  82. data/ext/iodine/facil.h +0 -616
  83. data/ext/iodine/fio_base64.c +0 -277
  84. data/ext/iodine/fio_base64.h +0 -71
  85. data/ext/iodine/fio_llist.h +0 -257
  86. data/ext/iodine/fio_mem.c +0 -675
  87. data/ext/iodine/fio_mem.h +0 -143
  88. data/ext/iodine/fio_random.c +0 -248
  89. data/ext/iodine/fio_random.h +0 -45
  90. data/ext/iodine/fio_sha1.c +0 -362
  91. data/ext/iodine/fio_sha1.h +0 -107
  92. data/ext/iodine/fio_sha2.c +0 -842
  93. data/ext/iodine/fio_sha2.h +0 -169
  94. data/ext/iodine/pubsub.c +0 -867
  95. data/ext/iodine/pubsub.h +0 -221
  96. data/ext/iodine/sock.c +0 -1366
  97. data/ext/iodine/sock.h +0 -566
  98. data/ext/iodine/spnlock.inc +0 -111
@@ -16,17 +16,17 @@ License: MIT
16
16
  */
17
17
  #define H_FIOBJ_IO_H
18
18
 
19
- #include "fiobject.h"
19
+ #include <fiobject.h>
20
20
 
21
21
  #ifdef __cplusplus
22
22
  extern "C" {
23
23
  #endif
24
24
 
25
25
  /* *****************************************************************************
26
- Creating the IO object
26
+ Creating the Data Stream object
27
27
  ***************************************************************************** */
28
28
 
29
- /** Creates a new local in-memory IO object */
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 IO object */
40
+ /** Creates a new local tempfile Data Stream object */
41
41
  FIOBJ fiobj_data_newtmpfile(void);
42
42
 
43
- /** Creates a new local file IO object */
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 IO object
50
+ Saving the Data Stream object
51
51
  ***************************************************************************** */
52
52
 
53
- /** Creates a new local file IO object */
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
- * IO object is made.
68
+ * Data Stream object is made.
69
69
  */
70
- fio_cstr_s fiobj_data_read(FIOBJ io, intptr_t length);
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
- * IO object is made.
81
+ * Data Stream object is made.
82
82
  */
83
- fio_cstr_s fiobj_data_read2ch(FIOBJ io, uint8_t token);
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
- * IO object is made.
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
- * IO object is made.
121
+ * Data Stream object is made.
122
122
  */
123
- fio_cstr_s fiobj_data_pread(FIOBJ io, intptr_t start_at, uintptr_t length);
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 IO stream, ignoring the reading
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 IO stream, ignoring the reading
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 IO object isn't attached to a static or external string.
146
+ * Makes sure the Data Stream object isn't attached to a static or external
147
+ * string.
147
148
  *
148
- * If the IO object is attached to a static or external string, the data will be
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 IO object is a slice from another IO object, the data will be copied
152
- * and the type of IO object (memory vs. tmpfile) will be inherited.
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
 
@@ -3,17 +3,17 @@ Copyright: Boaz Segev, 2017-2018
3
3
  License: MIT
4
4
  */
5
5
 
6
- #include "fiobject.h"
6
+ #include <fiobject.h>
7
7
 
8
8
  #define FIO_OVERRIDE_MALLOC 1
9
- #include "fio_mem.h"
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 "fiobj_hash.h"
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 "fio_hashmap.h"
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
- fio_cstr_s fiobject___noop_to_str(const FIOBJ o);
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 testig performance and memory consumption.
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 asociated with this hashed key value.
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));
@@ -16,10 +16,11 @@ License: MIT
16
16
  */
17
17
  #define H_FIOBJ_HASH_H
18
18
 
19
- #include "fiobject.h"
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 testig performance and memory consumption.
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 asociated with this hashed key value.
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
 
@@ -2,10 +2,10 @@
2
2
  Copyright: Boaz Segev, 2017-2018
3
3
  License: MIT
4
4
  */
5
- #include "fiobj_json.h"
6
- #include "fio_json_parser.h"
5
+ #include <fiobj_json.h>
7
6
 
8
- #include "fio_ary.h"
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
- fio_cstr_s s = fiobj_obj2cstr(str);
166
- fio_cstr_s t = fiobj_obj2cstr(dest);
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
- fio_cstr_s tmp = fiobj_obj2cstr(dest);
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 fiobj_fiobj_obj2json_task(FIOBJ o, void *data_) {
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
- fio_cstr_s buf = fiobj_obj2cstr(data->dest);
330
+ fio_str_info_s buf = fiobj_obj2cstr(data->dest);
331
331
  while (indent--) {
332
- buf.bytes[buf.len++] = ' ';
333
- buf.bytes[buf.len++] = ' ';
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, .stack = &stack, .pretty = pretty, .count = 1,
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
- fiobj_fiobj_obj2json_task(o, &data);
424
+ fiobj_obj2json_task(o, &data);
422
425
  return dest;
423
426
  }
424
427
  fio_ary_new(&stack, 0);
425
- fiobj_each2(o, fiobj_fiobj_obj2json_task, &data);
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(0), obj, pretty);
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.\n"); \
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).buffer,
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");
@@ -6,11 +6,11 @@ Copyright: Boaz Segev, 2017-2018
6
6
  License: MIT
7
7
  */
8
8
 
9
- #include "fiobj_ary.h"
10
- #include "fiobj_hash.h"
11
- #include "fiobj_numbers.h"
12
- #include "fiobj_str.h"
13
- #include "fiobject.h"
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] = "&lt;"
61
+ a['>'.ord] = "&gt;"
62
+ a['&'.ord] = "&amp;"
63
+ a['"'.ord] = "&quot;"
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
+ "&#x00;", "&#x01;", "&#x02;", "&#x03;", "&#x04;", "&#x05;", "&#x06;",
71
+ "&#x07;", "&#x08;", "&#x09;", "&#x0a;", "&#x0b;", "&#x0c;", "&#x0d;",
72
+ "&#x0e;", "&#x0f;", "&#x10;", "&#x11;", "&#x12;", "&#x13;", "&#x14;",
73
+ "&#x15;", "&#x16;", "&#x17;", "&#x18;", "&#x19;", "&#x1a;", "&#x1b;",
74
+ "&#x1c;", "&#x1d;", "&#x1e;", "&#x1f;", "&#x20;", "&#x21;", "&quot;",
75
+ "&#x23;", "&#x24;", "&#x25;", "&amp;", "&#x27;", "&#x28;", "&#x29;",
76
+ "&#x2a;", "&#x2b;", "&#x2c;", "&#x2d;", "&#x2e;", "&#x2f;", "0",
77
+ "1", "2", "3", "4", "5", "6", "7",
78
+ "8", "9", "&#x3a;", "&#x3b;", "&lt;", "&#x3d;", "&gt;",
79
+ "&#x3f;", "&#x40;", "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
+ "&#x5b;", "&#x5c;", "&#x5d;", "&#x5e;", "&#x5f;", "&#x60;", "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", "&#x7b;", "&#x7c;", "&#x7d;",
88
+ "&#x7e;", "&#x7f;", "&#x80;", "&#x81;", "&#x82;", "&#x83;", "&#x84;",
89
+ "&#x85;", "&#x86;", "&#x87;", "&#x88;", "&#x89;", "&#x8a;", "&#x8b;",
90
+ "&#x8c;", "&#x8d;", "&#x8e;", "&#x8f;", "&#x90;", "&#x91;", "&#x92;",
91
+ "&#x93;", "&#x94;", "&#x95;", "&#x96;", "&#x97;", "&#x98;", "&#x99;",
92
+ "&#x9a;", "&#x9b;", "&#x9c;", "&#x9d;", "&#x9e;", "&#x9f;", "&#xa0;",
93
+ "&#xa1;", "&#xa2;", "&#xa3;", "&#xa4;", "&#xa5;", "&#xa6;", "&#xa7;",
94
+ "&#xa8;", "&#xa9;", "&#xaa;", "&#xab;", "&#xac;", "&#xad;", "&#xae;",
95
+ "&#xaf;", "&#xb0;", "&#xb1;", "&#xb2;", "&#xb3;", "&#xb4;", "&#xb5;",
96
+ "&#xb6;", "&#xb7;", "&#xb8;", "&#xb9;", "&#xba;", "&#xbb;", "&#xbc;",
97
+ "&#xbd;", "&#xbe;", "&#xbf;", "&#xc0;", "&#xc1;", "&#xc2;", "&#xc3;",
98
+ "&#xc4;", "&#xc5;", "&#xc6;", "&#xc7;", "&#xc8;", "&#xc9;", "&#xca;",
99
+ "&#xcb;", "&#xcc;", "&#xcd;", "&#xce;", "&#xcf;", "&#xd0;", "&#xd1;",
100
+ "&#xd2;", "&#xd3;", "&#xd4;", "&#xd5;", "&#xd6;", "&#xd7;", "&#xd8;",
101
+ "&#xd9;", "&#xda;", "&#xdb;", "&#xdc;", "&#xdd;", "&#xde;", "&#xdf;",
102
+ "&#xe0;", "&#xe1;", "&#xe2;", "&#xe3;", "&#xe4;", "&#xe5;", "&#xe6;",
103
+ "&#xe7;", "&#xe8;", "&#xe9;", "&#xea;", "&#xeb;", "&#xec;", "&#xed;",
104
+ "&#xee;", "&#xef;", "&#xf0;", "&#xf1;", "&#xf2;", "&#xf3;", "&#xf4;",
105
+ "&#xf5;", "&#xf6;", "&#xf7;", "&#xf8;", "&#xf9;", "&#xfa;", "&#xfb;",
106
+ "&#xfc;", "&#xfd;", "&#xfe;", "&#xff;"};
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