qr_reader-native 0.0.1

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 (95) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE-mruby.txt +22 -0
  3. data/LICENSE-spinel.txt +19 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +61 -0
  6. data/ext/qr_reader_native/SPINEL_VERSION +1 -0
  7. data/ext/qr_reader_native/extconf.rb +8 -0
  8. data/ext/qr_reader_native/mruby/error.h +13 -0
  9. data/ext/qr_reader_native/mruby/internal.h +145 -0
  10. data/ext/qr_reader_native/mruby/string.h +22 -0
  11. data/ext/qr_reader_native/mruby.h +93 -0
  12. data/ext/qr_reader_native/mruby_shim.h +118 -0
  13. data/ext/qr_reader_native/qr_reader_native.c +13513 -0
  14. data/ext/qr_reader_native/qr_reader_native.h +29 -0
  15. data/ext/qr_reader_native/qr_reader_native_ext.c +598 -0
  16. data/ext/qr_reader_native/re_cased.h +71 -0
  17. data/ext/qr_reader_native/re_compile.c +5784 -0
  18. data/ext/qr_reader_native/re_ctype.h +3540 -0
  19. data/ext/qr_reader_native/re_exec.c +2190 -0
  20. data/ext/qr_reader_native/re_internal.h +671 -0
  21. data/ext/qr_reader_native/re_prop.h +4629 -0
  22. data/ext/qr_reader_native/re_spinel.c +363 -0
  23. data/ext/qr_reader_native/re_spinel.h +22 -0
  24. data/ext/qr_reader_native/re_spinel_utf8.inc +97 -0
  25. data/ext/qr_reader_native/re_utf8.c +156 -0
  26. data/ext/qr_reader_native/sp_alloc.c +1447 -0
  27. data/ext/qr_reader_native/sp_alloc.h +1196 -0
  28. data/ext/qr_reader_native/sp_argf.h +33 -0
  29. data/ext/qr_reader_native/sp_array.c +1052 -0
  30. data/ext/qr_reader_native/sp_array.h +456 -0
  31. data/ext/qr_reader_native/sp_bigint.c +5826 -0
  32. data/ext/qr_reader_native/sp_bigint.h +117 -0
  33. data/ext/qr_reader_native/sp_cold.c +5259 -0
  34. data/ext/qr_reader_native/sp_compat.h +402 -0
  35. data/ext/qr_reader_native/sp_core.c +818 -0
  36. data/ext/qr_reader_native/sp_core.h +56 -0
  37. data/ext/qr_reader_native/sp_crypto.c +877 -0
  38. data/ext/qr_reader_native/sp_crypto.h +169 -0
  39. data/ext/qr_reader_native/sp_dtoa.c +1533 -0
  40. data/ext/qr_reader_native/sp_dtoa.h +29 -0
  41. data/ext/qr_reader_native/sp_encoding_names.h +172 -0
  42. data/ext/qr_reader_native/sp_enum.h +86 -0
  43. data/ext/qr_reader_native/sp_exc.c +1185 -0
  44. data/ext/qr_reader_native/sp_exc.h +186 -0
  45. data/ext/qr_reader_native/sp_exc_ctx.h +56 -0
  46. data/ext/qr_reader_native/sp_fiber.c +889 -0
  47. data/ext/qr_reader_native/sp_fiber.h +162 -0
  48. data/ext/qr_reader_native/sp_fiber_ctx.h +84 -0
  49. data/ext/qr_reader_native/sp_format.c +695 -0
  50. data/ext/qr_reader_native/sp_format.h +83 -0
  51. data/ext/qr_reader_native/sp_gc.c +1793 -0
  52. data/ext/qr_reader_native/sp_gc.h +762 -0
  53. data/ext/qr_reader_native/sp_hash.c +131 -0
  54. data/ext/qr_reader_native/sp_hash.h +131 -0
  55. data/ext/qr_reader_native/sp_inspect.c +215 -0
  56. data/ext/qr_reader_native/sp_inspect.h +128 -0
  57. data/ext/qr_reader_native/sp_io.c +1676 -0
  58. data/ext/qr_reader_native/sp_io.h +272 -0
  59. data/ext/qr_reader_native/sp_iobuffer.c +1014 -0
  60. data/ext/qr_reader_native/sp_iobuffer.h +167 -0
  61. data/ext/qr_reader_native/sp_marshal.c +487 -0
  62. data/ext/qr_reader_native/sp_marshal.h +60 -0
  63. data/ext/qr_reader_native/sp_net.c +1029 -0
  64. data/ext/qr_reader_native/sp_net.h +205 -0
  65. data/ext/qr_reader_native/sp_pack.c +1254 -0
  66. data/ext/qr_reader_native/sp_poly_cold.c +1220 -0
  67. data/ext/qr_reader_native/sp_proc.c +410 -0
  68. data/ext/qr_reader_native/sp_proc.h +327 -0
  69. data/ext/qr_reader_native/sp_process.c +547 -0
  70. data/ext/qr_reader_native/sp_process_status.c +211 -0
  71. data/ext/qr_reader_native/sp_process_status.h +66 -0
  72. data/ext/qr_reader_native/sp_random.c +287 -0
  73. data/ext/qr_reader_native/sp_random.h +52 -0
  74. data/ext/qr_reader_native/sp_range.h +144 -0
  75. data/ext/qr_reader_native/sp_re.c +1379 -0
  76. data/ext/qr_reader_native/sp_re.h +186 -0
  77. data/ext/qr_reader_native/sp_re_names.h +59 -0
  78. data/ext/qr_reader_native/sp_sched.c +4044 -0
  79. data/ext/qr_reader_native/sp_sched.h +295 -0
  80. data/ext/qr_reader_native/sp_slab.c +1507 -0
  81. data/ext/qr_reader_native/sp_str.c +1462 -0
  82. data/ext/qr_reader_native/sp_str.h +306 -0
  83. data/ext/qr_reader_native/sp_str_crypt.c +23 -0
  84. data/ext/qr_reader_native/sp_string.c +92 -0
  85. data/ext/qr_reader_native/sp_string.h +253 -0
  86. data/ext/qr_reader_native/sp_system.c +78 -0
  87. data/ext/qr_reader_native/sp_system.h +18 -0
  88. data/ext/qr_reader_native/sp_time.c +860 -0
  89. data/ext/qr_reader_native/sp_time.h +100 -0
  90. data/ext/qr_reader_native/sp_types.h +292 -0
  91. data/ext/qr_reader_native/spinel_rt.h +19017 -0
  92. data/ext/qr_reader_native/unicase.c +399 -0
  93. data/ext/qr_reader_native/unicase.h +901 -0
  94. data/lib/qr_reader/native.rb +6 -0
  95. metadata +153 -0
@@ -0,0 +1,363 @@
1
+ /*
2
+ ** re_spinel.c - the regexp engine's entry points for spinel
3
+ **
4
+ ** The engine in this directory is mruby-regexp's, taken from mruby as mruby
5
+ ** carries it (see shim/mruby.h). This file is the part that is spinel's own:
6
+ ** the mruby API the engine calls, answered with the C library, and the
7
+ ** re_compile / re_exec / re_free surface the runtime (lib/sp_re.c, the
8
+ ** strscan package) and the compiler's literal check (src/re_lit_check.c)
9
+ ** have always called. A compiled pattern is handed out as the engine's
10
+ ** mrb_regexp_pattern inside a record that also keeps the pattern text, for
11
+ ** Regexp#source and #inspect.
12
+ */
13
+ #include <stdarg.h>
14
+ #include <stdio.h>
15
+ #include <stdbool.h>
16
+ #include "re_spinel.h"
17
+ #include <mruby/string.h>
18
+ #include <mruby/error.h>
19
+
20
+ #ifdef SP_THREADS
21
+ # define RE_TLS _Thread_local
22
+ #else
23
+ # define RE_TLS
24
+ #endif
25
+
26
+ static mrb_state re_mrb; /* nothing reads it; the engine passes it along */
27
+
28
+ /* ---- memory ---- */
29
+
30
+ static __attribute__((noreturn)) void re_nomem(void) {
31
+ fputs("[FATAL] regexp: failed to allocate memory\n", stderr);
32
+ abort();
33
+ }
34
+ void *mrb_malloc(mrb_state *mrb, size_t len) {
35
+ (void)mrb;
36
+ void *p = malloc(len ? len : 1);
37
+ if (!p) re_nomem();
38
+ return p;
39
+ }
40
+ void *mrb_malloc_simple(mrb_state *mrb, size_t len) {
41
+ (void)mrb;
42
+ return malloc(len ? len : 1);
43
+ }
44
+ void *mrb_calloc(mrb_state *mrb, size_t nelem, size_t len) {
45
+ (void)mrb;
46
+ void *p = calloc(nelem ? nelem : 1, len ? len : 1);
47
+ if (!p) re_nomem();
48
+ return p;
49
+ }
50
+ void *mrb_realloc(mrb_state *mrb, void *p, size_t len) {
51
+ (void)mrb;
52
+ void *q = realloc(p, len ? len : 1);
53
+ if (!q) re_nomem();
54
+ return q;
55
+ }
56
+ void *mrb_realloc_simple(mrb_state *mrb, void *p, size_t len) {
57
+ (void)mrb;
58
+ return realloc(p, len ? len : 1);
59
+ }
60
+ void mrb_free(mrb_state *mrb, void *p) { (void)mrb; free(p); }
61
+
62
+ /* ---- the strings a compile makes ----
63
+ mruby's GC collects these; here every one made while a compile runs is on
64
+ one list, and the compile releases the list when it returns or raises. */
65
+
66
+ static RE_TLS struct sp_re_str *re_strs;
67
+
68
+ static mrb_value re_str_alloc(mrb_int capa) {
69
+ struct sp_re_str *s = (struct sp_re_str *)mrb_malloc(NULL, sizeof *s);
70
+ s->capa = capa < 16 ? 16 : capa;
71
+ s->ptr = (char *)mrb_malloc(NULL, (size_t)s->capa + 1);
72
+ s->len = 0;
73
+ s->ptr[0] = 0;
74
+ s->next = re_strs;
75
+ re_strs = s;
76
+ return s;
77
+ }
78
+ static void re_strs_release(void) {
79
+ while (re_strs) {
80
+ struct sp_re_str *n = re_strs->next;
81
+ free(re_strs->ptr);
82
+ free(re_strs);
83
+ re_strs = n;
84
+ }
85
+ }
86
+ static void re_str_reserve(mrb_value s, mrb_int need) {
87
+ if (need <= s->capa) return;
88
+ mrb_int capa = s->capa;
89
+ while (capa < need) capa *= 2;
90
+ s->ptr = (char *)mrb_realloc(NULL, s->ptr, (size_t)capa + 1);
91
+ s->capa = capa;
92
+ }
93
+ mrb_value mrb_str_cat(mrb_state *mrb, mrb_value str, const char *p, size_t len) {
94
+ (void)mrb;
95
+ re_str_reserve(str, str->len + (mrb_int)len);
96
+ memcpy(str->ptr + str->len, p, len);
97
+ str->len += (mrb_int)len;
98
+ str->ptr[str->len] = 0;
99
+ return str;
100
+ }
101
+ mrb_value mrb_str_new(mrb_state *mrb, const char *p, size_t len) {
102
+ mrb_value s = re_str_alloc((mrb_int)len);
103
+ if (p) mrb_str_cat(mrb, s, p, len);
104
+ else { s->len = (mrb_int)len; memset(s->ptr, 0, len + 1); }
105
+ return s;
106
+ }
107
+ mrb_value mrb_str_new_cstr(mrb_state *mrb, const char *p) {
108
+ return mrb_str_new(mrb, p, strlen(p));
109
+ }
110
+ mrb_value mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len) {
111
+ (void)mrb;
112
+ re_str_reserve(str, len);
113
+ if (len > str->len) memset(str->ptr + str->len, 0, (size_t)(len - str->len));
114
+ str->len = len;
115
+ str->ptr[len] = 0;
116
+ return str;
117
+ }
118
+ void *mrb_temp_alloc(mrb_state *mrb, size_t size) {
119
+ return RSTRING_PTR(mrb_str_new(mrb, NULL, size));
120
+ }
121
+
122
+ /* mruby's format, for the directives the engine uses: %l (a pointer and a
123
+ size_t length), %v (a String), %c (a char, passed as an int), %d (an int),
124
+ and a backslash that takes the next character literally */
125
+ mrb_value mrb_format(mrb_state *mrb, const char *fmt, ...) {
126
+ mrb_value s = re_str_alloc(64);
127
+ va_list ap;
128
+ va_start(ap, fmt);
129
+ for (const char *p = fmt; *p; p++) {
130
+ /* a backslash takes the next character as it is, as mruby's does */
131
+ if (*p == '\\' && p[1]) { p++; mrb_str_cat(mrb, s, p, 1); continue; }
132
+ if (*p != '%' || !p[1]) { mrb_str_cat(mrb, s, p, 1); continue; }
133
+ p++;
134
+ switch (*p) {
135
+ case 'l': {
136
+ const char *q = va_arg(ap, const char *);
137
+ size_t n = va_arg(ap, size_t);
138
+ mrb_str_cat(mrb, s, q, n);
139
+ break;
140
+ }
141
+ case 'v': {
142
+ mrb_value v = va_arg(ap, mrb_value);
143
+ if (v) mrb_str_cat(mrb, s, v->ptr, (size_t)v->len);
144
+ break;
145
+ }
146
+ case 'c': { char ch = (char)va_arg(ap, int); mrb_str_cat(mrb, s, &ch, 1); break; }
147
+ case 'd': {
148
+ char buf[24];
149
+ int n = snprintf(buf, sizeof buf, "%d", va_arg(ap, int));
150
+ mrb_str_cat(mrb, s, buf, (size_t)n);
151
+ break;
152
+ }
153
+ default: mrb_str_cat(mrb, s, p, 1); break;
154
+ }
155
+ }
156
+ va_end(ap);
157
+ return s;
158
+ }
159
+
160
+ /* ---- the one exception the engine raises ---- */
161
+
162
+ /* Issue #781: the program installs a handler at startup that raises its
163
+ RegexpError (sp_raise_cls is per translation unit, so the library reaches
164
+ it through this pointer); it does not return. Without one the message is
165
+ printed and the process exits, as it was. */
166
+ static void (*sp_re_error_handler)(const char *msg) = NULL;
167
+ void sp_re_set_error_handler(void (*fn)(const char *msg)) {
168
+ sp_re_error_handler = fn;
169
+ }
170
+
171
+ static RE_TLS char re_errbuf[1024];
172
+
173
+ static __attribute__((noreturn)) void re_raise_msg(const char *msg, size_t len) {
174
+ if (len >= sizeof re_errbuf) len = sizeof re_errbuf - 1;
175
+ memcpy(re_errbuf, msg, len);
176
+ re_errbuf[len] = 0;
177
+ re_strs_release(); /* the message is copied out: nothing reads the list now */
178
+ if (sp_re_error_handler) sp_re_error_handler(re_errbuf);
179
+ fprintf(stderr, "RegexpError: %s\n", re_errbuf);
180
+ exit(1);
181
+ }
182
+
183
+ struct RClass *mrb_exc_get_id(mrb_state *mrb, mrb_sym name) {
184
+ (void)mrb; (void)name;
185
+ return NULL;
186
+ }
187
+ mrb_value mrb_exc_new_str(mrb_state *mrb, struct RClass *c, mrb_value str) {
188
+ (void)mrb; (void)c;
189
+ return str;
190
+ }
191
+ void mrb_exc_raise(mrb_state *mrb, mrb_value exc) {
192
+ (void)mrb;
193
+ re_raise_msg(exc ? exc->ptr : "invalid pattern", exc ? (size_t)exc->len : 15);
194
+ }
195
+
196
+ /* A compile error quotes the pattern as Regexp#inspect would, `/src/flags`.
197
+ Ruby's `m` is RE_FLAG_DOTALL to spinel, which is the bit spinel passes. */
198
+ void mrb_re_flags_cat(mrb_state *mrb, mrb_value str, uint32_t flags) {
199
+ if (flags & RE_FLAG_DOTALL) mrb_str_cat(mrb, str, "m", 1);
200
+ if (flags & RE_FLAG_IGNORECASE) mrb_str_cat(mrb, str, "i", 1);
201
+ if (flags & RE_FLAG_EXTENDED) mrb_str_cat(mrb, str, "x", 1);
202
+ }
203
+
204
+ /* ---- UTF-8 ---- */
205
+
206
+ #include "re_spinel_utf8.inc"
207
+
208
+ int re_utf8_charlen(const char *s, const char *end) {
209
+ return (int)mrb_re_charlen(s, end, FALSE);
210
+ }
211
+
212
+ /* ---- spinel's surface ---- */
213
+
214
+ /* The engine's pattern and the text it was compiled from. The pattern is the
215
+ first member, so a pattern pointer is the record's. */
216
+ typedef struct {
217
+ mrb_regexp_pattern pat;
218
+ char *source;
219
+ uint32_t source_len;
220
+ /* the group names as C strings: the engine keeps each as a pointer and a
221
+ length into one arena, with nothing between them, and spinel's side
222
+ reads a name up to its NUL */
223
+ char **names;
224
+ } sp_re_record;
225
+
226
+ mrb_regexp_pattern *re_compile(const char *pattern, mrb_int len, uint32_t flags) {
227
+ sp_re_record *r = (sp_re_record *)mrb_calloc(NULL, 1, sizeof *r);
228
+ r->source = (char *)mrb_malloc(NULL, (size_t)len + 1);
229
+ memcpy(r->source, pattern, (size_t)len);
230
+ r->source[len] = 0;
231
+ r->source_len = (uint32_t)len;
232
+ mrb_re_compile(&re_mrb, &r->pat, pattern, len, flags, FALSE);
233
+ re_strs_release();
234
+ if (r->pat.num_named) {
235
+ r->names = (char **)mrb_calloc(NULL, r->pat.num_named, sizeof(char *));
236
+ for (uint16_t i = 0; i < r->pat.num_named; i++) {
237
+ const re_named_capture *nc = &r->pat.named_captures[i];
238
+ r->names[i] = (char *)mrb_malloc(NULL, (size_t)nc->name_len + 1);
239
+ memcpy(r->names[i], nc->name, nc->name_len);
240
+ r->names[i][nc->name_len] = 0;
241
+ }
242
+ }
243
+ return &r->pat;
244
+ }
245
+
246
+ void re_free(mrb_regexp_pattern *pat) {
247
+ if (!pat) return;
248
+ sp_re_record *r = (sp_re_record *)pat;
249
+ free(r->source);
250
+ if (r->names) {
251
+ for (uint16_t i = 0; i < pat->num_named; i++) free(r->names[i]);
252
+ free(r->names);
253
+ }
254
+ /* mrb_re_free() releases the pattern block too, which is the record */
255
+ mrb_re_free(&re_mrb, pat);
256
+ }
257
+
258
+ /* A search that stops at one of the engine's limits has no answer to give:
259
+ what it found by then is neither a shorter nor a later match. mruby raises
260
+ RegexpError there, and so does this; the engine used to answer no match. */
261
+ int re_exec(const mrb_regexp_pattern *pat, const char *str, mrb_int len, mrb_int start,
262
+ int *captures, int captures_size, int binary) {
263
+ int n = mrb_re_exec(&re_mrb, pat, str, len, start, captures, captures_size, (mrb_bool)(binary != 0));
264
+ if (n >= 0) return n;
265
+ if (n == RE_NOMEM) re_nomem();
266
+ const char *m = n == RE_OVER_STEP_LIMIT ? "step limit over (MRB_REGEXP_STEP_LIMIT)"
267
+ : "stack limit over (MRB_REGEXP_STACK_LIMIT)";
268
+ re_raise_msg(m, strlen(m));
269
+ }
270
+
271
+ /* ---- named captures ---- */
272
+
273
+ int re_num_named(const mrb_regexp_pattern *pat) {
274
+ return pat ? (int)pat->num_named : 0;
275
+ }
276
+ const char *re_named_name(const mrb_regexp_pattern *pat, int i, int *group_out) {
277
+ if (!pat || i < 0 || i >= (int)pat->num_named) return NULL;
278
+ if (group_out) *group_out = (int)pat->named_captures[i].group;
279
+ return ((const sp_re_record *)pat)->names[i];
280
+ }
281
+ /* group index -> its name (NUL-terminated copy in a static rotating buffer),
282
+ or NULL when the group is positional. For MatchData#inspect. */
283
+ const char *re_group_name(const mrb_regexp_pattern *pat, int group) {
284
+ static RE_TLS char buf[4][64];
285
+ static RE_TLS int rot = 0;
286
+ if (!pat) return NULL;
287
+ for (int k = 0; k < pat->num_named; k++) {
288
+ if (pat->named_captures[k].group == group) {
289
+ size_t n = pat->named_captures[k].name_len;
290
+ if (n > 63) n = 63;
291
+ char *o = buf[rot = (rot + 1) & 3];
292
+ memcpy(o, pat->named_captures[k].name, n);
293
+ o[n] = 0;
294
+ return o;
295
+ }
296
+ }
297
+ return NULL;
298
+ }
299
+ /* A name may repeat across alternation branches; CRuby resolves to the last
300
+ declared group, so keep scanning and take the final match. */
301
+ int re_named_group(const mrb_regexp_pattern *pat, const char *name) {
302
+ if (!pat || !name) return -1;
303
+ size_t nlen = strlen(name);
304
+ int group = -1;
305
+ for (uint16_t i = 0; i < pat->num_named; i++) {
306
+ const re_named_capture *nc = &pat->named_captures[i];
307
+ if (nc->name_len == nlen && memcmp(nc->name, name, nlen) == 0)
308
+ group = (int)nc->group;
309
+ }
310
+ return group;
311
+ }
312
+
313
+ /* ---- Regexp's readers ---- */
314
+
315
+ const char *sp_re_source(void *vpat) {
316
+ sp_re_record *r = (sp_re_record *)vpat;
317
+ return (r && r->source) ? r->source : "";
318
+ }
319
+ /* ...and its byte length: the text may hold a NUL, which a strlen stops at */
320
+ uint32_t sp_re_source_len(void *vpat) {
321
+ sp_re_record *r = (sp_re_record *)vpat;
322
+ return (r && r->source) ? r->source_len : 0;
323
+ }
324
+ /* Regexp#options: CRuby's public option bits IGNORECASE=1, EXTENDED=2,
325
+ MULTILINE=4 (the /m "dot matches newline", RE_FLAG_DOTALL here). Returns
326
+ the runtime's sp_int (intptr_t), as sp_re.h declares it. */
327
+ intptr_t sp_re_options(void *vpat) {
328
+ mrb_regexp_pattern *pat = (mrb_regexp_pattern *)vpat;
329
+ uint32_t f = pat ? pat->flags : 0;
330
+ intptr_t o = 0;
331
+ if (f & RE_FLAG_IGNORECASE) o |= 1;
332
+ if (f & RE_FLAG_EXTENDED) o |= 2;
333
+ if (f & RE_FLAG_DOTALL) o |= 4;
334
+ return o;
335
+ }
336
+ /* Regexp#== / #eql? is source AND options: /ab/ and /ab/i differ (#3631).
337
+ Declared sp_bool (a C bool) by the runtime. */
338
+ bool sp_re_eq(void *a, void *b) {
339
+ if (a == b) return 1;
340
+ if (!a || !b) return 0;
341
+ uint32_t la = sp_re_source_len(a), lb = sp_re_source_len(b);
342
+ return la == lb && memcmp(sp_re_source(a), sp_re_source(b), la) == 0 &&
343
+ sp_re_options(a) == sp_re_options(b);
344
+ }
345
+ bool sp_re_casefold_p(void *vpat) {
346
+ mrb_regexp_pattern *pat = (mrb_regexp_pattern *)vpat;
347
+ return (pat && (pat->flags & RE_FLAG_IGNORECASE)) ? true : false;
348
+ }
349
+ /* The engine's own flag word, for re-compiling a copy (Regexp.new(re)) with
350
+ the source pattern's exact options. */
351
+ uint32_t sp_re_raw_flags(void *vpat) {
352
+ mrb_regexp_pattern *pat = (mrb_regexp_pattern *)vpat;
353
+ return pat ? pat->flags : 0;
354
+ }
355
+ /* The public Regexp option bits Regexp.new's second argument carries, as the
356
+ flag bits re_compile takes (#3055). */
357
+ uint32_t sp_re_opts_to_flags(intptr_t o) {
358
+ uint32_t f = 0;
359
+ if (o & 1) f |= RE_FLAG_IGNORECASE;
360
+ if (o & 2) f |= RE_FLAG_EXTENDED;
361
+ if (o & 4) f |= RE_FLAG_DOTALL; /* Ruby MULTILINE == "dot matches newline" */
362
+ return f;
363
+ }
@@ -0,0 +1,22 @@
1
+ /*
2
+ ** re_spinel.h - spinel's surface of the regexp engine (re_spinel.c)
3
+ **
4
+ ** The engine's own header, re_internal.h, is mruby-regexp's; the calls spinel
5
+ ** makes into the engine are these. lib/sp_re.h and the strscan package name
6
+ ** them again for the runtime, which does not include the engine's headers.
7
+ */
8
+ #ifndef SP_RE_SPINEL_H
9
+ #define SP_RE_SPINEL_H
10
+ #include "re_internal.h"
11
+
12
+ mrb_regexp_pattern *re_compile(const char *pattern, mrb_int len, uint32_t flags);
13
+ void re_free(mrb_regexp_pattern *pat);
14
+ int re_exec(const mrb_regexp_pattern *pat, const char *str, mrb_int len, mrb_int start,
15
+ int *captures, int captures_size, int binary);
16
+ void sp_re_set_error_handler(void (*fn)(const char *msg));
17
+ int re_utf8_charlen(const char *s, const char *end);
18
+ int re_num_named(const mrb_regexp_pattern *pat);
19
+ const char *re_named_name(const mrb_regexp_pattern *pat, int i, int *group_out);
20
+ const char *re_group_name(const mrb_regexp_pattern *pat, int group);
21
+ int re_named_group(const mrb_regexp_pattern *pat, const char *name);
22
+ #endif
@@ -0,0 +1,97 @@
1
+ /* re_spinel_utf8.inc - mruby's src/string.c UTF-8 readers the engine calls, as
2
+ mruby spells them (included by re_spinel.c) */
3
+ mrb_int
4
+ mrb_utf8_to_buf(char *buf, mrb_int cp)
5
+ {
6
+ if (cp < 0) {
7
+ return 0;
8
+ }
9
+ else if (cp < 0x80) {
10
+ buf[0] = (char)cp;
11
+ return 1;
12
+ }
13
+ else if (cp < 0x800) {
14
+ buf[0] = (char)(0xC0 | (cp >> 6));
15
+ buf[1] = (char)(0x80 | (cp & 0x3F));
16
+ return 2;
17
+ }
18
+ else if (cp < 0x10000) {
19
+ buf[0] = (char)(0xE0 | (cp >> 12));
20
+ buf[1] = (char)(0x80 | ((cp >> 6) & 0x3F));
21
+ buf[2] = (char)(0x80 | (cp & 0x3F));
22
+ return 3;
23
+ }
24
+ else if (cp <= 0x10FFFF) {
25
+ buf[0] = (char)(0xF0 | (cp >> 18));
26
+ buf[1] = (char)(0x80 | ((cp >> 12) & 0x3F));
27
+ buf[2] = (char)(0x80 | ((cp >> 6) & 0x3F));
28
+ buf[3] = (char)(0x80 | (cp & 0x3F));
29
+ return 4;
30
+ }
31
+ return 0; /* above U+10FFFF */
32
+ }
33
+
34
+ #define utf8_islead(c) ((unsigned char)((c)&0xc0) != 0x80)
35
+
36
+ /* What a lead byte's second byte may be for the sequence to spell a
37
+ character under RFC 3629 (Unicode D93b), one pair per lead byte from
38
+ 0xC0: the floor of each length (0xE0 A0, 0xF0 90; 0xC0 and 0xC1 have
39
+ nothing to spell), the UTF-16 surrogates (0xED up to 9F), U+10FFFF
40
+ (0xF4 up to 8F), and nothing at all for 0xF5 and above. This is the one
41
+ view the scan keeps none of; unpack("U") in mruby-pack holds its own. */
42
+ #define R(lo, hi) {0x##lo, 0x##hi}
43
+ static const uint8_t utf8_rfc3629_bounds[64][2] = {
44
+ R(C0,BF), R(C0,BF), R(80,BF), R(80,BF), R(80,BF), R(80,BF), R(80,BF), R(80,BF), /* C0..C7 */
45
+ R(80,BF), R(80,BF), R(80,BF), R(80,BF), R(80,BF), R(80,BF), R(80,BF), R(80,BF), /* C8..CF */
46
+ R(80,BF), R(80,BF), R(80,BF), R(80,BF), R(80,BF), R(80,BF), R(80,BF), R(80,BF), /* D0..D7 */
47
+ R(80,BF), R(80,BF), R(80,BF), R(80,BF), R(80,BF), R(80,BF), R(80,BF), R(80,BF), /* D8..DF */
48
+ R(A0,BF), R(80,BF), R(80,BF), R(80,BF), R(80,BF), R(80,BF), R(80,BF), R(80,BF), /* E0..E7 */
49
+ R(80,BF), R(80,BF), R(80,BF), R(80,BF), R(80,BF), R(80,9F), R(80,BF), R(80,BF), /* E8..EF */
50
+ R(90,BF), R(80,BF), R(80,BF), R(80,BF), R(80,8F), R(80,7F), R(80,7F), R(80,7F), /* F0..F7 */
51
+ R(80,7F), R(80,7F), R(80,7F), R(80,7F), R(80,7F), R(80,7F), R(80,7F), R(80,7F), /* F8..FF */
52
+ };
53
+ #undef R
54
+
55
+ mrb_int
56
+ mrb_utf8len(const char* p, const char* e)
57
+ {
58
+ mrb_int n = mrb_utf8_scan(p, e, NULL, utf8_rfc3629_bounds);
59
+ return n < 0 ? 1 : n;
60
+ }
61
+
62
+ /* The byte the character covering `p` starts at, or `p` itself when `p` is
63
+ already a character boundary. A continuation byte belongs to the character
64
+ that reaches it; one that no lead byte reaches belongs to none and stands as
65
+ a character of its own. Whether a lead byte reaches is mrb_utf8len()'s
66
+ answer, so the boundaries found here are the ones the character count is
67
+ taken over. Reading back three bytes covers it, since nothing longer than
68
+ four bytes spells a character. */
69
+ const char*
70
+ mrb_utf8_char_head(const char *beg, const char *p, const char *end)
71
+ {
72
+ if (p >= end || utf8_islead(p[0])) return p;
73
+ for (mrb_int back = 1; back <= 3 && back <= p - beg; back++) {
74
+ const char *lead = p - back;
75
+ if (!utf8_islead(lead[0])) continue; /* another continuation byte */
76
+ return mrb_utf8len(lead, end) > back ? lead : p;
77
+ }
78
+ return p;
79
+ }
80
+
81
+ /* Decode a UTF-8 character and return its codepoint.
82
+ *lenp is set to the byte length consumed. What mrb_utf8len() rejects is
83
+ rejected here by the same view, so those consume a single byte and come
84
+ back as the lead byte itself. */
85
+ uint32_t
86
+ mrb_utf8_decode(const char *p, const char *e, mrb_int *lenp)
87
+ {
88
+ uint32_t uv;
89
+ mrb_int n = mrb_utf8_scan(p, e, &uv, utf8_rfc3629_bounds);
90
+
91
+ if (n < 0) {
92
+ *lenp = 1;
93
+ return (uint8_t)p[0];
94
+ }
95
+ *lenp = n;
96
+ return uv;
97
+ }
@@ -0,0 +1,156 @@
1
+ /*
2
+ ** re_utf8.c - case folding, character types and word characters for regexp engine
3
+ **
4
+ ** See Copyright Notice in mruby.h
5
+ */
6
+
7
+ #include "re_internal.h"
8
+
9
+ #ifdef RE_UNICODE_CTYPE
10
+
11
+ #include "re_ctype.h"
12
+
13
+ /* The table numbers its bits in the order re_internal.h names them, so that
14
+ an entry read off it is a re_ctype value as it stands. */
15
+ mrb_static_assert(RE_CTYPE_TABLE_ALPHA == RE_CTYPE_ALPHA &&
16
+ RE_CTYPE_TABLE_UPPER == RE_CTYPE_UPPER &&
17
+ RE_CTYPE_TABLE_LOWER == RE_CTYPE_LOWER &&
18
+ RE_CTYPE_TABLE_DIGIT == RE_CTYPE_DIGIT &&
19
+ RE_CTYPE_TABLE_ALNUM == RE_CTYPE_ALNUM &&
20
+ RE_CTYPE_TABLE_WORD == RE_CTYPE_WORD &&
21
+ RE_CTYPE_TABLE_PUNCT == RE_CTYPE_PUNCT &&
22
+ RE_CTYPE_TABLE_SPACE == RE_CTYPE_SPACE &&
23
+ RE_CTYPE_TABLE_BLANK == RE_CTYPE_BLANK &&
24
+ RE_CTYPE_TABLE_GRAPH == RE_CTYPE_GRAPH &&
25
+ RE_CTYPE_TABLE_PRINT == RE_CTYPE_PRINT &&
26
+ RE_CTYPE_CNTRL >= (1 << RE_CTYPE_MASK_BITS),
27
+ "re_ctype.h and re_internal.h number the types differently");
28
+
29
+ /* The types of a codepoint above ASCII: the set of the run it falls in, which
30
+ is the last run starting at or below it, and cntrl from its range. */
31
+ uint16_t
32
+ mrb_re_ctype(uint32_t cp)
33
+ {
34
+ if (cp < RE_CTYPE_MIN) return 0;
35
+ size_t lo = 0, hi = RE_CTYPE_RUN_COUNT;
36
+ while (hi - lo > 1) {
37
+ size_t mid = lo + (hi - lo) / 2;
38
+ if ((re_ctype_runs[mid] >> RE_CTYPE_MASK_BITS) <= cp) lo = mid;
39
+ else hi = mid;
40
+ }
41
+ uint16_t t = (uint16_t)(re_ctype_runs[lo] & ((1u << RE_CTYPE_MASK_BITS) - 1));
42
+ if (cp >= RE_CTYPE_CNTRL_LO && cp <= RE_CTYPE_CNTRL_HI) t |= RE_CTYPE_CNTRL;
43
+ return t;
44
+ }
45
+
46
+ /* Whether the brackets in a class admit a type: the pair says the type has a
47
+ bit of ctype_yes or lacks a bit of ctype_no, and the masks that an
48
+ intersection writes say it has every bit of ctype_all and none of
49
+ ctype_none. A class with no pair puts only the masks, which is what a
50
+ bracket read on its own never leaves it with. */
51
+ static mrb_bool
52
+ ctype_admits(const re_charclass *cc, uint16_t t)
53
+ {
54
+ if ((cc->ctype_yes | cc->ctype_no) &&
55
+ !((t & cc->ctype_yes) || (~t & cc->ctype_no))) {
56
+ return FALSE;
57
+ }
58
+ return (t & cc->ctype_all) == cc->ctype_all && (t & cc->ctype_none) == 0;
59
+ }
60
+
61
+ /* Whether a class holds a codepoint above ASCII through the POSIX brackets in
62
+ it, once its ranges have said nothing: yes when the brackets admit the
63
+ codepoint's type, and failing that whatever utf8_any says. A byte, tagged
64
+ RE_CLASS_BYTE by the caller, has no type: it is in the class through a
65
+ negated bracket and not through a positive one.
66
+
67
+ Under /i a character is in the class when any character sharing its folding
68
+ is, so the question is put to every one of them, and to each as a whole:
69
+ the brackets are a conjunction once an intersection has been taken, and it
70
+ is one character having to answer all of it rather than a bracket at a time
71
+ finding a different character to answer. The ASCII ones are left out, since
72
+ what the class holds through an ASCII counterpart is in its ranges already;
73
+ see compile_charclass(). */
74
+ mrb_bool
75
+ mrb_re_class_ctype_match(const re_charclass *cc, uint32_t cp)
76
+ {
77
+ if (cp & RE_CLASS_BYTE) return ctype_admits(cc, 0) || cc->utf8_any;
78
+ if (ctype_admits(cc, mrb_re_ctype(cp))) return TRUE;
79
+ if (cc->ctype_fold) {
80
+ uint32_t alt[MRB_UNI_MAX_UNFOLD];
81
+ int n = mrb_uni_case_unfold(cp, alt, MRB_UNI_MAX_UNFOLD);
82
+ for (int i = 0; i < n; i++) {
83
+ if (alt[i] < 128) continue;
84
+ if (ctype_admits(cc, mrb_re_ctype(alt[i]))) return TRUE;
85
+ }
86
+ }
87
+ return cc->utf8_any;
88
+ }
89
+
90
+ uint32_t
91
+ mrb_re_ctype_span(const re_charclass *cc, uint32_t lo, uint32_t hi, mrb_bool *in)
92
+ {
93
+ size_t i = 0, j = RE_CTYPE_RUN_COUNT;
94
+ while (j - i > 1) {
95
+ size_t mid = i + (j - i) / 2;
96
+ if ((re_ctype_runs[mid] >> RE_CTYPE_MASK_BITS) <= lo) i = mid;
97
+ else j = mid;
98
+ }
99
+ uint32_t end = i + 1 < RE_CTYPE_RUN_COUNT
100
+ ? (re_ctype_runs[i + 1] >> RE_CTYPE_MASK_BITS) - 1 : 0x10ffff;
101
+ /* The control range is not a run of its own: mrb_re_ctype() lays it over
102
+ whatever runs it falls in, so it breaks a run the same way one does. */
103
+ if (lo < RE_CTYPE_CNTRL_LO) {
104
+ if (end >= RE_CTYPE_CNTRL_LO) end = RE_CTYPE_CNTRL_LO - 1;
105
+ }
106
+ else if (lo <= RE_CTYPE_CNTRL_HI) {
107
+ if (end > RE_CTYPE_CNTRL_HI) end = RE_CTYPE_CNTRL_HI;
108
+ }
109
+ if (end > hi) end = hi;
110
+ *in = mrb_re_class_ctype_match(cc, lo);
111
+ return end;
112
+ }
113
+
114
+ #endif /* RE_UNICODE_CTYPE */
115
+
116
+ /* Check if character is a "word" character (\w): [a-zA-Z0-9_] */
117
+ mrb_bool
118
+ mrb_re_is_word_char(uint32_t c)
119
+ {
120
+ if (c >= 'a' && c <= 'z') return TRUE;
121
+ if (c >= 'A' && c <= 'Z') return TRUE;
122
+ if (c >= '0' && c <= '9') return TRUE;
123
+ if (c == '_') return TRUE;
124
+ return FALSE;
125
+ }
126
+
127
+ #ifndef RE_UNICODE_CASE
128
+
129
+ #include "re_cased.h"
130
+
131
+ mrb_bool
132
+ mrb_re_needs_case_data(uint32_t lo, uint32_t hi)
133
+ {
134
+ if (hi < RE_CASED_MIN || lo > RE_CASED_MAX) return FALSE;
135
+ for (size_t i = 0; i < RE_CASED_RANGE_COUNT; i++) {
136
+ if (lo <= re_cased_ranges[i][1] && re_cased_ranges[i][0] <= hi) return TRUE;
137
+ }
138
+ return FALSE;
139
+ }
140
+
141
+ #endif /* !RE_UNICODE_CASE */
142
+
143
+ uint32_t
144
+ mrb_re_case_fold(uint32_t cp)
145
+ {
146
+ #ifdef RE_UNICODE_CASE
147
+ return mrb_uni_case_fold(cp);
148
+ #else
149
+ /* Without the option there is no table to walk, and the compiler reaches
150
+ the same two foldings directly, since there are only two. */
151
+ if (cp < 128) return (cp >= 'A' && cp <= 'Z') ? cp + 32 : cp;
152
+ if (cp == RE_FOLD_LONG_S) return 's';
153
+ if (cp == RE_FOLD_KELVIN) return 'k';
154
+ return cp;
155
+ #endif
156
+ }