iodine 0.7.60 → 0.8.0

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.
Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/.clang-format +15 -0
  3. data/.rspec +1 -0
  4. data/.yardopts +1 -3
  5. data/CHANGELOG.md +132 -12
  6. data/Gemfile +5 -7
  7. data/LICENSE.txt +1 -1
  8. data/README.md +147 -671
  9. data/Rakefile +9 -16
  10. data/examples/chatroom.nru +9 -0
  11. data/examples/client +74 -0
  12. data/examples/config-hello.nru +9 -0
  13. data/examples/config-hello.ru +11 -0
  14. data/examples/config-hijack.ru +13 -0
  15. data/examples/config-shootout.ru +43 -0
  16. data/examples/config.nru +120 -0
  17. data/examples/config.rb +37 -0
  18. data/examples/config.ru +42 -53
  19. data/examples/fake +24 -0
  20. data/examples/hello_neorack +137 -0
  21. data/examples/routes.nru +29 -0
  22. data/examples/routes.ru +42 -0
  23. data/exe/iodine +218 -258
  24. data/ext/iodine/extconf.rb +27 -100
  25. data/ext/iodine/fio-stl.h +128336 -0
  26. data/ext/iodine/fio-stl.md +26396 -0
  27. data/ext/iodine/iodine.c +213 -1393
  28. data/ext/iodine/iodine.h +250 -55
  29. data/ext/iodine/iodine_arg_helper.h +329 -0
  30. data/ext/iodine/iodine_caller.h +234 -25
  31. data/ext/iodine/iodine_cli.h +434 -0
  32. data/ext/iodine/iodine_compression.h +312 -0
  33. data/ext/iodine/iodine_connection.h +3484 -34
  34. data/ext/iodine/iodine_core.h +363 -0
  35. data/ext/iodine/iodine_crypto.h +1441 -0
  36. data/ext/iodine/iodine_defer.h +225 -4
  37. data/ext/iodine/iodine_json.h +738 -4
  38. data/ext/iodine/iodine_listener.h +263 -0
  39. data/ext/iodine/iodine_log.h +297 -0
  40. data/ext/iodine/iodine_minimap.h +543 -0
  41. data/ext/iodine/iodine_mustache.h +461 -4
  42. data/ext/iodine/iodine_pubsub_eng.h +729 -0
  43. data/ext/iodine/iodine_pubsub_history.h +547 -0
  44. data/ext/iodine/iodine_pubsub_msg.h +228 -0
  45. data/ext/iodine/iodine_redis.h +322 -0
  46. data/ext/iodine/iodine_store.h +418 -16
  47. data/ext/iodine/iodine_threads.h +279 -0
  48. data/ext/iodine/iodine_tls.h +515 -6
  49. data/ext/iodine/iodine_utils.h +923 -0
  50. data/iodine.gemspec +37 -42
  51. data/lib/iodine/benchmark.rb +1690 -0
  52. data/lib/iodine/documentation.rb +3085 -0
  53. data/lib/iodine/version.rb +17 -1
  54. data/lib/iodine.rb +54 -255
  55. data/logo.svg +36 -0
  56. data/mustache.md +55 -0
  57. data/sig/iodine.rbs +4 -0
  58. metadata +58 -184
  59. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
  60. data/.github/workflows/ruby.yml +0 -42
  61. data/.gitignore +0 -21
  62. data/LIMITS.md +0 -41
  63. data/SPEC-PubSub-Draft.md +0 -159
  64. data/SPEC-WebSocket-Draft.md +0 -239
  65. data/bin/console +0 -22
  66. data/bin/info.md +0 -353
  67. data/bin/mustache_bench.rb +0 -100
  68. data/bin/poc/Gemfile.lock +0 -23
  69. data/bin/poc/README.md +0 -37
  70. data/bin/poc/config.ru +0 -66
  71. data/bin/poc/gemfile +0 -1
  72. data/bin/poc/www/index.html +0 -57
  73. data/examples/async_task.ru +0 -92
  74. data/examples/bates/README.md +0 -3
  75. data/examples/bates/config.ru +0 -342
  76. data/examples/bates/david+bold.pdf +0 -0
  77. data/examples/bates/public/drop-pdf.png +0 -0
  78. data/examples/bates/public/index.html +0 -600
  79. data/examples/echo.ru +0 -59
  80. data/examples/etag.ru +0 -16
  81. data/examples/hello.ru +0 -29
  82. data/examples/pubsub_engine.ru +0 -81
  83. data/examples/rack3.ru +0 -12
  84. data/examples/redis.ru +0 -70
  85. data/examples/shootout.ru +0 -73
  86. data/examples/sub-protocols.ru +0 -90
  87. data/examples/tcp_client.rb +0 -66
  88. data/examples/x-sendfile.ru +0 -14
  89. data/ext/iodine/fio.c +0 -11995
  90. data/ext/iodine/fio.h +0 -6371
  91. data/ext/iodine/fio_cli.c +0 -431
  92. data/ext/iodine/fio_cli.h +0 -189
  93. data/ext/iodine/fio_json_parser.h +0 -688
  94. data/ext/iodine/fio_siphash.c +0 -157
  95. data/ext/iodine/fio_siphash.h +0 -37
  96. data/ext/iodine/fio_tls.h +0 -129
  97. data/ext/iodine/fio_tls_missing.c +0 -649
  98. data/ext/iodine/fio_tls_openssl.c +0 -1106
  99. data/ext/iodine/fio_tmpfile.h +0 -50
  100. data/ext/iodine/fiobj.h +0 -44
  101. data/ext/iodine/fiobj4fio.h +0 -21
  102. data/ext/iodine/fiobj_ary.c +0 -333
  103. data/ext/iodine/fiobj_ary.h +0 -139
  104. data/ext/iodine/fiobj_data.c +0 -1187
  105. data/ext/iodine/fiobj_data.h +0 -167
  106. data/ext/iodine/fiobj_hash.c +0 -409
  107. data/ext/iodine/fiobj_hash.h +0 -176
  108. data/ext/iodine/fiobj_json.c +0 -622
  109. data/ext/iodine/fiobj_json.h +0 -68
  110. data/ext/iodine/fiobj_mem.h +0 -71
  111. data/ext/iodine/fiobj_mustache.c +0 -317
  112. data/ext/iodine/fiobj_mustache.h +0 -62
  113. data/ext/iodine/fiobj_numbers.c +0 -344
  114. data/ext/iodine/fiobj_numbers.h +0 -127
  115. data/ext/iodine/fiobj_str.c +0 -433
  116. data/ext/iodine/fiobj_str.h +0 -172
  117. data/ext/iodine/fiobject.c +0 -620
  118. data/ext/iodine/fiobject.h +0 -655
  119. data/ext/iodine/hpack.h +0 -1923
  120. data/ext/iodine/http.c +0 -2743
  121. data/ext/iodine/http.h +0 -1002
  122. data/ext/iodine/http1.c +0 -910
  123. data/ext/iodine/http1.h +0 -29
  124. data/ext/iodine/http1_parser.h +0 -878
  125. data/ext/iodine/http_internal.c +0 -1279
  126. data/ext/iodine/http_internal.h +0 -237
  127. data/ext/iodine/http_mime_parser.h +0 -350
  128. data/ext/iodine/iodine_caller.c +0 -230
  129. data/ext/iodine/iodine_connection.c +0 -941
  130. data/ext/iodine/iodine_defer.c +0 -420
  131. data/ext/iodine/iodine_fiobj2rb.h +0 -120
  132. data/ext/iodine/iodine_helpers.c +0 -282
  133. data/ext/iodine/iodine_helpers.h +0 -12
  134. data/ext/iodine/iodine_http.c +0 -1181
  135. data/ext/iodine/iodine_http.h +0 -23
  136. data/ext/iodine/iodine_json.c +0 -302
  137. data/ext/iodine/iodine_mustache.c +0 -567
  138. data/ext/iodine/iodine_pubsub.c +0 -580
  139. data/ext/iodine/iodine_pubsub.h +0 -26
  140. data/ext/iodine/iodine_rack_io.c +0 -273
  141. data/ext/iodine/iodine_rack_io.h +0 -20
  142. data/ext/iodine/iodine_store.c +0 -148
  143. data/ext/iodine/iodine_tcp.c +0 -346
  144. data/ext/iodine/iodine_tcp.h +0 -13
  145. data/ext/iodine/iodine_tls.c +0 -261
  146. data/ext/iodine/mustache_parser.h +0 -1546
  147. data/ext/iodine/redis_engine.c +0 -957
  148. data/ext/iodine/redis_engine.h +0 -79
  149. data/ext/iodine/resp_parser.h +0 -317
  150. data/ext/iodine/websocket_parser.h +0 -506
  151. data/ext/iodine/websockets.c +0 -743
  152. data/ext/iodine/websockets.h +0 -185
  153. data/lib/iodine/connection.rb +0 -61
  154. data/lib/iodine/json.rb +0 -42
  155. data/lib/iodine/mustache.rb +0 -113
  156. data/lib/iodine/pubsub.rb +0 -55
  157. data/lib/iodine/rack_utils.rb +0 -43
  158. data/lib/iodine/tls.rb +0 -16
  159. data/lib/rack/handler/iodine.rb +0 -33
  160. data/logo.png +0 -0
@@ -1,1546 +0,0 @@
1
- /*
2
- Copyright: Boaz Segev, 2018-2019
3
- License: MIT
4
-
5
- Feel free to copy, use and enjoy according to the license provided.
6
- */
7
- #ifndef H_MUSTACHE_LOADR_H
8
- /**
9
- * A mustache parser using a callback systems that allows this implementation to
10
- * be framework agnostic (i.e., can be used with any JSON library).
11
- */
12
- #define H_MUSTACHE_LOADR_H
13
-
14
- #ifndef _GNU_SOURCE
15
- #define _GNU_SOURCE
16
- #endif
17
-
18
- #include <ctype.h>
19
- #include <stdint.h>
20
- #include <stdio.h>
21
- #include <stdlib.h>
22
- #include <string.h>
23
- #include <strings.h>
24
- #include <unistd.h>
25
-
26
- #include <errno.h>
27
- #include <fcntl.h>
28
- #include <sys/stat.h>
29
- #include <sys/types.h>
30
-
31
- #ifdef __MINGW32__
32
- ssize_t pread(int, void*, size_t, off_t);
33
- #endif
34
-
35
- #if !defined(__GNUC__) && !defined(__clang__) && !defined(FIO_GNUC_BYPASS)
36
- #define __attribute__(...)
37
- #define __has_include(...) 0
38
- #define __has_builtin(...) 0
39
- #define FIO_GNUC_BYPASS 1
40
- #elif !defined(__clang__) && !defined(__has_builtin)
41
- #define __has_builtin(...) 0
42
- #define FIO_GNUC_BYPASS 1
43
- #endif
44
-
45
- #ifndef MUSTACHE_FUNC
46
- #define MUSTACHE_FUNC static __attribute__((unused))
47
- #endif
48
-
49
- /* *****************************************************************************
50
- Compile Time Behavior Flags
51
- ***************************************************************************** */
52
-
53
- #ifndef MUSTACHE_USE_DYNAMIC_PADDING
54
- #define MUSTACHE_USE_DYNAMIC_PADDING 1
55
- #endif
56
-
57
- #ifndef MUSTACHE_FAIL_ON_MISSING_TEMPLATE
58
- #define MUSTACHE_FAIL_ON_MISSING_TEMPLATE 1
59
- #endif
60
-
61
- #if !defined(MUSTACHE_NESTING_LIMIT) || !MUSTACHE_NESTING_LIMIT
62
- #undef MUSTACHE_NESTING_LIMIT
63
- #define MUSTACHE_NESTING_LIMIT 82
64
- #endif
65
-
66
- /* *****************************************************************************
67
- Mustache API Argument types
68
- ***************************************************************************** */
69
-
70
- /** an opaque type for mustache template data (when caching). */
71
- typedef struct mustache_s mustache_s;
72
-
73
- /** Error reporting type. */
74
- typedef enum mustache_error_en {
75
- MUSTACHE_OK,
76
- MUSTACHE_ERR_TOO_DEEP,
77
- MUSTACHE_ERR_CLOSURE_MISMATCH,
78
- MUSTACHE_ERR_FILE_NOT_FOUND,
79
- MUSTACHE_ERR_FILE_TOO_BIG,
80
- MUSTACHE_ERR_FILE_NAME_TOO_LONG,
81
- MUSTACHE_ERR_FILE_NAME_TOO_SHORT,
82
- MUSTACHE_ERR_EMPTY_TEMPLATE,
83
- MUSTACHE_ERR_DELIMITER_TOO_LONG,
84
- MUSTACHE_ERR_NAME_TOO_LONG,
85
- MUSTACHE_ERR_UNKNOWN,
86
- MUSTACHE_ERR_USER_ERROR,
87
- } mustache_error_en;
88
-
89
- /** Arguments for the `mustache_load` function, used by the mustache parser. */
90
- typedef struct {
91
- /** The root template's file name. */
92
- char const *filename;
93
- /** The file name's length. */
94
- size_t filename_len;
95
- /** If data and data_len are set, they will be used as the file's contents. */
96
- char const *data;
97
- /** If data and data_len are set, they will be used as the file's contents. */
98
- size_t data_len;
99
- /** Parsing error reporting (can be NULL). */
100
- mustache_error_en *err;
101
- } mustache_load_args_s;
102
-
103
- /* *****************************************************************************
104
- REQUIRED: Define INCLUDE_MUSTACHE_IMPLEMENTATION only in the implementation file
105
- ***************************************************************************** */
106
-
107
- /**
108
- * In non-implementation files, don't define the INCLUDE_MUSTACHE_IMPLEMENTATION
109
- * macro.
110
- *
111
- * Before including the header within an implementation faile, define
112
- * INCLUDE_MUSTACHE_IMPLEMENTATION as 1.
113
- */
114
- #if INCLUDE_MUSTACHE_IMPLEMENTATION
115
-
116
- /* *****************************************************************************
117
- Mustache API Functions and Arguments
118
- ***************************************************************************** */
119
-
120
- MUSTACHE_FUNC mustache_s *mustache_load(mustache_load_args_s args);
121
-
122
- #define mustache_load(...) mustache_load((mustache_load_args_s){__VA_ARGS__})
123
-
124
- /** free the mustache template */
125
- inline MUSTACHE_FUNC void mustache_free(mustache_s *mustache) {
126
- free(mustache);
127
- }
128
-
129
- /** Arguments for the `mustache_build` function. */
130
- typedef struct {
131
- /** The parsed template (an instruction collection). */
132
- mustache_s *mustache;
133
- /** Opaque user data (recommended for input review) - children will inherit
134
- * the parent's udata value. Updated values will propegate to child sections
135
- * but won't effect parent sections.
136
- */
137
- void *udata1;
138
- /** Opaque user data (recommended for output handling)- children will inherit
139
- * the parent's udata value. Updated values will propegate to child sections
140
- * but won't effect parent sections.
141
- */
142
- void *udata2;
143
- /** Formatting error reporting (can be NULL). */
144
- mustache_error_en *err;
145
- } mustache_build_args_s;
146
- MUSTACHE_FUNC int mustache_build(mustache_build_args_s args);
147
-
148
- #define mustache_build(mustache_s_ptr, ...) \
149
- mustache_build( \
150
- (mustache_build_args_s){.mustache = (mustache_s_ptr), __VA_ARGS__})
151
-
152
- /* *****************************************************************************
153
- Callbacks Types - types used by the template builder callbacks
154
- ***************************************************************************** */
155
-
156
- /**
157
- * A mustache section allows the callbacks to "walk" backwards towards the root
158
- * in search of argument data.
159
- *
160
- * Note that every section is allowed a separate udata value.
161
- */
162
- typedef struct mustache_section_s {
163
- /** Opaque user data (recommended for input review) - children will inherit
164
- * the parent's udata value. Updated values will propegate to child sections
165
- * but won't effect parent sections.
166
- */
167
- void *udata1;
168
- /** Opaque user data (recommended for output handling)- children will inherit
169
- * the parent's udata value. Updated values will propegate to child sections
170
- * but won't effect parent sections.
171
- */
172
- void *udata2;
173
- } mustache_section_s;
174
-
175
- /* *****************************************************************************
176
- Callbacks Helpers - These functions can be called from within callbacks
177
- ***************************************************************************** */
178
-
179
- /**
180
- * Returns the section's parent for nested sections, or NULL (for root section).
181
- *
182
- * This allows the `udata` values in the parent to be accessed and can be used,
183
- * for example, when seeking a value (argument / keyword) within a nested data
184
- * structure such as a Hash.
185
- */
186
- static inline mustache_section_s *
187
- mustache_section_parent(mustache_section_s *section);
188
-
189
- /**
190
- * This helper function should be used to write text to the output
191
- * stream form within `mustache_on_arg` or `mustache_on_section_test`.
192
- *
193
- * This function will call the `mustache_on_text` callback for each slice of
194
- * text that requires padding and for escaped data.
195
- *
196
- * `mustache_on_text` must NEVER call this function.
197
- */
198
- static inline int mustache_write_text(mustache_section_s *section, char *text,
199
- uint32_t len, uint8_t escape);
200
-
201
- /**
202
- * Returns the section's unparsed content as a non-NUL terminated byte array.
203
- *
204
- * The length of the data will be placed in the `size_t` variable pointed to by
205
- * `p_len`. Do NOT use `strlen`, since the data isn't NUL terminated.
206
- *
207
- * This allows text to be accessed when a section's content is, in fact, meant
208
- * to be passed along to a function / lambda.
209
- */
210
- static inline const char *mustache_section_text(mustache_section_s *section,
211
- size_t *p_len);
212
-
213
- /* *****************************************************************************
214
- Client Callbacks - MUST be implemented by the including file
215
- ***************************************************************************** */
216
-
217
- /**
218
- * Called when an argument name was detected in the current section.
219
- *
220
- * A conforming implementation will search for the named argument both in the
221
- * existing section and all of it's parents (walking backwards towards the root)
222
- * until a value is detected.
223
- *
224
- * A missing value should be treated the same as an empty string.
225
- *
226
- * A conforming implementation will output the named argument's value (either
227
- * HTML escaped or not, depending on the `escape` flag) as a string.
228
- *
229
- * A conforming implementation will test for dot notation in the name.
230
- *
231
- * NOTE: the `name` data is **not** NUL terminated. Use the `name_len` data to
232
- * determine the actual string length.
233
- */
234
- static int mustache_on_arg(mustache_section_s *section, const char *name,
235
- uint32_t name_len, unsigned char escape);
236
-
237
- /**
238
- * Called when simple template text (string) is detected.
239
- *
240
- * A conforming implementation will output data as a string (no escaping).
241
- *
242
- * NOTE: the `data` is **not** NUL terminated. Use the `data_len` data to
243
- * determine the actual data length.
244
- */
245
- static int mustache_on_text(mustache_section_s *section, const char *data,
246
- uint32_t data_len);
247
-
248
- /**
249
- * Called for nested sections, must return the number of objects in the new
250
- * subsection (depending on the argument's name).
251
- *
252
- * Arrays should return the number of objects in the array.
253
- *
254
- * `true` values should return 1.
255
- *
256
- * `false` values should return 0.
257
- *
258
- * A return value of -1 will stop processing with an error.
259
- *
260
- * Please note, this will handle both normal and inverted sections.
261
- *
262
- * The `callable` value is true if the section is allowed to be a function /
263
- * callback. If the section object represent a function / callback (lambda), the
264
- * lambda should be called and the `mustache_on_section_test` callback should
265
- * return 0.
266
- *
267
- * NOTE: the `name` data is **not** NUL terminated. Use the `name_len` data to
268
- * determine the actual string length.
269
- *
270
- * A conforming implementation will test for dot notation in the name.
271
- */
272
- static int32_t mustache_on_section_test(mustache_section_s *section,
273
- const char *name, uint32_t name_len,
274
- uint8_t callable);
275
-
276
- /**
277
- * Called when entering a nested section.
278
- *
279
- * `index` is a zero based index indicating the number of repetitions that
280
- * occurred so far (same as the array index for arrays).
281
- *
282
- * A return value of -1 will stop processing with an error.
283
- *
284
- * Note: this is a good time to update the subsection's `udata` with the value
285
- * of the array index. The `udata` will always contain the value or the parent's
286
- * `udata`.
287
- *
288
- * NOTE: the `name` data is **not** NUL terminated. Use the `name_len` data to
289
- * determine the actual string length.
290
- *
291
- * A conforming implementation will test for dot notation in the name.
292
- */
293
- static int mustache_on_section_start(mustache_section_s *section,
294
- char const *name, uint32_t name_len,
295
- uint32_t index);
296
-
297
- /**
298
- * Called for cleanup in case of error.
299
- */
300
- static void mustache_on_formatting_error(void *udata1, void *udata2);
301
-
302
- /* *****************************************************************************
303
-
304
- IMPLEMENTATION (beware: monolithic functions ahead)
305
-
306
- ***************************************************************************** */
307
-
308
- /* *****************************************************************************
309
- Internal types
310
- ***************************************************************************** */
311
-
312
- struct mustache_s {
313
- /* The number of instructions in the engine */
314
- union {
315
- void *read_only_pt; /* ensure pointer wide padding */
316
- struct {
317
- uint32_t intruction_count;
318
- uint32_t data_length;
319
- } read_only;
320
- } u;
321
- };
322
-
323
- typedef struct mustache__instruction_s {
324
- enum {
325
- MUSTACHE_WRITE_TEXT,
326
- MUSTACHE_WRITE_ARG,
327
- MUSTACHE_WRITE_ARG_UNESCAPED,
328
- MUSTACHE_SECTION_START,
329
- MUSTACHE_SECTION_START_INV,
330
- MUSTACHE_SECTION_END,
331
- MUSTACHE_SECTION_GOTO,
332
- MUSTACHE_PADDING_PUSH,
333
- MUSTACHE_PADDING_POP,
334
- MUSTACHE_PADDING_WRITE,
335
- } instruction;
336
- /** the data the instruction acts upon */
337
- struct {
338
- /** The length instruction block in the instruction array (for sections). */
339
- uint32_t end;
340
- /** The length of the (string) data. */
341
- uint32_t len;
342
- /** The offset from the beginning of the data segment. */
343
- uint32_t name_pos;
344
- /** The offset between the name (start) and content (for sections). */
345
- uint16_t name_len;
346
- /** The offset between the name and the content (left / right by type). */
347
- uint16_t offset;
348
- } data;
349
- } mustache__instruction_s;
350
-
351
- typedef struct {
352
- mustache_section_s sec; /* client visible section data */
353
- uint32_t start; /* section start instruction position */
354
- uint32_t end; /* instruction to jump to after completion */
355
- uint32_t index; /* zero based index for section loops */
356
- uint32_t count; /* the number of times the section should be performed */
357
- uint16_t frame; /* the stack frame's index (zero based) */
358
- } mustache__section_stack_frame_s;
359
-
360
- /*
361
- * The stack memory is placed in a structure to allow stack unrolling and
362
- * avoiding recursion with it's stack overflow risks.
363
- */
364
- typedef struct {
365
- mustache_s *data; /* the mustache template being built */
366
- uint32_t pos; /* the instruction postision index */
367
- uint32_t padding; /* padding instruction position */
368
- uint16_t index; /* the stack postision index */
369
- mustache__section_stack_frame_s stack[MUSTACHE_NESTING_LIMIT];
370
- } mustache__builder_stack_s;
371
-
372
- #define MUSTACHE_DELIMITER_LENGTH_LIMIT 5
373
-
374
- /*
375
- * The stack memory is placed in a structure to allow stack unrolling and
376
- * avoiding recursion with it's stack overflow risks.
377
- */
378
- typedef struct {
379
- mustache_s *m;
380
- mustache__instruction_s *i;
381
- mustache_error_en *err;
382
- char *data;
383
- char *path;
384
- uint32_t i_capa;
385
- uint32_t data_len;
386
- uint32_t padding;
387
- uint16_t path_len;
388
- uint16_t path_capa;
389
- uint16_t index; /* stack index */
390
- struct {
391
- uint32_t data_start; /* template starting position (with header) */
392
- uint32_t data_pos; /* data reading position (how much was consumed) */
393
- uint32_t data_end; /* data ending position (for this template) */
394
- uint16_t open_sections; /* counts open sections waiting for closure */
395
- char del_start[MUSTACHE_DELIMITER_LENGTH_LIMIT]; /* currunt instruction
396
- start delimiter */
397
- char del_end[MUSTACHE_DELIMITER_LENGTH_LIMIT]; /* currunt instruction end
398
- delimiter */
399
- uint8_t del_start_len; /* currunt start delimiter length */
400
- uint8_t del_end_len; /* currunt end delimiter length */
401
- } stack[MUSTACHE_NESTING_LIMIT];
402
- } mustache__loader_stack_s;
403
-
404
- /* *****************************************************************************
405
- Callbacks Helper Implementation
406
- ***************************************************************************** */
407
-
408
- #define MUSTACH2INSTRUCTIONS(mustache) \
409
- ((mustache__instruction_s *)((mustache) + 1))
410
- #define MUSTACH2DATA(mustache) \
411
- (char *)(MUSTACH2INSTRUCTIONS((mustache)) + \
412
- (mustache)->u.read_only.intruction_count)
413
- #define MUSTACHE_OBJECT_OFFSET(type, member, ptr) \
414
- ((type *)((uintptr_t)(ptr) - (uintptr_t)(&(((type *)0)->member))))
415
-
416
- #define MUSTACHE_ASSERT(cond, msg) \
417
- if (!(cond)) { \
418
- perror("FATAL ERROR: " msg); \
419
- exit(errno); \
420
- }
421
- #define MUSTACHE_IGNORE_WHITESPACE(str, step) \
422
- while (isspace(*(str))) { \
423
- (str) += (step); \
424
- }
425
-
426
- /*
427
- * used internally by some of the helpers to find convert a section pointer to
428
- * the full builder stack data.
429
- */
430
- static inline mustache__builder_stack_s *
431
- mustache___section2stack(mustache_section_s *section) {
432
- mustache__section_stack_frame_s *f =
433
- (mustache__section_stack_frame_s *)section;
434
- return MUSTACHE_OBJECT_OFFSET(mustache__builder_stack_s, stack,
435
- (f - f->frame));
436
- }
437
-
438
- /**
439
- * Returns the section's parent for nested sections, or NULL (for root section).
440
- *
441
- * This allows the `udata` values in the parent to be accessed and can be used,
442
- * for example, when seeking a value (argument / keyword) within a nested data
443
- * structure such as a Hash.
444
- */
445
- static inline mustache_section_s *
446
- mustache_section_parent(mustache_section_s *section) {
447
- mustache_section_s tmp = *section;
448
- mustache__section_stack_frame_s *f =
449
- (mustache__section_stack_frame_s *)section;
450
- while (f->frame) {
451
- --f;
452
- if (tmp.udata1 != f->sec.udata1 || tmp.udata2 != f->sec.udata2)
453
- return &f->sec;
454
- }
455
- return NULL;
456
- }
457
-
458
- /**
459
- * Returns the section's unparsed content as a non-NUL terminated byte array.
460
- *
461
- * The length of the data will be placed in the `size_t` variable pointed to by
462
- * `p_len`. Do NOT use `strlen`, since the data isn't NUL terminated.
463
- *
464
- * This allows text to be accessed when a section's content is, in fact, meant
465
- * to be passed along to a function / lambda.
466
- */
467
- static inline const char *mustache_section_text(mustache_section_s *section,
468
- size_t *p_len) {
469
- if (!section || !p_len)
470
- goto error;
471
- mustache__builder_stack_s *s = mustache___section2stack(section);
472
- mustache__instruction_s *inst =
473
- MUSTACH2INSTRUCTIONS(s->data) + s->pos; /* current instruction*/
474
- if (inst->instruction != MUSTACHE_SECTION_START)
475
- goto error;
476
- const char *start =
477
- MUSTACH2DATA(s->data) + inst->data.name_pos + inst->data.offset;
478
- *p_len = inst->data.len;
479
- return start;
480
- error:
481
- *p_len = 0;
482
- return NULL;
483
- }
484
-
485
- /**
486
- * used internally to write escaped text rather than clear text.
487
- */
488
- static inline int mustache__write_padding(mustache__builder_stack_s *s) {
489
- mustache__instruction_s *const inst = MUSTACH2INSTRUCTIONS(s->data);
490
- char *const data = MUSTACH2DATA(s->data);
491
- for (uint32_t i = s->padding; i; i = inst[i].data.end) {
492
- if (mustache_on_text(&s->stack[s->index].sec, data + inst[i].data.name_pos,
493
- inst[i].data.name_len) == -1)
494
- return -1;
495
- }
496
- return 0;
497
- }
498
-
499
- /**
500
- * used internally to write escaped text rather than clear text.
501
- */
502
- static int mustache__write_escaped(mustache__builder_stack_s *s, char *text,
503
- uint32_t len) {
504
- #define MUSTACHE_ESCAPE_BUFFER_SIZE 4096
505
- /** HTML ecape table, created using the following Ruby Script:
506
-
507
- a = (0..255).to_a.map {|i| i.chr }
508
- 100.times {|i| a[i] = "&\##{i.to_s(10)};"}
509
- ('a'.ord..'z'.ord).each {|i| a[i] = i.chr }
510
- ('A'.ord..'Z'.ord).each {|i| a[i] = i.chr }
511
- ('0'.ord..'9'.ord).each {|i| a[i] = i.chr }
512
- a['<'.ord] = "&lt;"
513
- a['>'.ord] = "&gt;"
514
- a['&'.ord] = "&amp;"
515
- a['"'.ord] = "&quot;"
516
- a["\'".ord] = "&apos;"
517
- a['|'.ord] = "&\##{'|'.ord.to_s(10)};"
518
-
519
- b = a.map {|s| s.length }
520
- puts "static char *html_escape_strs[] = {",
521
- a.to_s.slice(1..-2) ,"};",
522
- "static uint8_t html_escape_len[] = {",
523
- b.to_s.slice(1..-2),"};"
524
- */
525
- static const char *html_escape_strs[] = {
526
- "&#0;", "&#1;", "&#2;", "&#3;", "&#4;", "&#5;", "&#6;", "&#7;",
527
- "&#8;", "&#9;", "&#10;", "&#11;", "&#12;", "&#13;", "&#14;", "&#15;",
528
- "&#16;", "&#17;", "&#18;", "&#19;", "&#20;", "&#21;", "&#22;", "&#23;",
529
- "&#24;", "&#25;", "&#26;", "&#27;", "&#28;", "&#29;", "&#30;", "&#31;",
530
- "&#32;", "&#33;", "&quot;", "&#35;", "&#36;", "&#37;", "&amp;", "&apos;",
531
- "&#40;", "&#41;", "&#42;", "&#43;", "&#44;", "&#45;", "&#46;", "&#47;",
532
- "0", "1", "2", "3", "4", "5", "6", "7",
533
- "8", "9", "&#58;", "&#59;", "&lt;", "&#61;", "&gt;", "&#63;",
534
- "&#64;", "A", "B", "C", "D", "E", "F", "G",
535
- "H", "I", "J", "K", "L", "M", "N", "O",
536
- "P", "Q", "R", "S", "T", "U", "V", "W",
537
- "X", "Y", "Z", "&#91;", "&#92;", "&#93;", "&#94;", "&#95;",
538
- "&#96;", "a", "b", "c", "d", "e", "f", "g",
539
- "h", "i", "j", "k", "l", "m", "n", "o",
540
- "p", "q", "r", "s", "t", "u", "v", "w",
541
- "x", "y", "z", "{", "&#124;", "}", "~", "\x7F",
542
- "\x80", "\x81", "\x82", "\x83", "\x84", "\x85", "\x86", "\x87",
543
- "\x88", "\x89", "\x8A", "\x8B", "\x8C", "\x8D", "\x8E", "\x8F",
544
- "\x90", "\x91", "\x92", "\x93", "\x94", "\x95", "\x96", "\x97",
545
- "\x98", "\x99", "\x9A", "\x9B", "\x9C", "\x9D", "\x9E", "\x9F",
546
- "\xA0", "\xA1", "\xA2", "\xA3", "\xA4", "\xA5", "\xA6", "\xA7",
547
- "\xA8", "\xA9", "\xAA", "\xAB", "\xAC", "\xAD", "\xAE", "\xAF",
548
- "\xB0", "\xB1", "\xB2", "\xB3", "\xB4", "\xB5", "\xB6", "\xB7",
549
- "\xB8", "\xB9", "\xBA", "\xBB", "\xBC", "\xBD", "\xBE", "\xBF",
550
- "\xC0", "\xC1", "\xC2", "\xC3", "\xC4", "\xC5", "\xC6", "\xC7",
551
- "\xC8", "\xC9", "\xCA", "\xCB", "\xCC", "\xCD", "\xCE", "\xCF",
552
- "\xD0", "\xD1", "\xD2", "\xD3", "\xD4", "\xD5", "\xD6", "\xD7",
553
- "\xD8", "\xD9", "\xDA", "\xDB", "\xDC", "\xDD", "\xDE", "\xDF",
554
- "\xE0", "\xE1", "\xE2", "\xE3", "\xE4", "\xE5", "\xE6", "\xE7",
555
- "\xE8", "\xE9", "\xEA", "\xEB", "\xEC", "\xED", "\xEE", "\xEF",
556
- "\xF0", "\xF1", "\xF2", "\xF3", "\xF4", "\xF5", "\xF6", "\xF7",
557
- "\xF8", "\xF9", "\xFA", "\xFB", "\xFC", "\xFD", "\xFE", "\xFF"};
558
- static const uint8_t html_escape_len[] = {
559
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
560
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5,
561
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 4, 5, 4, 5, 5, 1, 1, 1, 1, 1, 1, 1,
562
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 5, 5, 5,
563
- 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
564
- 1, 1, 1, 1, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
565
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
566
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
567
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
568
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
569
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
570
- char buffer[MUSTACHE_ESCAPE_BUFFER_SIZE];
571
- size_t pos = 0;
572
- const char *end = text + len;
573
- while (text < end) {
574
- if (MUSTACHE_USE_DYNAMIC_PADDING && *text == '\n' && s->padding) {
575
- buffer[pos++] = '\n';
576
- buffer[pos] = 0;
577
- if (mustache_on_text(&s->stack[s->index].sec, buffer, pos) == -1)
578
- return -1;
579
- pos = 0;
580
- if (mustache__write_padding(s) == -1)
581
- return -1;
582
- } else {
583
- memcpy(buffer + pos, html_escape_strs[(uint8_t)text[0]],
584
- html_escape_len[(uint8_t)text[0]]);
585
- pos += html_escape_len[(uint8_t)text[0]];
586
- if (pos >= (MUSTACHE_ESCAPE_BUFFER_SIZE - 6)) {
587
- buffer[pos] = 0;
588
- if (mustache_on_text(&s->stack[s->index].sec, buffer, pos) == -1)
589
- return -1;
590
- pos = 0;
591
- }
592
- }
593
- ++text;
594
- }
595
- if (pos) {
596
- buffer[pos] = 0;
597
- if (mustache_on_text(&s->stack[s->index].sec, buffer, pos) == -1)
598
- return -1;
599
- }
600
- return 0;
601
- #undef MUSTACHE_ESCAPE_BUFFER_SIZE
602
- }
603
- /**
604
- * This helper function should be used to write text to the output
605
- * stream (often used within the `mustache_on_arg` callback).
606
- */
607
- static inline int mustache_write_text(mustache_section_s *section, char *text,
608
- uint32_t len, uint8_t escape) {
609
- mustache__builder_stack_s *s = mustache___section2stack(section);
610
- if (escape)
611
- return mustache__write_escaped(s, text, len);
612
- /* TODO */
613
- #if MUSTACHE_USE_DYNAMIC_PADDING
614
- char *end = memchr(text, '\n', len);
615
- while (len && end) {
616
- ++end;
617
- const uint32_t slice_len = end - text;
618
- if (mustache_on_text(&s->stack[s->index].sec, text, slice_len) == -1)
619
- return -1;
620
- text = end;
621
- len -= slice_len;
622
- end = memchr(text, '\n', len);
623
- if (mustache__write_padding(s) == -1)
624
- return -1;
625
- }
626
- if (len && mustache_on_text(&s->stack[s->index].sec, text, len) == -1)
627
- return -1;
628
- #else
629
- if (mustache_on_text(&s->stack[s->index].sec, text, len) == -1)
630
- return -1;
631
-
632
- #endif
633
- return 0;
634
- }
635
-
636
- /* *****************************************************************************
637
- Internal Helpers
638
- ***************************************************************************** */
639
-
640
- /* the data segment's new length after loading the the template */
641
- /* The data segments includes a template header: */
642
- /* | 4 bytes template start instruction position | */
643
- /* | 2 bytes template name | 4 bytes next template position | */
644
- /* | template name (filename) | ...[template data]... */
645
- /* this allows template data to be reused when repeating a template */
646
-
647
- /** a template file data segment header */
648
- typedef struct {
649
- const char *filename; /* template file name */
650
- uint32_t inst_start; /* start position for instructions */
651
- uint32_t next; /* next template position (absolute) */
652
- uint16_t filename_len; /* file name length */
653
- uint16_t path_len; /* if the file is in a folder, this marks the '/' */
654
- } mustache__data_segment_s;
655
-
656
- /* data segment serialization, returns the number of bytes written. */
657
- static inline size_t
658
- mustache__data_segment_write(uint8_t *dest, mustache__data_segment_s data) {
659
- dest[0] = 0xFF & data.inst_start;
660
- dest[1] = 0xFF & (data.inst_start >> 1);
661
- dest[2] = 0xFF & (data.inst_start >> 2);
662
- dest[3] = 0xFF & (data.inst_start >> 3);
663
- dest[4] = 0xFF & data.next;
664
- dest[5] = 0xFF & (data.next >> 1);
665
- dest[6] = 0xFF & (data.next >> 2);
666
- dest[7] = 0xFF & (data.next >> 3);
667
- dest[8] = 0xFF & data.filename_len;
668
- dest[9] = 0xFF & (data.filename_len >> 1);
669
- dest[10] = 0xFF & data.path_len;
670
- dest[11] = 0xFF & (data.path_len >> 1);
671
- if (data.filename_len)
672
- memcpy(dest + 12, data.filename, data.filename_len);
673
- (dest + 12)[data.filename_len] = 0;
674
- return 13 + data.filename_len;
675
- }
676
-
677
- static inline size_t mustache__data_segment_length(size_t filename_len) {
678
- return 13 + filename_len;
679
- }
680
-
681
- /* data segment serialization, reads data from raw stream. */
682
- static inline mustache__data_segment_s
683
- mustache__data_segment_read(uint8_t *data) {
684
- mustache__data_segment_s s = {
685
- .filename = (char *)(data + 12),
686
- .inst_start = ((uint32_t)data[0] | ((uint32_t)data[1] << 1) |
687
- ((uint32_t)data[2] << 2) | ((uint32_t)data[3] << 3)),
688
- .next = ((uint32_t)data[4] | ((uint32_t)data[5] << 1) |
689
- ((uint32_t)data[6] << 2) | ((uint32_t)data[7] << 3)),
690
- .filename_len = ((uint16_t)data[8] | ((uint16_t)data[9] << 1)),
691
- .path_len = ((uint16_t)data[10] | ((uint16_t)data[11] << 1)),
692
- };
693
- return s;
694
- }
695
-
696
- static inline void mustache__stand_alone_adjust(mustache__loader_stack_s *s,
697
- uint32_t stand_alone) {
698
- if (!stand_alone)
699
- return;
700
- /* adjust reading position */
701
- s->stack[s->index].data_pos +=
702
- 1 + (s->data[s->stack[s->index].data_pos] == '\r');
703
- /* remove any padding from the beginning of the line */
704
- if (s->m->u.read_only.intruction_count &&
705
- s->i[s->m->u.read_only.intruction_count - 1].instruction ==
706
- MUSTACHE_WRITE_TEXT) {
707
- mustache__instruction_s *ins =
708
- s->i + s->m->u.read_only.intruction_count - 1;
709
- if (ins->data.name_len <= (stand_alone >> 1))
710
- --s->m->u.read_only.intruction_count;
711
- else
712
- ins->data.name_len -= (stand_alone >> 1);
713
- }
714
- }
715
-
716
- /* pushes an instruction to the instruction array */
717
- static inline int mustache__instruction_push(mustache__loader_stack_s *s,
718
- mustache__instruction_s inst) {
719
- if (s->m->u.read_only.intruction_count >= INT32_MAX)
720
- goto instructions_too_long;
721
- if (s->i_capa <= s->m->u.read_only.intruction_count) {
722
- s->m = realloc(s->m, sizeof(*s->m) + (sizeof(*s->i) * (s->i_capa + 32)));
723
- MUSTACHE_ASSERT(s->m, "Mustache memory allocation failed");
724
- s->i_capa += 32;
725
- s->i = MUSTACH2INSTRUCTIONS(s->m);
726
- }
727
- s->i[s->m->u.read_only.intruction_count] = inst;
728
- ++s->m->u.read_only.intruction_count;
729
- return 0;
730
- instructions_too_long:
731
- *s->err = MUSTACHE_ERR_TOO_DEEP;
732
- return -1;
733
- }
734
-
735
- /* pushes text and padding instruction to the instruction array */
736
- static inline int mustache__push_text_instruction(mustache__loader_stack_s *s,
737
- uint32_t pos, uint32_t len) {
738
- /* always push padding instructions, in case or recursion with padding */
739
- // if (!s->padding) {
740
- // /* no padding, push text, as is */
741
- // return mustache__instruction_push(
742
- // s, (mustache__instruction_s){
743
- // .instruction = MUSTACHE_WRITE_TEXT,
744
- // .data = {.name_pos = pos, .name_len = len},
745
- // });
746
- // }
747
- /* insert padding instruction after each new line */
748
- for (;;) {
749
- /* seek new line markers */
750
- char *start = s->data + pos;
751
- char *end = memchr(s->data + pos, '\n', len);
752
- if (!end)
753
- break;
754
- /* offset marks the line's length */
755
- const size_t offset = (end - start) + 1;
756
- /* push text and padding instructions */
757
- if (mustache__instruction_push(
758
- s,
759
- (mustache__instruction_s){
760
- .instruction = MUSTACHE_WRITE_TEXT,
761
- .data = {.name_pos = pos, .name_len = offset},
762
- }) == -1 ||
763
- mustache__instruction_push(s, (mustache__instruction_s){
764
- .instruction = MUSTACHE_PADDING_WRITE,
765
- }) == -1)
766
- return -1;
767
- pos += offset;
768
- len -= offset;
769
- }
770
- /* done? */
771
- if (!len)
772
- return 0;
773
- /* write any text that doesn't terminate in the EOL marker */
774
- return mustache__instruction_push(
775
- s, (mustache__instruction_s){
776
- .instruction = MUSTACHE_WRITE_TEXT,
777
- .data = {.name_pos = pos, .name_len = len},
778
- });
779
- }
780
-
781
- /*
782
- * Returns the instruction's position if the template is already existing.
783
- *
784
- * Returns `(uint32_t)-1` if the template is missing (not loaded, yet).
785
- */
786
- static inline uint32_t mustache__file_is_loaded(mustache__loader_stack_s *s,
787
- char *name, size_t name_len) {
788
- char *data = s->data;
789
- const char *end = data + s->m->u.read_only.data_length;
790
- while (data < end) {
791
- mustache__data_segment_s seg = mustache__data_segment_read((uint8_t *)data);
792
- if (seg.filename_len == name_len && !memcmp(seg.filename, name, name_len))
793
- return seg.inst_start;
794
- data += seg.next;
795
- }
796
- return (uint32_t)-1;
797
- }
798
-
799
- static inline ssize_t mustache__load_data(mustache__loader_stack_s *s,
800
- const char *name, size_t name_len,
801
- const char *data, size_t data_len) {
802
- const size_t old_len = s->data_len;
803
- if (old_len + data_len > UINT32_MAX)
804
- goto too_long;
805
- s->data = realloc(s->data, old_len + data_len +
806
- mustache__data_segment_length(name_len) + 1);
807
- MUSTACHE_ASSERT(s->data,
808
- "failed to allocate memory for mustache template data");
809
- size_t path_len = name_len;
810
- while (path_len) {
811
- --path_len;
812
- if (name[path_len] == '/' || name[path_len] == '\\') {
813
- ++path_len;
814
- break;
815
- }
816
- }
817
- mustache__data_segment_write(
818
- (uint8_t *)s->data + old_len,
819
- (mustache__data_segment_s){
820
- .filename = name,
821
- .filename_len = name_len,
822
- .inst_start = s->m->u.read_only.intruction_count,
823
- .next =
824
- s->data_len + data_len + mustache__data_segment_length(name_len),
825
- .path_len = path_len,
826
- });
827
- if (data) {
828
- memcpy(s->data + old_len + mustache__data_segment_length(name_len), data,
829
- data_len);
830
- }
831
- s->data_len += data_len + mustache__data_segment_length(name_len);
832
- s->data[s->data_len] = 0;
833
- s->m->u.read_only.data_length = s->data_len;
834
-
835
- mustache__instruction_push(
836
- s, (mustache__instruction_s){.instruction = MUSTACHE_SECTION_START});
837
- /* advance stack frame */
838
- ++s->index;
839
- if (s->index >= MUSTACHE_NESTING_LIMIT)
840
- goto too_long;
841
- s->stack[s->index].data_pos =
842
- old_len + mustache__data_segment_length(name_len);
843
- s->stack[s->index].data_start = old_len;
844
- s->stack[s->index].data_end = s->data_len;
845
- /* reset delimiters */
846
- s->stack[s->index].del_start_len = 2;
847
- s->stack[s->index].del_end_len = 2;
848
- s->stack[s->index].del_start[0] = s->stack[s->index].del_start[1] = '{';
849
- s->stack[s->index].del_start[2] = 0;
850
- s->stack[s->index].del_end[0] = s->stack[s->index].del_end[1] = '}';
851
- s->stack[s->index].del_end[2] = 0;
852
- s->stack[s->index].open_sections = 0;
853
- return data_len;
854
- too_long:
855
- *s->err = MUSTACHE_ERR_TOO_DEEP;
856
- return -1;
857
- }
858
-
859
- static inline ssize_t mustache__load_file(mustache__loader_stack_s *s,
860
- const char *name, size_t name_len) {
861
- struct stat f_data;
862
- uint16_t i = s->index;
863
- uint32_t old_path_len = 0;
864
- if (!name_len) {
865
- goto name_missing_error;
866
- }
867
- if (name_len >= 8192)
868
- goto name_length_error;
869
- /* test file names by walking the stack backwards and matching paths */
870
- do {
871
- mustache__data_segment_s seg;
872
- if (s->data)
873
- seg = mustache__data_segment_read((uint8_t *)s->data +
874
- s->stack[i].data_start);
875
- else
876
- seg = (mustache__data_segment_s){
877
- .path_len = 0,
878
- };
879
- /* did we test this path for the file? */
880
- if (old_path_len && (old_path_len == seg.path_len &&
881
- !memcmp(s->path, seg.filename, old_path_len))) {
882
- continue;
883
- }
884
- old_path_len = seg.path_len;
885
- /* make sure s->path capacity is enough. */
886
- if (s->path_capa < seg.path_len + name_len + 10) {
887
- s->path = realloc(s->path, seg.path_len + name_len + 10);
888
- MUSTACHE_ASSERT(s->path,
889
- "failed to allocate memory for mustache template data");
890
- s->path_capa = seg.path_len + name_len + 10;
891
- }
892
- /* if testing local folder, there's no need to keep looping */
893
- if (!seg.path_len) {
894
- i = 1;
895
- } else {
896
- memcpy(s->path, seg.filename, seg.path_len);
897
- }
898
- /* copy name to path */
899
- memcpy(s->path + seg.path_len, name, name_len);
900
- s->path[name_len + seg.path_len] = 0;
901
- /* test if file exists */
902
- if (!stat(s->path, &f_data) && S_ISREG(f_data.st_mode)) {
903
- old_path_len = name_len + seg.path_len;
904
- goto file_found;
905
- }
906
- /* add default extension */
907
- memcpy(s->path + seg.path_len + name_len, ".mustache", 9);
908
- s->path[name_len + seg.path_len + 9] = 0;
909
- /* test if new filename file exists */
910
- if (!stat(s->path, &f_data) && S_ISREG(f_data.st_mode)) {
911
- old_path_len = name_len + seg.path_len + 9;
912
- goto file_found;
913
- }
914
- } while (--i);
915
-
916
- /* test if the file is "virtual" (only true for the first template loaded) */
917
- if (s->data) {
918
- mustache__data_segment_s seg =
919
- mustache__data_segment_read((uint8_t *)s->data);
920
- if (seg.filename_len == name_len && !memcmp(seg.filename, name, name_len)) {
921
- /* this name points to the original (root) template, and it's virtual */
922
- if (mustache__instruction_push(
923
- s, (mustache__instruction_s){
924
- .instruction = MUSTACHE_SECTION_GOTO,
925
- .data =
926
- {
927
- .len = 0,
928
- .end = s->m->u.read_only.intruction_count,
929
- },
930
- }))
931
- goto unknown_error;
932
- return 0;
933
- }
934
- }
935
-
936
- #if MUSTACHE_FAIL_ON_MISSING_TEMPLATE
937
- *s->err = MUSTACHE_ERR_FILE_NOT_FOUND;
938
- return -1;
939
- #else
940
- return 0;
941
- #endif
942
-
943
- file_found:
944
- if (f_data.st_size >= INT32_MAX) {
945
- goto file_too_big;
946
- } else if (f_data.st_size == 0) {
947
- /* empty, do nothing */
948
- return 0;
949
- } else {
950
- /* test if the file was previously loaded */
951
- uint32_t pre_existing = mustache__file_is_loaded(s, s->path, old_path_len);
952
- if (pre_existing != (uint32_t)-1) {
953
- if (mustache__instruction_push(
954
- s, (mustache__instruction_s){
955
- .instruction = MUSTACHE_SECTION_GOTO,
956
- .data =
957
- {
958
- .len = pre_existing,
959
- .end = s->m->u.read_only.intruction_count,
960
- },
961
- })) {
962
- goto unknown_error;
963
- }
964
- return 0;
965
- }
966
- }
967
- if (mustache__load_data(s, s->path, old_path_len, NULL, f_data.st_size) == -1)
968
- goto unknown_error;
969
- int fd = open(s->path, O_RDONLY);
970
- if (fd == -1)
971
- goto file_err;
972
- if (pread(fd, s->data + s->data_len - f_data.st_size, f_data.st_size, 0) !=
973
- f_data.st_size)
974
- goto file_err;
975
- close(fd);
976
- return f_data.st_size;
977
-
978
- name_missing_error:
979
- *s->err = MUSTACHE_ERR_FILE_NAME_TOO_SHORT;
980
- return -1;
981
-
982
- name_length_error:
983
- *s->err = MUSTACHE_ERR_FILE_NAME_TOO_LONG;
984
- return -1;
985
-
986
- file_too_big:
987
- *s->err = MUSTACHE_ERR_FILE_TOO_BIG;
988
- return -1;
989
-
990
- file_err:
991
- *s->err = MUSTACHE_ERR_UNKNOWN;
992
- return -1;
993
-
994
- unknown_error:
995
- return -1;
996
- }
997
-
998
- /* *****************************************************************************
999
- Calling the instrustion list (using the template engine)
1000
- ***************************************************************************** */
1001
-
1002
- /*
1003
- * This function reviews the instructions listed at the end of the mustache_s
1004
- * and performs any callbacks necessary.
1005
- *
1006
- * The `mustache_s` data is looks like this:
1007
- *
1008
- * - header (the `mustache_s` struct): lists the length of the instruction
1009
- * array and data segments.
1010
- * - Instruction array: lists all the instructions extracted from the
1011
- * template(s) (an array of `mustache__instruction_s`).
1012
- * - Data segment: text and data related to the instructions.
1013
- *
1014
- * The instructions, much like machine code, might loop or jump. This is why the
1015
- * function keeps a stack of sorts. This allows the code to avoid recursion and
1016
- * minimize any risk of stack overflow caused by recursive templates.
1017
- */
1018
- MUSTACHE_FUNC int(mustache_build)(mustache_build_args_s args) {
1019
- mustache_error_en err_if_missing;
1020
- if (!args.err)
1021
- args.err = &err_if_missing;
1022
- if (!args.mustache) {
1023
- goto user_error;
1024
- }
1025
- /* extract the instruction array and data segment from the mustache_s */
1026
- mustache__instruction_s *instructions = MUSTACH2INSTRUCTIONS(args.mustache);
1027
- char *const data = MUSTACH2DATA(args.mustache);
1028
- mustache__builder_stack_s s;
1029
- s.data = args.mustache;
1030
- s.pos = 0;
1031
- s.index = 0;
1032
- s.padding = 0;
1033
- s.stack[0] = (mustache__section_stack_frame_s){
1034
- .sec =
1035
- {
1036
- .udata1 = args.udata1,
1037
- .udata2 = args.udata2,
1038
- },
1039
- .start = 0,
1040
- .end = instructions[0].data.end,
1041
- .index = 0,
1042
- .count = 0,
1043
- .frame = 0,
1044
- };
1045
- while ((uintptr_t)(instructions + s.pos) < (uintptr_t)data) {
1046
- switch (instructions[s.pos].instruction) {
1047
- case MUSTACHE_WRITE_TEXT:
1048
- if (mustache_on_text(&s.stack[s.index].sec,
1049
- data + instructions[s.pos].data.name_pos,
1050
- instructions[s.pos].data.name_len))
1051
- goto user_error;
1052
- break;
1053
- /* fallthrough */
1054
- case MUSTACHE_WRITE_ARG:
1055
- if (mustache_on_arg(&s.stack[s.index].sec,
1056
- data + instructions[s.pos].data.name_pos,
1057
- instructions[s.pos].data.name_len, 1))
1058
- goto user_error;
1059
- break;
1060
- case MUSTACHE_WRITE_ARG_UNESCAPED:
1061
- if (mustache_on_arg(&s.stack[s.index].sec,
1062
- data + instructions[s.pos].data.name_pos,
1063
- instructions[s.pos].data.name_len, 0))
1064
- goto user_error;
1065
- break;
1066
- /* fallthrough */
1067
- case MUSTACHE_SECTION_GOTO:
1068
- /* fallthrough */
1069
- case MUSTACHE_SECTION_START:
1070
- case MUSTACHE_SECTION_START_INV:
1071
- /* advance stack*/
1072
- if (s.index + 1 >= MUSTACHE_NESTING_LIMIT) {
1073
- if (args.err)
1074
- *args.err = MUSTACHE_ERR_TOO_DEEP;
1075
- goto error;
1076
- }
1077
- s.stack[s.index + 1].sec = s.stack[s.index].sec;
1078
- ++s.index;
1079
- s.stack[s.index].start =
1080
- (instructions[s.pos].instruction == MUSTACHE_SECTION_GOTO
1081
- ? instructions[s.pos].data.len
1082
- : s.pos);
1083
- s.stack[s.index].end = instructions[s.pos].data.end;
1084
- s.stack[s.index].frame = s.index;
1085
- s.stack[s.index].index = 0;
1086
- s.stack[s.index].count = 1;
1087
-
1088
- /* test section count */
1089
- if (instructions[s.pos].data.name_pos) {
1090
- /* this is a named section, it should be tested against user data */
1091
- int32_t val = mustache_on_section_test(
1092
- &s.stack[s.index].sec, data + instructions[s.pos].data.name_pos,
1093
- instructions[s.pos].data.name_len,
1094
- instructions[s.pos].instruction == MUSTACHE_SECTION_START);
1095
- if (val == -1) {
1096
- goto user_error;
1097
- }
1098
- if (instructions[s.pos].instruction == MUSTACHE_SECTION_START_INV) {
1099
- /* invert test */
1100
- val = (val == 0);
1101
- }
1102
- s.stack[s.index].count = (uint32_t)val;
1103
- }
1104
- /* fallthrough */
1105
- case MUSTACHE_SECTION_END:
1106
- /* loop section or continue */
1107
- if (s.stack[s.index].index < s.stack[s.index].count) {
1108
- /* repeat / start section */
1109
- s.pos = s.stack[s.index].start;
1110
- s.stack[s.index].sec = s.stack[s.index - 1].sec;
1111
- /* review user callback (if it's a named section) */
1112
- if (instructions[s.pos].data.name_pos &&
1113
- mustache_on_section_start(&s.stack[s.index].sec,
1114
- data + instructions[s.pos].data.name_pos,
1115
- instructions[s.pos].data.name_len,
1116
- s.stack[s.index].index) == -1)
1117
- goto user_error;
1118
- /* skip padding instructions in GOTO tags (recursive partials) */
1119
- if (instructions[s.pos].instruction == MUSTACHE_SECTION_GOTO)
1120
- ++s.pos;
1121
- ++s.stack[s.index].index;
1122
- break;
1123
- }
1124
- s.pos = s.stack[s.index].end;
1125
- --s.index;
1126
- break;
1127
- case MUSTACHE_PADDING_PUSH:
1128
- s.padding = s.pos;
1129
- break;
1130
- case MUSTACHE_PADDING_POP:
1131
- s.padding = instructions[s.padding].data.end;
1132
- break;
1133
- case MUSTACHE_PADDING_WRITE:
1134
- for (uint32_t i = s.padding; i; i = instructions[i].data.end) {
1135
- if (mustache_on_text(&s.stack[s.index].sec,
1136
- data + instructions[i].data.name_pos,
1137
- instructions[i].data.name_len))
1138
- goto user_error;
1139
- }
1140
- break;
1141
- default:
1142
- /* not a valid engine */
1143
- fprintf(stderr, "ERROR: invalid mustache instruction set detected (wrong "
1144
- "`mustache_s`?)\n");
1145
- if (args.err) {
1146
- *args.err = MUSTACHE_ERR_UNKNOWN;
1147
- }
1148
- goto error;
1149
- }
1150
- ++s.pos;
1151
- }
1152
- *args.err = MUSTACHE_OK;
1153
- return 0;
1154
- user_error:
1155
- *args.err = MUSTACHE_ERR_USER_ERROR;
1156
- error:
1157
- mustache_on_formatting_error(args.udata1, args.udata2);
1158
- return -1;
1159
- }
1160
-
1161
- /* *****************************************************************************
1162
- Building the instrustion list (parsing the template)
1163
- ***************************************************************************** */
1164
-
1165
- /* The parsing implementation, converts a template to an instruction array */
1166
- MUSTACHE_FUNC mustache_s *(mustache_load)(mustache_load_args_s args) {
1167
- mustache_error_en err_if_missing;
1168
- mustache__loader_stack_s s;
1169
- uint8_t flag = 0;
1170
-
1171
- if (!args.err)
1172
- args.err = &err_if_missing;
1173
- s.path_capa = 0;
1174
- s.path = NULL;
1175
- s.data = NULL;
1176
- s.data_len = 0;
1177
- s.i = NULL;
1178
- s.i_capa = 32;
1179
- s.index = 0;
1180
- s.padding = 0;
1181
- s.m = malloc(sizeof(*s.m) + (sizeof(*s.i) * 32));
1182
- MUSTACHE_ASSERT(s.m, "failed to allocate memory for mustache data");
1183
- s.m->u.read_only_pt = 0;
1184
- s.m->u.read_only.data_length = 0;
1185
- s.m->u.read_only.intruction_count = 0;
1186
- s.i = MUSTACH2INSTRUCTIONS(s.m);
1187
- s.err = args.err;
1188
-
1189
- if (!args.filename_len && args.filename)
1190
- args.filename_len = strlen(args.filename);
1191
-
1192
- if (args.data) {
1193
- if (mustache__load_data(&s, args.filename, args.filename_len, args.data,
1194
- args.data_len) == -1) {
1195
- goto error;
1196
- }
1197
- } else {
1198
- if (mustache__load_file(&s, args.filename, args.filename_len) == -1) {
1199
- goto error;
1200
- }
1201
- }
1202
-
1203
- /* loop while there are templates to be parsed on the stack */
1204
- while (s.index) {
1205
- /* parsing loop */
1206
- while (s.stack[s.index].data_pos < s.stack[s.index].data_end) {
1207
- /* stand-alone tag flag, also containes padding length after bit 1 */
1208
- uint32_t stand_alone = 0;
1209
- uint32_t stand_alone_pos = 0;
1210
- /* start parsing at current position */
1211
- const char *start = s.data + s.stack[s.index].data_pos;
1212
- /* find the next instruction (beg == beginning) */
1213
- char *beg = strstr(start, s.stack[s.index].del_start);
1214
- const char *org_beg = beg;
1215
- if (!beg || beg >= s.data + s.stack[s.index].data_end) {
1216
- /* no instructions left, only text */
1217
- mustache__push_text_instruction(&s, s.stack[s.index].data_pos,
1218
- s.stack[s.index].data_end -
1219
- s.stack[s.index].data_pos);
1220
- s.stack[s.index].data_pos = s.stack[s.index].data_end;
1221
- continue;
1222
- }
1223
- if (beg != start) {
1224
- /* there's text before the instruction */
1225
- mustache__push_text_instruction(&s, s.stack[s.index].data_pos,
1226
- (uint32_t)(uintptr_t)(beg - start));
1227
- }
1228
- /* move beg (reading position) after the delimiter */
1229
- beg += s.stack[s.index].del_start_len;
1230
- /* seek the end of the instruction delimiter */
1231
- char *end = strstr(beg, s.stack[s.index].del_end);
1232
- if (!end || end >= s.data + s.stack[s.index].data_end) {
1233
- /* delimiter not closed */
1234
- *args.err = MUSTACHE_ERR_CLOSURE_MISMATCH;
1235
- goto error;
1236
- }
1237
-
1238
- /* update reading position in the stack */
1239
- s.stack[s.index].data_pos = (end - s.data) + s.stack[s.index].del_end_len;
1240
-
1241
- /* Test for stand-alone tags */
1242
- if (!end[s.stack[s.index].del_end_len] ||
1243
- end[s.stack[s.index].del_end_len] == '\n' ||
1244
- (end[s.stack[s.index].del_end_len] == '\r' &&
1245
- end[1 + s.stack[s.index].del_end_len] == '\n')) {
1246
- char *pad = beg - (s.stack[s.index].del_start_len + 1);
1247
- while (pad >= start && (pad[0] == ' ' || pad[0] == '\t'))
1248
- --pad;
1249
- if (pad[0] == '\n' || pad[0] == 0) {
1250
- /* Yes, this a stand-alone tag, store padding length + flag */
1251
- ++pad;
1252
- stand_alone_pos = pad - s.data;
1253
- stand_alone =
1254
- ((beg - (pad + s.stack[s.index].del_start_len)) << 1) | 1;
1255
- }
1256
- }
1257
-
1258
- /* parse instruction content */
1259
- flag = 1;
1260
-
1261
- switch (beg[0]) {
1262
- case '!':
1263
- /* comment, do nothing... almost */
1264
- mustache__stand_alone_adjust(&s, stand_alone);
1265
- break;
1266
-
1267
- case '=':
1268
- /* define new seperators */
1269
- mustache__stand_alone_adjust(&s, stand_alone);
1270
- ++beg;
1271
- --end;
1272
- if (end[0] != '=') {
1273
- *args.err = MUSTACHE_ERR_CLOSURE_MISMATCH;
1274
- goto error;
1275
- }
1276
- --end;
1277
- MUSTACHE_IGNORE_WHITESPACE(beg, 1);
1278
- MUSTACHE_IGNORE_WHITESPACE(end, -1);
1279
- ++end;
1280
- {
1281
- char *div = beg;
1282
- while (div < end && !isspace(*div)) {
1283
- ++div;
1284
- }
1285
- if (div == end || div == beg) {
1286
- *args.err = MUSTACHE_ERR_CLOSURE_MISMATCH;
1287
- goto error;
1288
- }
1289
- if (div - beg >= MUSTACHE_DELIMITER_LENGTH_LIMIT) {
1290
- *args.err = MUSTACHE_ERR_DELIMITER_TOO_LONG;
1291
- goto error;
1292
- }
1293
- /* copy starting delimiter */
1294
- s.stack[s.index].del_start_len = div - beg;
1295
- for (size_t i = 0; i < s.stack[s.index].del_start_len; ++i) {
1296
- s.stack[s.index].del_start[i] = beg[i];
1297
- }
1298
- s.stack[s.index].del_start[s.stack[s.index].del_start_len] = 0;
1299
-
1300
- ++div;
1301
- MUSTACHE_IGNORE_WHITESPACE(div, 1);
1302
- if (div == end) {
1303
- *args.err = MUSTACHE_ERR_CLOSURE_MISMATCH;
1304
- goto error;
1305
- }
1306
- if (end - div >= MUSTACHE_DELIMITER_LENGTH_LIMIT) {
1307
- *args.err = MUSTACHE_ERR_DELIMITER_TOO_LONG;
1308
- goto error;
1309
- }
1310
- /* copy ending delimiter */
1311
- s.stack[s.index].del_end_len = end - div;
1312
- for (size_t i = 0; i < s.stack[s.index].del_end_len; ++i) {
1313
- s.stack[s.index].del_end[i] = div[i];
1314
- }
1315
- s.stack[s.index].del_end[s.stack[s.index].del_end_len] = 0;
1316
- }
1317
- break;
1318
-
1319
- case '^':
1320
- /* start inverted section */
1321
- flag = 0;
1322
- /* fallthrough */
1323
- case '#':
1324
- /* start section (or inverted section) */
1325
- mustache__stand_alone_adjust(&s, stand_alone);
1326
- ++beg;
1327
- --end;
1328
- MUSTACHE_IGNORE_WHITESPACE(beg, 1);
1329
- MUSTACHE_IGNORE_WHITESPACE(end, -1);
1330
- ++end;
1331
-
1332
- ++s.stack[s.index].open_sections;
1333
- if (s.stack[s.index].open_sections >= MUSTACHE_NESTING_LIMIT) {
1334
- *args.err = MUSTACHE_ERR_TOO_DEEP;
1335
- goto error;
1336
- }
1337
- if (beg - s.data >= UINT16_MAX) {
1338
- *args.err = MUSTACHE_ERR_NAME_TOO_LONG;
1339
- }
1340
- if (mustache__instruction_push(
1341
- &s,
1342
- (mustache__instruction_s){
1343
- .instruction = (flag ? MUSTACHE_SECTION_START
1344
- : MUSTACHE_SECTION_START_INV),
1345
- .data = {
1346
- .name_pos = beg - s.data,
1347
- .name_len = end - beg,
1348
- .offset = s.stack[s.index].data_pos - (beg - s.data),
1349
- }})) {
1350
- goto error;
1351
- }
1352
- break;
1353
-
1354
- case '>':
1355
- /* partial template - search data for loaded template or load new */
1356
- mustache__stand_alone_adjust(&s, stand_alone);
1357
- if ((stand_alone >> 1)) {
1358
- /* TODO: add padding markers */
1359
- if (mustache__instruction_push(
1360
- &s, (mustache__instruction_s){
1361
- .instruction = MUSTACHE_PADDING_PUSH,
1362
- .data = {
1363
- .name_pos = stand_alone_pos,
1364
- .name_len = (stand_alone >> 1),
1365
- .end = s.padding,
1366
- }})) {
1367
- goto error;
1368
- }
1369
- s.padding = s.m->u.read_only.intruction_count - 1;
1370
- }
1371
- ++beg;
1372
- --end;
1373
- MUSTACHE_IGNORE_WHITESPACE(beg, 1);
1374
- MUSTACHE_IGNORE_WHITESPACE(end, -1);
1375
- ++end;
1376
- ssize_t loaded = mustache__load_file(&s, beg, end - beg);
1377
- if (loaded == -1)
1378
- goto error;
1379
- /* Add latest padding section to text */
1380
- if ((stand_alone >> 1)) {
1381
- if (loaded)
1382
- mustache__instruction_push(
1383
- &s, (mustache__instruction_s){
1384
- .instruction = MUSTACHE_WRITE_TEXT,
1385
- .data =
1386
- {
1387
- .name_pos = stand_alone_pos,
1388
- .name_len = (stand_alone >> 1),
1389
- },
1390
- });
1391
- else if (mustache__instruction_push(
1392
- &s, (mustache__instruction_s){.instruction =
1393
- MUSTACHE_PADDING_POP}))
1394
- goto error;
1395
- }
1396
- break;
1397
-
1398
- case '/':
1399
- /* section end */
1400
- mustache__stand_alone_adjust(&s, stand_alone);
1401
- ++beg;
1402
- --end;
1403
- MUSTACHE_IGNORE_WHITESPACE(beg, 1);
1404
- MUSTACHE_IGNORE_WHITESPACE(end, -1);
1405
- ++end;
1406
- if (!s.stack[s.index].open_sections) {
1407
- *args.err = MUSTACHE_ERR_CLOSURE_MISMATCH;
1408
- goto error;
1409
- } else {
1410
- uint32_t pos = s.m->u.read_only.intruction_count;
1411
- uint32_t nested = 0;
1412
- do {
1413
- --pos;
1414
- if (s.i[pos].instruction == MUSTACHE_SECTION_END)
1415
- ++nested;
1416
- else if (s.i[pos].instruction == MUSTACHE_SECTION_START ||
1417
- s.i[pos].instruction == MUSTACHE_SECTION_START_INV) {
1418
- if (nested) {
1419
- --nested;
1420
- } else {
1421
- /* test instruction closure */
1422
- if (s.i[pos].data.name_len != end - beg ||
1423
- memcmp(beg, s.data + s.i[pos].data.name_pos,
1424
- s.i[pos].data.name_len)) {
1425
- *args.err = MUSTACHE_ERR_CLOSURE_MISMATCH;
1426
- goto error;
1427
- }
1428
- /* update initial instruction (do this before adding closure) */
1429
- s.i[pos].data.end = s.m->u.read_only.intruction_count;
1430
- s.i[pos].data.len = org_beg - (s.data + s.i[pos].data.name_pos +
1431
- s.i[pos].data.offset);
1432
- /* add closure instruction */
1433
- mustache__instruction_push(
1434
- &s, (mustache__instruction_s){.instruction =
1435
- MUSTACHE_SECTION_END,
1436
- .data = s.i[pos].data});
1437
- /* update closure count */
1438
- --s.stack[s.index].open_sections;
1439
- /* stop loop */
1440
- pos = 0;
1441
- beg = NULL;
1442
- }
1443
- }
1444
- } while (pos);
1445
- if (beg) {
1446
- *args.err = MUSTACHE_ERR_CLOSURE_MISMATCH;
1447
- goto error;
1448
- }
1449
- }
1450
- break;
1451
-
1452
- case '{':
1453
- /* step the read position forward if the ending was '}}}' */
1454
- if (s.data[s.stack[s.index].data_pos] == '}' &&
1455
- s.stack[s.index].del_end[0] == '}' &&
1456
- s.stack[s.index].del_end[s.stack[s.index].del_end_len - 1] == '}') {
1457
- ++s.stack[s.index].data_pos;
1458
- }
1459
- /* fallthrough */
1460
- case '&':
1461
- /* unescaped variable data */
1462
- flag = 0;
1463
- /* fallthrough */
1464
- case ':': /*fallthrough*/
1465
- case '<': /*fallthrough*/
1466
- ++beg; /*fallthrough*/
1467
- default:
1468
- --end;
1469
- MUSTACHE_IGNORE_WHITESPACE(beg, 1);
1470
- MUSTACHE_IGNORE_WHITESPACE(end, -1);
1471
- ++end;
1472
- mustache__instruction_push(
1473
- &s, (mustache__instruction_s){
1474
- .instruction = (flag ? MUSTACHE_WRITE_ARG
1475
- : MUSTACHE_WRITE_ARG_UNESCAPED),
1476
- .data = {.name_pos = beg - s.data, .name_len = end - beg}});
1477
- break;
1478
- }
1479
- }
1480
- /* make sure all sections were closed */
1481
- if (s.stack[s.index].open_sections) {
1482
- *args.err = MUSTACHE_ERR_CLOSURE_MISMATCH;
1483
- goto error;
1484
- }
1485
- /* move padding from section tail to post closure (adjust for padding
1486
- * changes) */
1487
- flag = 0;
1488
- if (s.m->u.read_only.intruction_count &&
1489
- s.i[s.m->u.read_only.intruction_count - 1].instruction ==
1490
- MUSTACHE_PADDING_WRITE) {
1491
- --s.m->u.read_only.intruction_count;
1492
- flag = 1;
1493
- }
1494
- /* mark section length */
1495
- mustache__data_segment_s seg = mustache__data_segment_read(
1496
- (uint8_t *)s.data + s.stack[s.index].data_start);
1497
- s.i[seg.inst_start].data.end = s.m->u.read_only.intruction_count;
1498
- /* add instruction closure */
1499
- mustache__instruction_push(
1500
- &s, (mustache__instruction_s){.instruction = MUSTACHE_SECTION_END});
1501
- /* TODO: pop any padding (if exists) */
1502
- if (s.padding && s.padding + 1 == seg.inst_start) {
1503
- s.padding = s.i[s.padding].data.end;
1504
- mustache__instruction_push(&s, (mustache__instruction_s){
1505
- .instruction = MUSTACHE_PADDING_POP,
1506
- });
1507
- }
1508
- /* complete padding switch*/
1509
- if (flag) {
1510
- mustache__instruction_push(&s, (mustache__instruction_s){
1511
- .instruction = MUSTACHE_PADDING_WRITE,
1512
- });
1513
- flag = 0;
1514
- }
1515
- /* pop stack */
1516
- --s.index;
1517
- }
1518
-
1519
- s.m = realloc(s.m, sizeof(*s.m) +
1520
- (sizeof(*s.i) * s.m->u.read_only.intruction_count) +
1521
- s.data_len);
1522
- MUSTACHE_ASSERT(s.m,
1523
- "failed to allocate memory for consolidated mustache data");
1524
- memcpy(MUSTACH2DATA(s.m), s.data, s.data_len);
1525
- free(s.data);
1526
- free(s.path);
1527
-
1528
- *args.err = MUSTACHE_OK;
1529
- return s.m;
1530
-
1531
- error:
1532
- free(s.data);
1533
- free(s.path);
1534
- free(s.m);
1535
- return NULL;
1536
- }
1537
-
1538
- #endif /* INCLUDE_MUSTACHE_IMPLEMENTATION */
1539
-
1540
- #undef MUSTACHE_FUNC
1541
- #undef MUSTACH2INSTRUCTIONS
1542
- #undef MUSTACH2DATA
1543
- #undef MUSTACHE_OBJECT_OFFSET
1544
- #undef MUSTACHE_IGNORE_WHITESPACE
1545
-
1546
- #endif /* H_MUSTACHE_LOADR_H */