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,1187 +0,0 @@
1
- #if defined(__unix__) || defined(__APPLE__) || defined(__linux__) || \
2
- defined(__CYGWIN__) || defined(__MINGW32__) /* require POSIX */
3
- /*
4
- Copyright: Boaz Segev, 2017-2019
5
- License: MIT
6
- */
7
- #ifndef _GNU_SOURCE
8
- #define _GNU_SOURCE
9
- #endif
10
-
11
- /**
12
- * A dynamic type for reading / writing to a local file, a temporary file or an
13
- * in-memory string.
14
- *
15
- * Supports basic reak, write, seek, puts and gets operations.
16
- *
17
- * Writing is always performed at the end of the stream / memory buffer,
18
- * ignoring the current seek position.
19
- */
20
- #include <fio_tmpfile.h>
21
- #include <fiobj_data.h>
22
- #include <fiobj_str.h>
23
-
24
- #include <assert.h>
25
- #include <errno.h>
26
- #include <fcntl.h>
27
- #include <string.h>
28
- #include <sys/stat.h>
29
- #include <sys/types.h>
30
- #include <unistd.h>
31
-
32
- #include <fio.h>
33
-
34
- /* *****************************************************************************
35
- Numbers Type
36
- ***************************************************************************** */
37
-
38
- typedef struct {
39
- fiobj_object_header_s head;
40
- uint8_t *buffer; /* reader buffer */
41
- union {
42
- FIOBJ parent;
43
- void (*dealloc)(void *); /* buffer deallocation function */
44
- size_t fpos; /* the file reader's position */
45
- } source;
46
- size_t capa; /* total buffer capacity / slice offset */
47
- size_t len; /* length of valid data in buffer */
48
- size_t pos; /* position of reader */
49
- int fd; /* file descriptor (-1 if invalid). */
50
- } fiobj_data_s;
51
-
52
- #define obj2io(o) ((fiobj_data_s *)(o))
53
-
54
- /* *****************************************************************************
55
- Object required VTable and functions
56
- ***************************************************************************** */
57
-
58
- #define REQUIRE_MEM(mem) \
59
- do { \
60
- if ((mem) == NULL) { \
61
- perror("FATAL ERROR: fiobj IO couldn't allocate memory"); \
62
- exit(errno); \
63
- } \
64
- } while (0)
65
-
66
- static inline int64_t fiobj_data_get_fd_size(const FIOBJ o) {
67
- struct stat stat;
68
- retry:
69
- if (fstat(obj2io(o)->fd, &stat)) {
70
- if (errno == EINTR)
71
- goto retry;
72
- return -1;
73
- }
74
- return stat.st_size;
75
- }
76
-
77
- static void fiobj_data_copy_buffer(FIOBJ o) {
78
- obj2io(o)->capa = (((obj2io(o)->len) >> 12) + 1) << 12;
79
- void *tmp = fio_malloc(obj2io(o)->capa);
80
- REQUIRE_MEM(tmp);
81
- memcpy(tmp, obj2io(o)->buffer, obj2io(o)->len);
82
- if (obj2io(o)->source.dealloc)
83
- obj2io(o)->source.dealloc(obj2io(o)->buffer);
84
- obj2io(o)->source.dealloc = fio_free;
85
- obj2io(o)->buffer = tmp;
86
- }
87
-
88
- static void fiobj_data_copy_parent(FIOBJ o) {
89
- switch (obj2io(obj2io(o)->source.parent)->fd) {
90
- case -1:
91
- obj2io(o)->buffer = fio_malloc(obj2io(o)->len + 1);
92
- FIO_ASSERT_ALLOC(obj2io(o)->buffer);
93
- memcpy(obj2io(o)->buffer,
94
- obj2io(obj2io(o)->source.parent)->buffer + obj2io(o)->capa,
95
- obj2io(o)->len);
96
- obj2io(o)->buffer[obj2io(o)->len] = 0;
97
- obj2io(o)->capa = obj2io(o)->len;
98
- obj2io(o)->fd = -1;
99
- fiobj_free(obj2io(o)->source.parent);
100
- obj2io(o)->source.dealloc = fio_free;
101
- return;
102
- default:
103
- obj2io(o)->fd = fio_tmpfile();
104
- if (obj2io(o)->fd < 0) {
105
- perror("FATAL ERROR: (fiobj_data) can't create temporary file");
106
- exit(errno);
107
- }
108
- fio_str_info_s data;
109
- size_t pos = 0;
110
- do {
111
- ssize_t written;
112
- data = fiobj_data_pread(obj2io(o)->source.parent, pos + obj2io(o)->capa,
113
- 4096);
114
- if (data.len + pos > obj2io(o)->len)
115
- data.len = obj2io(o)->len - pos;
116
- retry_int:
117
- #ifdef __MINGW32__
118
- written = pwrite(obj2io(o)->fd, data.data, data.len, 0);
119
- #else
120
- written = write(obj2io(o)->fd, data.data, data.len);
121
- #endif
122
- if (written < 0) {
123
- if (errno == EINTR)
124
- goto retry_int;
125
- perror("FATAL ERROR: (fiobj_data) can't write to temporary file");
126
- exit(errno);
127
- }
128
- pos += written;
129
- } while (data.len == 4096);
130
- fiobj_free(obj2io(o)->source.parent);
131
- obj2io(o)->capa = 0;
132
- obj2io(o)->len = pos;
133
- obj2io(o)->source.fpos = obj2io(o)->pos;
134
- obj2io(o)->pos = 0;
135
- obj2io(o)->buffer = NULL;
136
- break;
137
- }
138
- }
139
-
140
- static inline void fiobj_data_pre_write(FIOBJ o, uintptr_t length) {
141
- switch (obj2io(o)->fd) {
142
- case -1:
143
- if (obj2io(o)->source.dealloc != fio_free) {
144
- fiobj_data_copy_buffer(o);
145
- }
146
- break;
147
- case -2:
148
- fiobj_data_copy_parent(o);
149
- break;
150
- }
151
- if (obj2io(o)->capa >= obj2io(o)->len + length)
152
- return;
153
- /* add rounded pages (4096) to capacity */
154
- obj2io(o)->capa = (((obj2io(o)->len + length) >> 12) + 1) << 12;
155
- obj2io(o)->buffer = fio_realloc(obj2io(o)->buffer, obj2io(o)->capa);
156
- REQUIRE_MEM(obj2io(o)->buffer);
157
- }
158
-
159
- static FIOBJ fiobj_data_alloc(void *buffer, int fd) {
160
- fiobj_data_s *io = fio_malloc(sizeof(*io));
161
- REQUIRE_MEM(io);
162
- *io = (fiobj_data_s){
163
- .head = {.ref = 1, .type = FIOBJ_T_DATA},
164
- .buffer = buffer,
165
- .fd = fd,
166
- };
167
- return (FIOBJ)io;
168
- }
169
-
170
- static void fiobj_data_dealloc(FIOBJ o, void (*task)(FIOBJ, void *),
171
- void *arg) {
172
- switch (obj2io(o)->fd) {
173
- case -1:
174
- if (obj2io(o)->source.dealloc && obj2io(o)->buffer)
175
- obj2io(o)->source.dealloc(obj2io(o)->buffer);
176
- break;
177
- case -2:
178
- fiobj_free(obj2io(o)->source.parent);
179
- break;
180
- default:
181
- close(obj2io(o)->fd);
182
- fio_free(obj2io(o)->buffer);
183
- break;
184
- }
185
- fio_free((void *)o);
186
- (void)task;
187
- (void)arg;
188
- }
189
-
190
- static intptr_t fiobj_data_i(const FIOBJ o) {
191
- switch (obj2io(o)->fd) {
192
- case -1:
193
- case -2:
194
- return obj2io(o)->len;
195
- break;
196
- default:
197
- return fiobj_data_get_fd_size(o);
198
- }
199
- }
200
-
201
- static size_t fiobj_data_is_true(const FIOBJ o) { return fiobj_data_i(o) > 0; }
202
-
203
- static fio_str_info_s fio_io2str(const FIOBJ o) {
204
- switch (obj2io(o)->fd) {
205
- case -1:
206
- return (fio_str_info_s){.data = (char *)obj2io(o)->buffer,
207
- .len = obj2io(o)->len};
208
- break;
209
- case -2:
210
- return fiobj_data_pread(obj2io(o)->source.parent, obj2io(o)->capa,
211
- obj2io(o)->len);
212
- break;
213
- }
214
- int64_t i = fiobj_data_get_fd_size(o);
215
- if (i <= 0)
216
- return (fio_str_info_s){.data = (char *)obj2io(o)->buffer,
217
- .len = obj2io(o)->len};
218
- obj2io(o)->len = 0;
219
- obj2io(o)->pos = 0;
220
- fiobj_data_pre_write((FIOBJ)o, i + 1);
221
- if (pread(obj2io(o)->fd, obj2io(o)->buffer, i, 0) != i)
222
- return (fio_str_info_s){.data = NULL, .len = 0};
223
- obj2io(o)->buffer[i] = 0;
224
- return (fio_str_info_s){.data = (char *)obj2io(o)->buffer, .len = i};
225
- }
226
-
227
- static size_t fiobj_data_iseq(const FIOBJ self, const FIOBJ other) {
228
- int64_t len;
229
- return ((len = fiobj_data_i(self)) == fiobj_data_i(other) &&
230
- !memcmp(fio_io2str(self).data, fio_io2str(other).data, (size_t)len));
231
- }
232
-
233
- uintptr_t fiobject___noop_count(FIOBJ o);
234
- double fiobject___noop_to_f(FIOBJ o);
235
-
236
- const fiobj_object_vtable_s FIOBJECT_VTABLE_DATA = {
237
- .class_name = "IO",
238
- .dealloc = fiobj_data_dealloc,
239
- .to_i = fiobj_data_i,
240
- .to_str = fio_io2str,
241
- .is_eq = fiobj_data_iseq,
242
- .is_true = fiobj_data_is_true,
243
- .to_f = fiobject___noop_to_f,
244
- .count = fiobject___noop_count,
245
- };
246
-
247
- /* *****************************************************************************
248
- Seeking for characters in a string
249
- ***************************************************************************** */
250
-
251
- #if FIO_MEMCHAR
252
-
253
- /**
254
- * This seems to be faster on some systems, especially for smaller distances.
255
- *
256
- * On newer systems, `memchr` should be faster.
257
- */
258
- static inline int swallow_ch(uint8_t **buffer, register uint8_t *const limit,
259
- const uint8_t c) {
260
- if (**buffer == c)
261
- return 1;
262
-
263
- #if !ALLOW_UNALIGNED_MEMORY_ACCESS || !defined(__x86_64__)
264
- /* too short for this mess */
265
- if ((uintptr_t)limit <= 16 + ((uintptr_t)*buffer & (~(uintptr_t)7)))
266
- goto finish;
267
-
268
- /* align memory */
269
- {
270
- const uint8_t *alignment =
271
- (uint8_t *)(((uintptr_t)(*buffer) & (~(uintptr_t)7)) + 8);
272
- if (limit >= alignment) {
273
- while (*buffer < alignment) {
274
- if (**buffer == c) {
275
- (*buffer)++;
276
- return 1;
277
- }
278
- *buffer += 1;
279
- }
280
- }
281
- }
282
- const uint8_t *limit64 = (uint8_t *)((uintptr_t)limit & (~(uintptr_t)7));
283
- #else
284
- const uint8_t *limit64 = (uint8_t *)limit - 7;
285
- #endif
286
- uint64_t wanted1 = 0x0101010101010101ULL * c;
287
- for (; *buffer < limit64; *buffer += 8) {
288
- const uint64_t eq1 = ~((*((uint64_t *)*buffer)) ^ wanted1);
289
- const uint64_t t0 = (eq1 & 0x7f7f7f7f7f7f7f7fllu) + 0x0101010101010101llu;
290
- const uint64_t t1 = (eq1 & 0x8080808080808080llu);
291
- if ((t0 & t1)) {
292
- break;
293
- }
294
- }
295
- #if !ALLOW_UNALIGNED_MEMORY_ACCESS || !defined(__x86_64__)
296
- finish:
297
- #endif
298
- while (*buffer < limit) {
299
- if (**buffer == c) {
300
- (*buffer)++;
301
- return 1;
302
- }
303
- (*buffer)++;
304
- }
305
-
306
- return 0;
307
- }
308
- #else
309
-
310
- static inline int swallow_ch(uint8_t **buffer, uint8_t *const limit,
311
- const uint8_t c) {
312
- if (limit - *buffer == 0)
313
- return 0;
314
- void *tmp = memchr(*buffer, c, limit - (*buffer));
315
- if (tmp) {
316
- *buffer = tmp;
317
- (*buffer)++;
318
- return 1;
319
- }
320
- *buffer = (uint8_t *)limit;
321
- return 0;
322
- }
323
-
324
- #endif
325
-
326
- /* *****************************************************************************
327
- Creating the IO object
328
- ***************************************************************************** */
329
-
330
- /** Creates a new local in-memory IO object */
331
- FIOBJ fiobj_data_newstr(void) {
332
- FIOBJ o = fiobj_data_alloc(fio_malloc(4096), -1);
333
- REQUIRE_MEM(obj2io(o)->buffer);
334
- obj2io(o)->capa = 4096;
335
- obj2io(o)->source.dealloc = fio_free;
336
- return o;
337
- }
338
-
339
- /**
340
- * Creates a IO object from an existing buffer. The buffer will be deallocated
341
- * using the provided `dealloc` function pointer. Use a NULL `dealloc` function
342
- * pointer if the buffer is static and shouldn't be freed.
343
- */
344
- FIOBJ fiobj_data_newstr2(void *buffer, uintptr_t length,
345
- void (*dealloc)(void *)) {
346
- FIOBJ o = fiobj_data_alloc(buffer, -1);
347
- obj2io(o)->capa = length;
348
- obj2io(o)->len = length;
349
- obj2io(o)->source.dealloc = dealloc;
350
- return o;
351
- }
352
-
353
- /** Creates a new local file IO object */
354
- FIOBJ fiobj_data_newfd(int fd) {
355
- FIOBJ o = fiobj_data_alloc(fio_malloc(4096), fd);
356
- REQUIRE_MEM(obj2io(o)->buffer);
357
- obj2io(o)->source.fpos = 0;
358
- return o;
359
- }
360
-
361
- /** Creates a new local tempfile IO object */
362
- FIOBJ fiobj_data_newtmpfile(void) {
363
- // create a temporary file to contain the data.
364
- int fd = fio_tmpfile();
365
- if (fd == -1)
366
- return 0;
367
- return fiobj_data_newfd(fd);
368
- }
369
-
370
- /** Creates a slice from an existing Data object. */
371
- FIOBJ fiobj_data_slice(FIOBJ parent, intptr_t offset, uintptr_t length) {
372
- /* cut from the end */
373
- if (offset < 0) {
374
- size_t parent_len = fiobj_data_len(parent);
375
- offset = parent_len + 1 + offset;
376
- }
377
- if (offset < 0)
378
- offset = 0;
379
- while (obj2io(parent)->fd == -2) {
380
- /* don't slice a slice... climb the parent chain. */
381
- offset += obj2io(parent)->capa;
382
- parent = obj2io(parent)->source.parent;
383
- }
384
- size_t parent_len = fiobj_data_len(parent);
385
- if (parent_len <= (size_t)offset) {
386
- length = 0;
387
- offset = parent_len;
388
- } else if (parent_len < offset + length) {
389
- length = parent_len - offset;
390
- }
391
- /* make the object */
392
- FIOBJ o = fiobj_data_alloc(NULL, -2);
393
- obj2io(o)->capa = offset;
394
- obj2io(o)->len = length;
395
- obj2io(o)->source.parent = fiobj_dup(parent);
396
- return o;
397
- }
398
-
399
- /* *****************************************************************************
400
- Saving the IO object
401
- ***************************************************************************** */
402
-
403
- static int fiobj_data_save_str(FIOBJ o, const char *filename) {
404
- int target = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0777);
405
- if (target == -1)
406
- return -1;
407
- errno = 0;
408
- size_t total = 0;
409
- do {
410
- ssize_t act =
411
- write(target, obj2io(o)->buffer + total, obj2io(o)->len - total);
412
- if (act < 0)
413
- goto error;
414
- total += act;
415
- } while (total < obj2io(o)->len);
416
- close(target);
417
- return 0;
418
- error:
419
- close(target);
420
- unlink(filename);
421
- return -1;
422
- }
423
-
424
- static int fiobj_data_save_file(FIOBJ o, const char *filename) {
425
- int target = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0777);
426
- if (target == -1)
427
- return -1;
428
- errno = 0;
429
- char buf[1024];
430
- size_t total = 0;
431
- do {
432
- ssize_t act = pread(obj2io(o)->fd, buf, 1024, total);
433
- if (act == 0)
434
- break;
435
- if (act < 0)
436
- goto error;
437
- ssize_t act2 = write(target, buf, act);
438
- if (act2 < act)
439
- goto error;
440
- total += act2;
441
- } while (1);
442
- close(target);
443
- return 0;
444
- error:
445
- close(target);
446
- unlink(filename);
447
- return -1;
448
- }
449
-
450
- static int fiobj_data_save_slice(FIOBJ o, const char *filename) {
451
- int target = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0777);
452
- if (target == -1)
453
- return -1;
454
- errno = 0;
455
- fio_str_info_s tmp;
456
- size_t total = 0;
457
- do {
458
- tmp = fiobj_data_pread(obj2io(o)->source.parent, obj2io(o)->capa + total,
459
- 4096);
460
- if (tmp.len == 0)
461
- break;
462
- if (total + tmp.len > obj2io(o)->len)
463
- tmp.len = obj2io(o)->len - total;
464
- if (tmp.len) {
465
- ssize_t act2 = write(target, tmp.data, tmp.len);
466
- if (act2 < 0 || (size_t)act2 < tmp.len)
467
- goto error;
468
- total += act2;
469
- }
470
- } while (tmp.len == 4096);
471
- close(target);
472
- return 0;
473
- error:
474
- close(target);
475
- unlink(filename);
476
- return -1;
477
- }
478
-
479
- /** Creates a new local file IO object */
480
- int fiobj_data_save(FIOBJ o, const char *filename) {
481
- switch (obj2io(o)->fd) {
482
- case -1:
483
- return fiobj_data_save_str(o, filename);
484
- break;
485
- case -2:
486
- return fiobj_data_save_slice(o, filename);
487
- break;
488
- default:
489
- return fiobj_data_save_file(o, filename);
490
- }
491
- }
492
-
493
- /* *****************************************************************************
494
- Reading API
495
- ***************************************************************************** */
496
-
497
- /** Reads up to `length` bytes */
498
- static fio_str_info_s fiobj_data_read_str(FIOBJ io, intptr_t length) {
499
- if (obj2io(io)->pos == obj2io(io)->len) {
500
- /* EOF */
501
- return (fio_str_info_s){.data = NULL, .len = 0};
502
- }
503
-
504
- if (length <= 0) {
505
- /* read to EOF - length */
506
- length = (obj2io(io)->len - obj2io(io)->pos) + length;
507
- }
508
-
509
- if (length <= 0) {
510
- /* We are at EOF - length or beyond */
511
- return (fio_str_info_s){.data = NULL, .len = 0};
512
- }
513
-
514
- /* reading length bytes */
515
- register size_t pos = obj2io(io)->pos;
516
- obj2io(io)->pos = pos + length;
517
- if (obj2io(io)->pos > obj2io(io)->len)
518
- obj2io(io)->pos = obj2io(io)->len;
519
- return (fio_str_info_s){
520
- .data = (char *)(obj2io(io)->buffer + pos),
521
- .len = (obj2io(io)->pos - pos),
522
- };
523
- }
524
-
525
- /** Reads up to `length` bytes */
526
- static fio_str_info_s fiobj_data_read_slice(FIOBJ io, intptr_t length) {
527
- if (obj2io(io)->pos == obj2io(io)->len) {
528
- /* EOF */
529
- return (fio_str_info_s){.data = NULL, .len = 0};
530
- }
531
- if (length <= 0) {
532
- /* read to EOF - length */
533
- length = (obj2io(io)->len - obj2io(io)->pos) + length;
534
- }
535
-
536
- if (length <= 0) {
537
- /* We are at EOF - length or beyond */
538
- return (fio_str_info_s){.data = NULL, .len = 0};
539
- }
540
- register size_t pos = obj2io(io)->pos;
541
- obj2io(io)->pos = pos + length;
542
- if (obj2io(io)->pos > obj2io(io)->len)
543
- obj2io(io)->pos = obj2io(io)->len;
544
- return fiobj_data_pread(obj2io(io)->source.parent, pos + obj2io(io)->capa,
545
- (obj2io(io)->pos - pos));
546
- }
547
-
548
- /** Reads up to `length` bytes */
549
- static fio_str_info_s fiobj_data_read_file(FIOBJ io, intptr_t length) {
550
- uintptr_t fsize = fiobj_data_get_fd_size(io);
551
-
552
- if (length <= 0) {
553
- /* read to EOF - length */
554
- length = (fsize - obj2io(io)->source.fpos) + length;
555
- }
556
-
557
- if (length <= 0) {
558
- /* We are at EOF - length or beyond */
559
- errno = 0;
560
- return (fio_str_info_s){.data = NULL, .len = 0};
561
- }
562
-
563
- /* reading length bytes */
564
- if (length + obj2io(io)->pos <= obj2io(io)->len) {
565
- /* the data already exists in the buffer */
566
- // fprintf(stderr, "in_buffer...\n");
567
- fio_str_info_s data = {.data =
568
- (char *)(obj2io(io)->buffer + obj2io(io)->pos),
569
- .len = (uintptr_t)length};
570
- obj2io(io)->pos += length;
571
- obj2io(io)->source.fpos += length;
572
- return data;
573
- } else {
574
- /* read the data into the buffer - internal counting gets invalidated */
575
- // fprintf(stderr, "populate buffer...\n");
576
- obj2io(io)->len = 0;
577
- obj2io(io)->pos = 0;
578
- fiobj_data_pre_write(io, length);
579
- ssize_t l;
580
- retry_int:
581
- l = pread(obj2io(io)->fd, obj2io(io)->buffer, length,
582
- obj2io(io)->source.fpos);
583
- if (l == -1 && errno == EINTR)
584
- goto retry_int;
585
- if (l == -1 || l == 0)
586
- return (fio_str_info_s){.data = NULL, .len = 0};
587
- obj2io(io)->source.fpos += l;
588
- return (fio_str_info_s){.data = (char *)obj2io(io)->buffer, .len = l};
589
- }
590
- }
591
-
592
- /**
593
- * Reads up to `length` bytes and returns a temporary(!) C string object.
594
- *
595
- * The C string object will be invalidate the next time a function call to the
596
- * IO object is made.
597
- */
598
- fio_str_info_s fiobj_data_read(FIOBJ io, intptr_t length) {
599
- if (!io || !FIOBJ_TYPE_IS(io, FIOBJ_T_DATA)) {
600
- errno = EFAULT;
601
- return (fio_str_info_s){.data = NULL, .len = 0};
602
- }
603
- errno = 0;
604
- switch (obj2io(io)->fd) {
605
- case -1:
606
- return fiobj_data_read_str(io, length);
607
- break;
608
- case -2:
609
- return fiobj_data_read_slice(io, length);
610
- break;
611
- default:
612
- return fiobj_data_read_file(io, length);
613
- }
614
- }
615
-
616
- /* *****************************************************************************
617
- Tokenize (read2ch)
618
- ***************************************************************************** */
619
-
620
- static fio_str_info_s fiobj_data_read2ch_str(FIOBJ io, uint8_t token) {
621
- if (obj2io(io)->pos == obj2io(io)->len) /* EOF */
622
- return (fio_str_info_s){.data = NULL, .len = 0};
623
-
624
- uint8_t *pos = obj2io(io)->buffer + obj2io(io)->pos;
625
- uint8_t *lim = obj2io(io)->buffer + obj2io(io)->len;
626
- swallow_ch(&pos, lim, token);
627
- fio_str_info_s ret = (fio_str_info_s){
628
- .data = (char *)obj2io(io)->buffer + obj2io(io)->pos,
629
- .len = (uintptr_t)(pos - obj2io(io)->buffer) - obj2io(io)->pos,
630
- };
631
- obj2io(io)->pos = (uintptr_t)(pos - obj2io(io)->buffer);
632
- return ret;
633
- }
634
-
635
- static fio_str_info_s fiobj_data_read2ch_slice(FIOBJ io, uint8_t token) {
636
- if (obj2io(io)->pos == obj2io(io)->len) /* EOF */
637
- return (fio_str_info_s){.data = NULL, .len = 0};
638
- size_t old_pos = obj2io(obj2io(io)->source.parent)->pos;
639
- obj2io(obj2io(io)->source.parent)->pos = obj2io(io)->capa + obj2io(io)->pos;
640
- fio_str_info_s tmp = fiobj_data_read2ch(obj2io(io)->source.parent, token);
641
- obj2io(obj2io(io)->source.parent)->pos = old_pos;
642
- if (tmp.len + obj2io(io)->pos > obj2io(io)->len) {
643
- /* EOF */
644
- tmp.len = obj2io(io)->len - obj2io(io)->pos;
645
- obj2io(io)->pos = obj2io(io)->len;
646
- return tmp;
647
- }
648
- return tmp;
649
- }
650
-
651
- static fio_str_info_s fiobj_data_read2ch_file(FIOBJ io, uint8_t token) {
652
- uint8_t *pos = obj2io(io)->buffer + obj2io(io)->pos;
653
- uint8_t *lim = obj2io(io)->buffer + obj2io(io)->len;
654
- if (pos != lim && swallow_ch(&pos, lim, token)) {
655
- /* newline found in existing buffer */
656
- const uintptr_t delta =
657
- (uintptr_t)(pos - (obj2io(io)->buffer + obj2io(io)->pos));
658
- obj2io(io)->pos += delta;
659
- obj2io(io)->source.fpos += delta;
660
- return (fio_str_info_s){
661
- .data =
662
- (char *)(delta ? ((obj2io(io)->buffer + obj2io(io)->pos) - delta)
663
- : NULL),
664
- .len = delta,
665
- };
666
- }
667
-
668
- obj2io(io)->pos = 0;
669
- obj2io(io)->len = 0;
670
-
671
- while (1) {
672
- ssize_t tmp;
673
- fiobj_data_pre_write(io, 4096); /* read a page at a time */
674
- retry_int:
675
- tmp = pread(obj2io(io)->fd, obj2io(io)->buffer + obj2io(io)->len, 4096,
676
- obj2io(io)->source.fpos + obj2io(io)->len);
677
- if (tmp < 0 && errno == EINTR)
678
- goto retry_int;
679
- if (tmp < 0 || (tmp == 0 && obj2io(io)->len == 0)) {
680
- return (fio_str_info_s){.data = NULL, .len = 0};
681
- }
682
- if (tmp == 0) {
683
- obj2io(io)->source.fpos += obj2io(io)->len;
684
- return (fio_str_info_s){.data = (char *)obj2io(io)->buffer,
685
- .len = obj2io(io)->len};
686
- }
687
- obj2io(io)->len += tmp;
688
- pos = obj2io(io)->buffer;
689
- lim = obj2io(io)->buffer + obj2io(io)->len;
690
- if (swallow_ch(&pos, lim, token)) {
691
- const uintptr_t delta =
692
- (uintptr_t)(pos - (obj2io(io)->buffer + obj2io(io)->pos));
693
- obj2io(io)->pos = delta;
694
- obj2io(io)->source.fpos += delta;
695
- return (fio_str_info_s){
696
- .data = (char *)obj2io(io)->buffer,
697
- .len = delta,
698
- };
699
- }
700
- }
701
- }
702
-
703
- /**
704
- * Reads until the `token` byte is encountered or until the end of the stream.
705
- *
706
- * Returns a temporary(!) C string including the end of line marker.
707
- *
708
- * Careful when using this call on large file streams, as the whole file
709
- * stream might be loaded into the memory.
710
- *
711
- * The C string object will be invalidate the next time a function call to the
712
- * IO object is made.
713
- */
714
- fio_str_info_s fiobj_data_read2ch(FIOBJ io, uint8_t token) {
715
- if (!io || !FIOBJ_TYPE_IS(io, FIOBJ_T_DATA)) {
716
- errno = EFAULT;
717
- return (fio_str_info_s){.data = NULL, .len = 0};
718
- }
719
- switch (obj2io(io)->fd) {
720
- case -1:
721
- return fiobj_data_read2ch_str(io, token);
722
- break;
723
- case -2:
724
- return fiobj_data_read2ch_slice(io, token);
725
- break;
726
- default:
727
- return fiobj_data_read2ch_file(io, token);
728
- }
729
- }
730
-
731
- /* *****************************************************************************
732
- Position / Seeking
733
- ***************************************************************************** */
734
-
735
- /**
736
- * Returns the current reading position.
737
- */
738
- intptr_t fiobj_data_pos(FIOBJ io) {
739
- if (!io || !FIOBJ_TYPE_IS(io, FIOBJ_T_DATA))
740
- return -1;
741
- switch (obj2io(io)->fd) {
742
- case -1: /* fallthrough */
743
- case -2:
744
- return obj2io(io)->pos;
745
- break;
746
- default:
747
- return obj2io(io)->source.fpos;
748
- }
749
- }
750
-
751
- /**
752
- * Returns the length of the stream.
753
- */
754
- intptr_t fiobj_data_len(FIOBJ io) {
755
- if (!io || !FIOBJ_TYPE_IS(io, FIOBJ_T_DATA))
756
- return -1;
757
- return fiobj_data_i(io);
758
- }
759
-
760
- /**
761
- * Moves the reading position to the requested position.
762
- */
763
- void fiobj_data_seek(FIOBJ io, intptr_t position) {
764
- if (!io || !FIOBJ_TYPE_IS(io, FIOBJ_T_DATA))
765
- return;
766
- switch (obj2io(io)->fd) {
767
- case -1: /* fallthrough */
768
- case -2:
769
- /* String / Slice code */
770
- if (position == 0) {
771
- obj2io(io)->pos = 0;
772
- return;
773
- }
774
- if (position > 0) {
775
- if ((uintptr_t)position > obj2io(io)->len)
776
- position = obj2io(io)->len;
777
- obj2io(io)->pos = position;
778
- return;
779
- }
780
- position = (0 - position);
781
- if ((uintptr_t)position > obj2io(io)->len)
782
- position = 0;
783
- else
784
- position = obj2io(io)->len - position;
785
- obj2io(io)->pos = position;
786
- return;
787
- break;
788
- default:
789
- /* File code */
790
- obj2io(io)->pos = 0;
791
- obj2io(io)->len = 0;
792
-
793
- if (position == 0) {
794
- obj2io(io)->source.fpos = 0;
795
- return;
796
- }
797
- int64_t len = fiobj_data_get_fd_size(io);
798
- if (len < 0)
799
- len = 0;
800
- if (position > 0) {
801
- if (position > len)
802
- position = len;
803
-
804
- obj2io(io)->source.fpos = position;
805
- return;
806
- }
807
- position = (0 - position);
808
- if (position > len)
809
- position = 0;
810
- else
811
- position = len - position;
812
- obj2io(io)->source.fpos = position;
813
- return;
814
- }
815
- }
816
-
817
- /* *****************************************************************************
818
- `fiobj_data_pread`
819
- ***************************************************************************** */
820
- // switch(obj2io(o)->fd) {
821
- // case -1:
822
- // break;
823
- // case -2:
824
- // break;
825
- // default:
826
- // }
827
-
828
- static fio_str_info_s fiobj_data_pread_str(FIOBJ io, intptr_t start_at,
829
- uintptr_t length) {
830
- if (start_at < 0)
831
- start_at = obj2io(io)->len + start_at;
832
- if (start_at < 0)
833
- start_at = 0;
834
- if ((size_t)start_at > obj2io(io)->len)
835
- start_at = obj2io(io)->len;
836
- if (length + start_at > obj2io(io)->len)
837
- length = obj2io(io)->len - start_at;
838
- if (length == 0)
839
- return (fio_str_info_s){
840
- .data = NULL,
841
- .len = 0,
842
- };
843
- return (fio_str_info_s){
844
- .data = (char *)obj2io(io)->buffer + start_at,
845
- .len = length,
846
- };
847
- }
848
- static fio_str_info_s fiobj_data_pread_slice(FIOBJ io, intptr_t start_at,
849
- uintptr_t length) {
850
- if (start_at < 0)
851
- start_at = obj2io(io)->len + start_at;
852
- if (start_at < 0)
853
- start_at = 0;
854
- if ((size_t)start_at > obj2io(io)->len)
855
- start_at = obj2io(io)->len;
856
- if (length + start_at > obj2io(io)->len)
857
- length = obj2io(io)->len - start_at;
858
- if (length == 0)
859
- return (fio_str_info_s){
860
- .data = NULL,
861
- .len = 0,
862
- };
863
- return fiobj_data_pread(obj2io(io)->source.parent, start_at, length);
864
- }
865
-
866
- static fio_str_info_s fiobj_data_pread_file(FIOBJ io, intptr_t start_at,
867
- uintptr_t length) {
868
- const int64_t size = fiobj_data_get_fd_size(io);
869
- if (start_at < 0)
870
- start_at = size + start_at;
871
- if (start_at < 0)
872
- start_at = 0;
873
- if (length + start_at > (uint64_t)size)
874
- length = size - start_at;
875
- if (length == 0) {
876
- /* free memory once there's no more data to read */
877
- obj2io(io)->capa = 0;
878
- fio_free(obj2io(io)->buffer);
879
- obj2io(io)->buffer = NULL;
880
- return (fio_str_info_s){
881
- .data = NULL,
882
- .len = 0,
883
- };
884
- }
885
- obj2io(io)->len = 0;
886
- obj2io(io)->pos = 0;
887
- fiobj_data_pre_write(io, length + 1);
888
- ssize_t tmp = pread(obj2io(io)->fd, obj2io(io)->buffer, length, start_at);
889
- if (tmp <= 0) {
890
- return (fio_str_info_s){
891
- .data = NULL,
892
- .len = 0,
893
- };
894
- }
895
- obj2io(io)->buffer[tmp] = 0;
896
- return (fio_str_info_s){
897
- .data = (char *)obj2io(io)->buffer,
898
- .len = tmp,
899
- };
900
- }
901
- /**
902
- * Reads up to `length` bytes starting at `start_at` position and returns a
903
- * temporary(!) C string object. The reading position is ignored and
904
- * unchanged.
905
- *
906
- * The C string object will be invalidate the next time a function call to the
907
- * IO object is made.
908
- */
909
- fio_str_info_s fiobj_data_pread(FIOBJ io, intptr_t start_at, uintptr_t length) {
910
- if (!io || !FIOBJ_TYPE_IS(io, FIOBJ_T_DATA)) {
911
- errno = EFAULT;
912
- return (fio_str_info_s){
913
- .data = NULL,
914
- .len = 0,
915
- };
916
- }
917
-
918
- errno = 0;
919
- switch (obj2io(io)->fd) {
920
- case -1:
921
- return fiobj_data_pread_str(io, start_at, length);
922
- break;
923
- case -2:
924
- return fiobj_data_pread_slice(io, start_at, length);
925
- break;
926
- default:
927
- return fiobj_data_pread_file(io, start_at, length);
928
- }
929
- }
930
-
931
- /* *****************************************************************************
932
- Writing API
933
- ***************************************************************************** */
934
-
935
- /**
936
- * Makes sure the IO object isn't attached to a static or external string.
937
- *
938
- * If the IO object is attached to a static or external string, the data will be
939
- * copied to a new memory block.
940
- */
941
- void fiobj_data_assert_dynamic(FIOBJ io) {
942
- if (!io) {
943
- errno = ENFILE;
944
- return;
945
- }
946
- assert(FIOBJ_TYPE(io) == FIOBJ_T_DATA);
947
- fiobj_data_pre_write(io, 0);
948
- return;
949
- }
950
-
951
- /**
952
- * Writes `length` bytes at the end of the IO stream, ignoring the reading
953
- * position.
954
- *
955
- * Behaves and returns the same value as the system call `write`.
956
- */
957
- intptr_t fiobj_data_write(FIOBJ io, void *buffer, uintptr_t length) {
958
- if (!io || !FIOBJ_TYPE_IS(io, FIOBJ_T_DATA) || (!buffer && length)) {
959
- errno = EFAULT;
960
- return -1;
961
- }
962
- errno = 0;
963
- /* Unslice slices */
964
- if (obj2io(io)->fd == -2)
965
- fiobj_data_assert_dynamic(io);
966
-
967
- if (obj2io(io)->fd == -1) {
968
- /* String Code */
969
- fiobj_data_pre_write(io, length + 1);
970
- memcpy(obj2io(io)->buffer + obj2io(io)->len, buffer, length);
971
- obj2io(io)->len = obj2io(io)->len + length;
972
- obj2io(io)->buffer[obj2io(io)->len] = 0;
973
- return length;
974
- }
975
-
976
- /* File Code */
977
- return pwrite(obj2io(io)->fd, buffer, length, fiobj_data_get_fd_size(io));
978
- }
979
-
980
- /**
981
- * Writes `length` bytes at the end of the IO stream, ignoring the reading
982
- * position, adding an EOL marker ("\r\n") to the end of the stream.
983
- *
984
- * Behaves and returns the same value as the system call `write`.
985
- */
986
- intptr_t fiobj_data_puts(FIOBJ io, void *buffer, uintptr_t length) {
987
- if (!io || !FIOBJ_TYPE_IS(io, FIOBJ_T_DATA) || (!buffer && length)) {
988
- errno = EFAULT;
989
- return -1;
990
- }
991
- /* Unslice slices */
992
- if (obj2io(io)->fd == -2)
993
- fiobj_data_assert_dynamic(io);
994
-
995
- if (obj2io(io)->fd == -1) {
996
- /* String Code */
997
- fiobj_data_pre_write(io, length + 2);
998
- if (length) {
999
- memcpy(obj2io(io)->buffer + obj2io(io)->len, buffer, length);
1000
- }
1001
- obj2io(io)->len = obj2io(io)->len + length + 2;
1002
- obj2io(io)->buffer[obj2io(io)->len - 2] = '\r';
1003
- obj2io(io)->buffer[obj2io(io)->len - 1] = '\n';
1004
- return length + 2;
1005
- }
1006
- /* File Code */
1007
- uintptr_t end = fiobj_data_get_fd_size(io);
1008
- ssize_t t1 = 0, t2 = 0;
1009
-
1010
- if (length) {
1011
- t1 = pwrite(obj2io(io)->fd, buffer, length, end);
1012
- if (t1 < 0)
1013
- return t1;
1014
- end += t1;
1015
- }
1016
- t2 = pwrite(obj2io(io)->fd, buffer, length, end);
1017
- if (t2 < 0)
1018
- return t1;
1019
- return t1 + t2;
1020
- }
1021
-
1022
- #if DEBUG
1023
-
1024
- void fiobj_data_test(void) {
1025
- char *filename = NULL;
1026
- FIOBJ text;
1027
- fio_str_info_s s1, s2;
1028
- fprintf(stderr, "=== testing fiobj_data\n");
1029
- if (filename) {
1030
- text = fiobj_str_buf(0);
1031
- fiobj_str_readfile(text, filename, 0, 0);
1032
- } else
1033
- text = fiobj_str_new("Line 1\r\nLine 2\nLine 3 unended", 29);
1034
- FIOBJ strio = fiobj_data_newstr();
1035
- fprintf(stderr, "* `newstr` passed.\n");
1036
- FIOBJ fdio = fiobj_data_newtmpfile();
1037
- fprintf(stderr, "* `newtmpfile` passed.\n");
1038
- fiobj_data_write(fdio, fiobj_obj2cstr(text).data, fiobj_obj2cstr(text).len);
1039
- fiobj_data_write(strio, fiobj_obj2cstr(text).data, fiobj_obj2cstr(text).len);
1040
- FIOBJ sliceio = fiobj_data_slice(fdio, 8, 7);
1041
-
1042
- s1 = fiobj_data_read(sliceio, 4096);
1043
- if (s1.len != 7 || memcmp(s1.data, fiobj_data_pread(strio, 8, 7).data, 7)) {
1044
- fprintf(stderr, "* `fiobj_data_slice` operation FAILED!\n");
1045
- fprintf(stderr, "* `fiobj_data_slice` s1.len = %zu s1.data = %s!\n", s1.len,
1046
- s1.data);
1047
- exit(-1);
1048
- }
1049
- s1 = fiobj_data_read(sliceio, 4096);
1050
- if (s1.len || s1.data) {
1051
- fprintf(stderr, "* `fiobj_data_read` operation overflow - FAILED!\n");
1052
- exit(-1);
1053
- }
1054
- if (fiobj_obj2cstr(strio).len != fiobj_obj2cstr(text).len ||
1055
- fiobj_obj2cstr(fdio).len != fiobj_obj2cstr(text).len) {
1056
- fprintf(stderr, "* `write` operation FAILED!\n");
1057
- exit(-1);
1058
- }
1059
- s1 = fiobj_data_gets(strio);
1060
- s2 = fiobj_data_gets(fdio);
1061
- fprintf(stderr, "str(%d): %.*s", (int)s1.len, (int)s1.len, s1.data);
1062
- fprintf(stderr, "fd(%d): %.*s", (int)s2.len, (int)s2.len, s2.data);
1063
- if (s1.len != s2.len || memcmp(s1.data, s2.data, s1.len)) {
1064
- fprintf(stderr,
1065
- "* `gets` operation FAILED! (non equal data):\n"
1066
- "%d bytes vs. %d bytes\n"
1067
- "%.*s vs %.*s\n",
1068
- (int)s1.len, (int)s2.len, (int)s1.len, s1.data, (int)s2.len,
1069
- s2.data);
1070
- exit(-1);
1071
- } else
1072
- fprintf(stderr, "* `gets` operation passed (equal data).\n");
1073
-
1074
- if (!filename) {
1075
- intptr_t last_pos = fiobj_data_pos(fdio);
1076
- fiobj_data_seek(sliceio, 0);
1077
- s1 = fiobj_data_gets(sliceio);
1078
- s2 = fiobj_data_gets(fdio);
1079
- fiobj_data_seek(fdio, last_pos);
1080
- if (s1.len != s2.len || memcmp(s1.data, s2.data, s1.len)) {
1081
- fprintf(stderr,
1082
- "* slice `gets` operation FAILED! (non equal data):\n"
1083
- "%d bytes vs. %d bytes\n"
1084
- "%.*s vs %.*s\n",
1085
- (int)s1.len, (int)s2.len, (int)s1.len, s1.data, (int)s2.len,
1086
- s2.data);
1087
- exit(-1);
1088
- }
1089
- }
1090
-
1091
- s1 = fiobj_data_read(strio, 3);
1092
- s2 = fiobj_data_read(fdio, 3);
1093
- if (s1.len != s2.len || memcmp(s1.data, s2.data, s1.len)) {
1094
- fprintf(stderr,
1095
- "* `read` operation FAILED! (non equal data):\n"
1096
- "%d bytes vs. %d bytes\n"
1097
- "%.*s vs %.*s\n",
1098
- (int)s1.len, (int)s2.len, (int)s1.len, s1.data, (int)s2.len,
1099
- s2.data);
1100
- exit(-1);
1101
- } else
1102
- fprintf(stderr, "* `read` operation passed (equal data).\n");
1103
- if (!filename) {
1104
- s1 = fiobj_data_gets(strio);
1105
- s2 = fiobj_data_gets(fdio);
1106
- s1 = fiobj_data_gets(strio);
1107
- s2 = fiobj_data_gets(fdio);
1108
- if (s1.len != s2.len || memcmp(s1.data, s2.data, s1.len)) {
1109
- fprintf(stderr,
1110
- "* EOF `gets` operation FAILED! (non equal data):\n"
1111
- "%d bytes vs. %d bytes\n"
1112
- "%.*s vs %.*s\n",
1113
- (int)s1.len, (int)s2.len, (int)s1.len, s1.data, (int)s2.len,
1114
- s2.data);
1115
- exit(-1);
1116
- } else
1117
- fprintf(stderr, "* EOF `gets` operation passed (equal data).\n");
1118
- s1 = fiobj_data_gets(strio);
1119
- s2 = fiobj_data_gets(fdio);
1120
- if (s1.data || s2.data) {
1121
- fprintf(stderr,
1122
- "* EOF `gets` was not EOF?!\n"
1123
- "str(%d): %.*s\n"
1124
- "fd(%d): %.*s\n",
1125
- (int)s1.len, (int)s1.len, s1.data, (int)s2.len, (int)s2.len,
1126
- s2.data);
1127
- exit(-1);
1128
- }
1129
- }
1130
- fiobj_free(text);
1131
- fiobj_free(strio);
1132
- fiobj_free(fdio);
1133
-
1134
- {
1135
- fiobj_data_seek(sliceio, 0);
1136
- s1 = fiobj_data_read(sliceio, 4096);
1137
- if (s1.len != (size_t)fiobj_data_len(sliceio) || !s1.data) {
1138
- fprintf(stderr, "* `fiobj_data_slice` data lost? FAILED!\n");
1139
- fprintf(stderr,
1140
- "* `fiobj_data_slice` s1.len = %zu (out of %zu) s1.data = %s!\n",
1141
- s1.len, (size_t)fiobj_data_len(sliceio), s1.data);
1142
- exit(-1);
1143
- }
1144
- size_t old_len = fiobj_data_len(sliceio);
1145
- fiobj_data_write(sliceio, "hi", 2);
1146
- fiobj_data_seek(sliceio, 0);
1147
- s1 = fiobj_data_read(sliceio, 4096);
1148
- if (s1.len != old_len + 2 || !s1.data || s1.data[s1.len - 1] != 'i') {
1149
- fprintf(stderr, "* `fiobj_data_write` for Slice data lost? FAILED!\n");
1150
- fprintf(stderr,
1151
- "* `fiobj_data_slice` s1.len = %zu (out of %zu) s1.data = %s!\n",
1152
- s1.len, (size_t)fiobj_data_len(sliceio), s1.data);
1153
- exit(-1);
1154
- }
1155
- }
1156
- fiobj_free(sliceio);
1157
-
1158
- fprintf(stderr, "* passed.\n");
1159
- }
1160
-
1161
- #endif
1162
-
1163
- #else /* require POSIX */
1164
- #include <fiobj_data.h>
1165
-
1166
- /** Creates a new local in-memory IO object */
1167
- FIOBJ fiobj_data_newstr(void) { return FIOBJ_INVALID; }
1168
-
1169
- /**
1170
- * Creates a IO object from an existing buffer. The buffer will be deallocated
1171
- * using the provided `dealloc` function pointer. Use a NULL `dealloc` function
1172
- * pointer if the buffer is static and shouldn't be freed.
1173
- */
1174
- FIOBJ fiobj_data_newstr2(void *buffer, uintptr_t length,
1175
- void (*dealloc)(void *)) {
1176
- return FIOBJ_INVALID;
1177
- }
1178
-
1179
- /** Creates a new local tempfile IO object */
1180
- FIOBJ fiobj_data_newtmpfile(void) { return FIOBJ_INVALID; }
1181
-
1182
- /** Creates a new local file IO object */
1183
- FIOBJ fiobj_data_newfd(int fd) { return FIOBJ_INVALID; }
1184
-
1185
- int fiobj_data_save(FIOBJ io, const char *filename) { return -1; }
1186
-
1187
- #endif /* require POSIX */