iodine 0.4.19 → 0.5.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 (146) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -2
  3. data/CHANGELOG.md +22 -0
  4. data/LIMITS.md +19 -9
  5. data/README.md +92 -77
  6. data/SPEC-PubSub-Draft.md +113 -0
  7. data/SPEC-Websocket-Draft.md +127 -143
  8. data/bin/http-hello +0 -1
  9. data/bin/raw-rbhttp +1 -1
  10. data/bin/raw_broadcast +8 -10
  11. data/bin/updated api +2 -2
  12. data/bin/ws-broadcast +2 -4
  13. data/bin/ws-echo +2 -2
  14. data/examples/config.ru +13 -13
  15. data/examples/echo.ru +5 -6
  16. data/examples/hello.ru +2 -3
  17. data/examples/info.md +316 -0
  18. data/examples/pubsub_engine.ru +81 -0
  19. data/examples/redis.ru +9 -9
  20. data/examples/shootout.ru +45 -11
  21. data/ext/iodine/defer.c +194 -297
  22. data/ext/iodine/defer.h +61 -53
  23. data/ext/iodine/evio.c +0 -260
  24. data/ext/iodine/evio.h +50 -22
  25. data/ext/iodine/evio_callbacks.c +26 -0
  26. data/ext/iodine/evio_epoll.c +251 -0
  27. data/ext/iodine/evio_kqueue.c +193 -0
  28. data/ext/iodine/extconf.rb +1 -1
  29. data/ext/iodine/facil.c +1420 -542
  30. data/ext/iodine/facil.h +151 -64
  31. data/ext/iodine/fio_ary.h +418 -0
  32. data/ext/iodine/{base64.c → fio_base64.c} +33 -24
  33. data/ext/iodine/{base64.h → fio_base64.h} +6 -7
  34. data/ext/iodine/{fio_cli_helper.c → fio_cli.c} +77 -58
  35. data/ext/iodine/{fio_cli_helper.h → fio_cli.h} +9 -4
  36. data/ext/iodine/fio_hashmap.h +759 -0
  37. data/ext/iodine/fio_json_parser.h +651 -0
  38. data/ext/iodine/fio_llist.h +257 -0
  39. data/ext/iodine/fio_mem.c +672 -0
  40. data/ext/iodine/fio_mem.h +140 -0
  41. data/ext/iodine/fio_random.c +248 -0
  42. data/ext/iodine/{random.h → fio_random.h} +11 -14
  43. data/ext/iodine/{sha1.c → fio_sha1.c} +28 -24
  44. data/ext/iodine/{sha1.h → fio_sha1.h} +38 -16
  45. data/ext/iodine/{sha2.c → fio_sha2.c} +66 -49
  46. data/ext/iodine/{sha2.h → fio_sha2.h} +57 -26
  47. data/ext/iodine/{fiobj_internal.c → fio_siphash.c} +9 -90
  48. data/ext/iodine/fio_siphash.h +18 -0
  49. data/ext/iodine/fio_tmpfile.h +38 -0
  50. data/ext/iodine/fiobj.h +24 -7
  51. data/ext/iodine/fiobj4sock.h +23 -0
  52. data/ext/iodine/fiobj_ary.c +143 -226
  53. data/ext/iodine/fiobj_ary.h +17 -16
  54. data/ext/iodine/fiobj_data.c +1160 -0
  55. data/ext/iodine/fiobj_data.h +164 -0
  56. data/ext/iodine/fiobj_hash.c +298 -406
  57. data/ext/iodine/fiobj_hash.h +101 -54
  58. data/ext/iodine/fiobj_json.c +478 -601
  59. data/ext/iodine/fiobj_json.h +34 -9
  60. data/ext/iodine/fiobj_numbers.c +383 -51
  61. data/ext/iodine/fiobj_numbers.h +87 -11
  62. data/ext/iodine/fiobj_str.c +423 -184
  63. data/ext/iodine/fiobj_str.h +81 -32
  64. data/ext/iodine/fiobject.c +273 -522
  65. data/ext/iodine/fiobject.h +477 -112
  66. data/ext/iodine/http.c +2243 -83
  67. data/ext/iodine/http.h +842 -121
  68. data/ext/iodine/http1.c +810 -385
  69. data/ext/iodine/http1.h +16 -39
  70. data/ext/iodine/http1_parser.c +146 -74
  71. data/ext/iodine/http1_parser.h +15 -4
  72. data/ext/iodine/http_internal.c +1258 -0
  73. data/ext/iodine/http_internal.h +226 -0
  74. data/ext/iodine/http_mime_parser.h +341 -0
  75. data/ext/iodine/iodine.c +86 -68
  76. data/ext/iodine/iodine.h +26 -11
  77. data/ext/iodine/iodine_helpers.c +8 -7
  78. data/ext/iodine/iodine_http.c +487 -324
  79. data/ext/iodine/iodine_json.c +304 -0
  80. data/ext/iodine/iodine_json.h +6 -0
  81. data/ext/iodine/iodine_protocol.c +107 -45
  82. data/ext/iodine/iodine_pubsub.c +526 -225
  83. data/ext/iodine/iodine_pubsub.h +10 -0
  84. data/ext/iodine/iodine_websockets.c +268 -510
  85. data/ext/iodine/iodine_websockets.h +2 -4
  86. data/ext/iodine/pubsub.c +726 -432
  87. data/ext/iodine/pubsub.h +85 -103
  88. data/ext/iodine/rb-call.c +4 -4
  89. data/ext/iodine/rb-defer.c +46 -22
  90. data/ext/iodine/rb-fiobj2rb.h +117 -0
  91. data/ext/iodine/rb-rack-io.c +73 -238
  92. data/ext/iodine/rb-rack-io.h +2 -2
  93. data/ext/iodine/rb-registry.c +35 -93
  94. data/ext/iodine/rb-registry.h +1 -0
  95. data/ext/iodine/redis_engine.c +742 -304
  96. data/ext/iodine/redis_engine.h +42 -39
  97. data/ext/iodine/resp_parser.h +311 -0
  98. data/ext/iodine/sock.c +627 -490
  99. data/ext/iodine/sock.h +345 -297
  100. data/ext/iodine/spnlock.inc +15 -4
  101. data/ext/iodine/websocket_parser.h +16 -20
  102. data/ext/iodine/websockets.c +188 -257
  103. data/ext/iodine/websockets.h +24 -133
  104. data/lib/iodine.rb +52 -7
  105. data/lib/iodine/cli.rb +6 -24
  106. data/lib/iodine/json.rb +40 -0
  107. data/lib/iodine/version.rb +1 -1
  108. data/lib/iodine/websocket.rb +5 -3
  109. data/lib/rack/handler/iodine.rb +58 -13
  110. metadata +38 -48
  111. data/bin/ws-shootout +0 -107
  112. data/examples/broadcast.ru +0 -56
  113. data/ext/iodine/bscrypt-common.h +0 -116
  114. data/ext/iodine/bscrypt.h +0 -49
  115. data/ext/iodine/fio2resp.c +0 -60
  116. data/ext/iodine/fio2resp.h +0 -51
  117. data/ext/iodine/fio_dict.c +0 -446
  118. data/ext/iodine/fio_dict.h +0 -99
  119. data/ext/iodine/fio_hash_table.h +0 -370
  120. data/ext/iodine/fio_list.h +0 -111
  121. data/ext/iodine/fiobj_internal.h +0 -280
  122. data/ext/iodine/fiobj_primitives.c +0 -131
  123. data/ext/iodine/fiobj_primitives.h +0 -55
  124. data/ext/iodine/fiobj_sym.c +0 -135
  125. data/ext/iodine/fiobj_sym.h +0 -60
  126. data/ext/iodine/hex.c +0 -124
  127. data/ext/iodine/hex.h +0 -70
  128. data/ext/iodine/http1_request.c +0 -81
  129. data/ext/iodine/http1_request.h +0 -58
  130. data/ext/iodine/http1_response.c +0 -417
  131. data/ext/iodine/http1_response.h +0 -95
  132. data/ext/iodine/http_request.c +0 -111
  133. data/ext/iodine/http_request.h +0 -102
  134. data/ext/iodine/http_response.c +0 -1703
  135. data/ext/iodine/http_response.h +0 -250
  136. data/ext/iodine/misc.c +0 -182
  137. data/ext/iodine/misc.h +0 -74
  138. data/ext/iodine/random.c +0 -208
  139. data/ext/iodine/redis_connection.c +0 -278
  140. data/ext/iodine/redis_connection.h +0 -86
  141. data/ext/iodine/resp.c +0 -842
  142. data/ext/iodine/resp.h +0 -261
  143. data/ext/iodine/siphash.c +0 -154
  144. data/ext/iodine/siphash.h +0 -22
  145. data/ext/iodine/xor-crypt.c +0 -193
  146. data/ext/iodine/xor-crypt.h +0 -107
data/ext/iodine/bscrypt.h DELETED
@@ -1,49 +0,0 @@
1
- /*
2
- Copyright: Boaz segev, 2016-2017
3
- License: MIT except for any non-public-domain algorithms (none that I'm aware
4
- of), which might be subject to their own licenses.
5
-
6
- Feel free to copy, use and enjoy in accordance with to the license(s).
7
- */
8
- #ifndef BSCRYPT
9
- /**
10
- The bscrypt library supplies some **basic** cryptographic functions.
11
-
12
- Read the README file for more details.
13
-
14
- All functions will be available using the prefix `bscrypt_`, i.e.:
15
-
16
- char buffer[13] = {0};
17
- bscrypt_base64_encode(buffer, "My String", 9);
18
-
19
-
20
- */
21
- #define BSCRYPT "0.0.1"
22
-
23
- #include "base64.h"
24
- #include "bscrypt-common.h"
25
- #include "hex.h"
26
- #include "misc.h"
27
- #include "random.h"
28
- #include "sha1.h"
29
- #include "sha2.h"
30
- #include "siphash.h"
31
- #include "xor-crypt.h"
32
-
33
- #if defined(DEBUG) && DEBUG == 1
34
- #define bscrypt_test() \
35
- { \
36
- bscrypt_test_sha1(); \
37
- bscrypt_test_sha2(); \
38
- bscrypt_test_base64(); \
39
- bscrypt_test_random(); \
40
- bscrypt_test_siphash(); \
41
- }
42
- #else
43
- #define bscrypt_test() \
44
- fprintf(stderr, \
45
- "Debug mode not enabled, define DEBUG as 1 in the compiler.\n");
46
- #endif
47
-
48
- /* end include gate */
49
- #endif
@@ -1,60 +0,0 @@
1
- /*
2
- Copyright: Boaz Segev, 2017
3
- License: MIT
4
-
5
- Feel free to copy, use and enjoy according to the license provided.
6
-
7
- Copyright refers to the parser, not the protocol.
8
- */
9
- #ifndef _GNU_SOURCE
10
- #define _GNU_SOURCE
11
- #endif
12
-
13
- #include "fiobj.h"
14
- #include "resp.h"
15
-
16
- #include <stdio.h>
17
- #include <stdlib.h>
18
- #include <string.h>
19
-
20
- static int resp_fioformat_task(fiobj_s *obj, void *s_) {
21
- fiobj_s *str = s_;
22
-
23
- if (obj->type == FIOBJ_T_FALSE)
24
- fiobj_str_write(str, "false\r\n", 7);
25
- else if (obj->type == FIOBJ_T_TRUE)
26
- fiobj_str_write(str, "true\r\n", 6);
27
- else if (obj->type == FIOBJ_T_NULL)
28
- fiobj_str_write(str, "$-1\r\n", 4);
29
- else if (obj->type == FIOBJ_T_ARRAY)
30
- fiobj_str_write2(str, "*%lu\r\n", (unsigned long)fiobj_ary_count(obj));
31
- else if (obj->type == FIOBJ_T_HASH)
32
- fiobj_str_write2(str, "*%lu\r\n", (unsigned long)fiobj_hash_count(obj));
33
- else if (obj->type == FIOBJ_T_COUPLET) {
34
- fiobj_str_write(str, "*2\r\n", 4);
35
- resp_fioformat_task(fiobj_couplet2key(obj), s_);
36
- resp_fioformat_task(fiobj_couplet2obj(obj), s_);
37
- } else {
38
- if (obj->type == FIOBJ_T_SYMBOL || FIOBJ_IS_STRING(obj)) {
39
- /* use this opportunity to optimize memory allocation to page boundries */
40
- fio_cstr_s s = fiobj_obj2cstr(str);
41
- if (fiobj_str_capa(str) <= s.len + 128 + fiobj_obj2cstr(obj).len) {
42
- fiobj_str_resize(str, (((fiobj_str_capa(str) >> 12) + 1) << 12) - 1);
43
- fiobj_str_resize(str, s.len);
44
- }
45
- }
46
- fiobj_str_join(str, obj);
47
- fiobj_str_write(str, "\r\n", 2);
48
- }
49
- return 0;
50
- }
51
- #undef safe_write_eol
52
- #undef safe_write1
53
- #undef safe_write2
54
- #undef safe_write_i
55
-
56
- fiobj_pt resp_fioformat(fiobj_pt obj) {
57
- fiobj_pt str = fiobj_str_buf(4096);
58
- fiobj_each2(obj, resp_fioformat_task, str);
59
- return str;
60
- }
@@ -1,51 +0,0 @@
1
- /*
2
- Copyright: Boaz segev, 2017
3
- License: MIT except for any non-public-domain algorithms (none that I'm aware
4
- of), which might be subject to their own licenses.
5
-
6
- Feel free to copy, use and enjoy in accordance with to the license(s).
7
- */
8
- #ifndef H_FIO2RESP_FORMAT_H
9
- /**
10
- This is a neive implementation of the RESP protocol for Redis.
11
- */
12
- #define H_FIO2RESP_FORMAT_H
13
-
14
- #include "fiobj.h"
15
- #include "resp.h"
16
-
17
- /* support C++ */
18
- #ifdef __cplusplus
19
- extern "C" {
20
- #endif
21
-
22
- /* *****************************************************************************
23
- `fiobj_s` => RESP (formatting): implemented seperately; can be safely removed.
24
- ***************************************************************************** */
25
-
26
- /**
27
- * Returns a **new** String object containing a RESP representation of `obj`.
28
- *
29
- * Returns NULL on failur.
30
- *
31
- * Obviously, RESP objects and `fiobj_s` objects aren't fully compatible,
32
- * meaning that the RESP_OK and RESP_ERR aren't implemented.
33
- *
34
- * Also, `FIOBJ_T_HASH` objects are rendered as a flattened Array of `[key,
35
- * value, key, value, ...]`, any `FIOBJ_T_FLOAT` will be converted to an Integet
36
- * (the decimal information discarded) and any other object is converted to a
37
- * String. `FIOBJ_T_IO` and `FIOBJ_T_FILE` are ignored.
38
- *
39
- * No `parser` argument is provided and extensions aren't supported for this
40
- * format.
41
- *
42
- * To write a RESP OK or Error don;t use this function. Instead, simply ctreate
43
- * a new String "OK" or "-error message".
44
- */
45
- fiobj_pt resp_fioformat(fiobj_pt obj);
46
-
47
- #ifdef __cplusplus
48
- } /* extern "C" */
49
- #endif
50
-
51
- #endif
@@ -1,446 +0,0 @@
1
- /*
2
- Copyright: Boaz segev, 2017
3
- License: MIT
4
-
5
- Feel free to copy, use and enjoy according to the license provided.
6
- */
7
- #include "fio_dict.h"
8
- /**
9
- `fio_dict_s` Is based on a 4-bit trie structure, allowing for fast no-collisions
10
- key-value matching while avoiding any hashing.
11
-
12
- It's memory intensive... very memory intensive... but it has 0 collision risk
13
- and offers fairly high performance.
14
-
15
- Just to offer some insight, a single key-value pair for the key "hello" will
16
- require ~1,360 bytes. Add the key "bye!" ad you'll add ~1,088 bytes more... but
17
- the key "hello1" will cost only 272 bytes... brrr.
18
- */
19
-
20
- /* *****************************************************************************
21
- Inline variation
22
- ***************************************************************************** */
23
-
24
- static inline fio_dict_s *fio_dict_step_inline(fio_dict_s *dict,
25
- uint8_t prefix) {
26
- if (!dict)
27
- return NULL;
28
- dict = dict->trie[prefix & 0xf];
29
- if (!dict)
30
- return NULL;
31
- return dict->trie[(prefix >> 4) & 0xf];
32
- }
33
-
34
- static inline fio_dict_s *fio_dict_prefix_inline(fio_dict_s *dict,
35
- void *prefix_, size_t len) {
36
- uint8_t *prefix = prefix_;
37
- while (dict && len) {
38
- dict = fio_dict_step_inline(dict, *prefix);
39
- prefix++;
40
- len--;
41
- }
42
- if (len)
43
- return NULL;
44
- return dict;
45
- }
46
-
47
- /* *****************************************************************************
48
- Implementation
49
- ***************************************************************************** */
50
-
51
- /** Returns the `fio_dict_s *` object associated with the key, NULL if none.
52
- */
53
- fio_dict_s *fio_dict_get(fio_dict_s *dict, void *key, size_t key_len) {
54
- dict = fio_dict_prefix_inline(dict, key, key_len);
55
- if (dict && dict->used)
56
- return dict;
57
- return NULL;
58
- }
59
-
60
- /** Returns the old `fio_dict_s *` object associated with the key, if any.*/
61
- fio_dict_s *fio_dict_set(fio_dict_s *dict, void *key, size_t key_len,
62
- fio_dict_s *node) {
63
- uint8_t *pos = key;
64
- uint8_t tr;
65
- fio_dict_s *old;
66
- if (!key_len || !dict)
67
- return NULL;
68
- if (!node) {
69
- dict = fio_dict_get(dict, key, key_len);
70
- fio_dict_remove(dict);
71
- return dict;
72
- }
73
- if (key_len > 1) {
74
- pos += key_len - 1;
75
- dict = fio_dict_ensure_prefix(dict, key, key_len - 1);
76
- }
77
- tr = *pos & 0xf;
78
- if (!dict->trie[tr]) {
79
- if (node == NULL)
80
- return NULL;
81
- dict->trie[tr] = malloc(sizeof(fio_dict_s));
82
- *dict->trie[tr] = (fio_dict_s){.trie_val = tr, .parent = dict};
83
- }
84
- dict = dict->trie[tr];
85
-
86
- tr = ((*pos) >> 4) & 0xf;
87
- if ((old = dict->trie[tr]))
88
- goto replace_node;
89
-
90
- /* no old, but we have a new node we need to initialize and add. */
91
- *node = (fio_dict_s){.parent = dict, .trie_val = tr, .used = 1};
92
- dict->trie[tr] = node;
93
- return NULL;
94
-
95
- replace_node:
96
- /* We have an old node to be replaced with a new one. */
97
- *node = *old;
98
- node->used = 1;
99
- dict->trie[tr] = node;
100
- for (size_t i = 0; i < 16; i++) {
101
- if (node->trie[i])
102
- node->trie[i]->parent = node;
103
- }
104
- if (old->used)
105
- return old;
106
- return NULL;
107
- }
108
-
109
- /** Returns the old `fio_dict_s *` object associated with the key, if any.*/
110
- fio_dict_s *fio_dict_remove(fio_dict_s *node) {
111
- fio_dict_s *tmp;
112
- fio_dict_s *dict = node->parent;
113
- /* We need to remove the existing node and clear the branch if empty. */
114
- if (fio_dict_isempty(node)) {
115
- dict->trie[node->trie_val] = NULL;
116
- while (fio_dict_isempty(dict)) {
117
- if (dict->used || !dict->parent)
118
- break;
119
- tmp = dict;
120
- dict = dict->parent;
121
- dict->trie[tmp->trie_val] = NULL;
122
- free(tmp);
123
- }
124
- if (node->used)
125
- return node;
126
- return NULL;
127
- }
128
- /* We need to place an alternative node. */
129
- if (!node->used)
130
- return NULL;
131
- tmp = malloc(sizeof(fio_dict_s));
132
- *tmp = *node;
133
- tmp->used = 0;
134
- for (size_t i = 0; i < 16; i++) {
135
- if (tmp->trie[i])
136
- tmp->trie[i]->parent = tmp;
137
- }
138
- return node;
139
- }
140
-
141
- /** Returns a `fio_dict_s *` dictionary (or NULL) of all `prefix` children. */
142
- fio_dict_s *fio_dict_step(fio_dict_s *dict, uint8_t prefix) {
143
- return fio_dict_step_inline(dict, prefix);
144
- }
145
-
146
- /** Returns a `fio_dict_s *` dictionary (or NULL) of all `prefix` children. */
147
- fio_dict_s *fio_dict_prefix(fio_dict_s *dict, void *prefix_, size_t len) {
148
- return fio_dict_prefix_inline(dict, prefix_, len);
149
- }
150
-
151
- /**
152
- * Creates a `fio_dict_s *` dictionary (if missing) for the `prefix`...
153
- *
154
- * After calling this function a node MUST be added to this dictionary, or
155
- * memory leaks will occure.
156
- */
157
- fio_dict_s *fio_dict_ensure_prefix(fio_dict_s *dict, void *prefix, size_t len) {
158
- uint8_t *pos = prefix;
159
- uint8_t tr;
160
-
161
- while (dict && len) {
162
- tr = *pos & 0xf;
163
- if (!dict->trie[tr]) {
164
- dict->trie[tr] = malloc(sizeof(fio_dict_s));
165
- *dict->trie[tr] = (fio_dict_s){.trie_val = tr, .parent = dict};
166
- }
167
- dict = dict->trie[tr];
168
- tr = (*pos >> 4) & 0xf;
169
- if (!dict->trie[tr]) {
170
- dict->trie[tr] = malloc(sizeof(fio_dict_s));
171
- *dict->trie[tr] = (fio_dict_s){.trie_val = tr, .parent = dict};
172
- }
173
- dict = dict->trie[tr];
174
- pos++;
175
- len--;
176
- }
177
- return dict;
178
- }
179
-
180
- /** Traverses a dictionary, performing an action for each item. */
181
- void fio_dict_each(fio_dict_s *dict,
182
- void (*action)(fio_dict_s *node, void *arg), void *arg) {
183
- if (!dict)
184
- return;
185
- fio_dict_s *child, *head = dict->parent, *to_call = NULL;
186
- uint8_t tr;
187
- tr = 0;
188
-
189
- /* We use this to make sure that the function doesn't break if `to_call` is
190
- * removed from the trie while we are iterating. */
191
- #define test_callback() \
192
- do { \
193
- if (to_call) \
194
- action(to_call, arg); \
195
- to_call = dict; \
196
- } while (0);
197
-
198
- while (dict != head) {
199
- top:
200
- while (tr < 16) {
201
- /* walk child */
202
- if ((child = dict->trie[tr])) {
203
- dict = child;
204
- tr = 0;
205
- goto top;
206
- }
207
- tr++;
208
- }
209
- if (dict->used)
210
- test_callback();
211
- tr = dict->trie_val + 1;
212
- dict = dict->parent;
213
- }
214
- test_callback();
215
- #undef test_callback
216
- }
217
-
218
- /**
219
-
220
- Traverses a dictionary, performing an action for each item.
221
-
222
- based on the same matching behavior used by Redis... hopefully...
223
- https://github.com/antirez/redis/blob/d680eb6dbdf2d2030cb96edfb089be1e2a775ac1/src/util.c#L47
224
- */
225
- void fio_dict_each_match_glob(fio_dict_s *dict, void *pattern, size_t len,
226
- void (*action)(fio_dict_s *node, void *arg),
227
- void *arg) {
228
-
229
- if (!dict || !pattern || !action)
230
- return;
231
- fio_dict_s *child, *head = dict->parent;
232
- uint8_t *pos = pattern;
233
-
234
- while (len && dict) {
235
-
236
- if (*pos == '*') {
237
- /* eat up all '*' and match whatever */
238
- while (*pos == '*' && len) {
239
- len--;
240
- pos++;
241
- }
242
- if (!len) {
243
- fio_dict_each(dict, action, arg);
244
- return;
245
- }
246
- /* test each "tail"... (brrr). */
247
- head = dict->parent;
248
- uint8_t tr = 0;
249
- while (dict != head) {
250
- glob_top:
251
- while (tr < 16) {
252
- /* walk child */
253
- if ((child = dict->trie[tr])) {
254
- dict = child;
255
- tr = 0;
256
- goto glob_top;
257
- }
258
- tr++;
259
- }
260
- fio_dict_each_match_glob(dict, pos, len, action, arg);
261
- tr = dict->trie_val + 1;
262
- dict = dict->parent;
263
- }
264
- fio_dict_each_match_glob(dict, pos, len, action, arg);
265
- return;
266
- }
267
-
268
- if (*pos == '?') {
269
- pos++;
270
- len--;
271
- for (size_t i = 0; i < 256; i++) {
272
- if (dict->trie[i & 0xf])
273
- fio_dict_each_match_glob(dict->trie[i & 0xf]->trie[(i >> 4) & 0xf],
274
- pos, len, action, arg);
275
- }
276
- return;
277
- }
278
-
279
- if (*pos == '[') {
280
- int state = 0;
281
- uint8_t map[256] = {0};
282
- pos++;
283
- len--;
284
- if (*pos == '^') {
285
- state = 1;
286
- pos++;
287
- len--;
288
- }
289
- if (!len)
290
- return; /* pattern error */
291
- while (*pos != ']' && len) {
292
- if (*pos == '\\') {
293
- pos++;
294
- len--;
295
- }
296
- if (pos[1] == '-') {
297
- if (len < 4) {
298
- return; /* pattern error */
299
- }
300
- uint8_t end, start;
301
- start = *pos;
302
- pos += 2;
303
- len -= 2;
304
- if (*pos == '\\') {
305
- pos++;
306
- len--;
307
- }
308
- end = *pos;
309
- if (start > end) {
310
- uint8_t tmp;
311
- tmp = start;
312
- start = end;
313
- end = tmp;
314
- }
315
- while (start < end)
316
- map[start++] = 1;
317
- map[end] = 1; /* prevent endless loop where `end == 255`*/
318
- } else
319
- map[*pos] = 1;
320
- pos++;
321
- len--;
322
- }
323
- if (!len) {
324
- return;
325
- }
326
- pos++;
327
- len--;
328
- for (size_t i = 0; i < 256; i++) {
329
- /* code */
330
- if (map[i] == state)
331
- continue;
332
- if (dict->trie[i & 0xf])
333
- fio_dict_each_match_glob(dict->trie[i & 0xf]->trie[(i >> 4) & 0xf],
334
- pos, len, action, arg);
335
- }
336
- return;
337
- }
338
-
339
- if (*pos == '\\' && len > 1) {
340
- pos++;
341
- len--;
342
- }
343
- dict = fio_dict_step_inline(dict, *pos);
344
- pos++;
345
- len--;
346
- }
347
-
348
- if (dict && dict->used)
349
- action(dict, arg);
350
- }
351
-
352
- /** A binary glob matching helper. Returns 1 on match, otherwise returns 0. */
353
- int fio_glob_match(uint8_t *data, size_t data_len, uint8_t *pattern,
354
- size_t pat_len) {
355
- /* adapted and rewritten, with thankfulness, from the code at:
356
- * https://github.com/opnfv/kvmfornfv/blob/master/kernel/lib/glob.c
357
- *
358
- * Original version's copyright:
359
- * Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
360
- * Under the MIT license.
361
- */
362
-
363
- /*
364
- * Backtrack to previous * on mismatch and retry starting one
365
- * character later in the string. Because * matches all characters
366
- * (no exception for /), it can be easily proved that there's
367
- * never a need to backtrack multiple levels.
368
- */
369
- uint8_t *back_pat = NULL, *back_str = data;
370
- size_t back_pat_len = 0, back_str_len = data_len;
371
-
372
- /*
373
- * Loop over each token (character or class) in pat, matching
374
- * it against the remaining unmatched tail of str. Return false
375
- * on mismatch, or true after matching the trailing nul bytes.
376
- */
377
- while (data_len) {
378
- uint8_t c = *data++;
379
- uint8_t d = *pattern++;
380
- data_len--;
381
- pat_len--;
382
-
383
- switch (d) {
384
- case '?': /* Wildcard: anything goes */
385
- break;
386
-
387
- case '*': /* Any-length wildcard */
388
- if (!pat_len) /* Optimize trailing * case */
389
- return 1;
390
- back_pat = pattern;
391
- back_pat_len = pat_len;
392
- back_str = --data; /* Allow zero-length match */
393
- back_str_len = ++data_len;
394
- break;
395
-
396
- case '[': { /* Character class */
397
- uint8_t match = 0, inverted = (*pattern == '^');
398
- uint8_t *cls = pattern + inverted;
399
- uint8_t a = *cls++;
400
-
401
- /*
402
- * Iterate over each span in the character class.
403
- * A span is either a single character a, or a
404
- * range a-b. The first span may begin with ']'.
405
- */
406
- do {
407
- uint8_t b = a;
408
-
409
- if (cls[0] == '-' && cls[1] != ']') {
410
- b = cls[1];
411
-
412
- cls += 2;
413
- if (a > b) {
414
- uint8_t tmp = a;
415
- a = b;
416
- b = tmp;
417
- }
418
- }
419
- match |= (a <= c && c <= b);
420
- } while ((a = *cls++) != ']');
421
-
422
- if (match == inverted)
423
- goto backtrack;
424
- pat_len -= cls - pattern;
425
- pattern = cls;
426
-
427
- } break;
428
- case '\\':
429
- d = *pattern++;
430
- pat_len--;
431
- /*FALLTHROUGH*/
432
- default: /* Literal character */
433
- if (c == d)
434
- break;
435
- backtrack:
436
- if (!back_pat)
437
- return 0; /* No point continuing */
438
- /* Try again from last *, one character later in str. */
439
- pattern = back_pat;
440
- data = ++back_str;
441
- data_len = --back_str_len;
442
- pat_len = back_pat_len;
443
- }
444
- }
445
- return !data_len && !pat_len;
446
- }