oj_windows 3.16.15

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 (102) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +44 -0
  3. data/LICENSE +21 -0
  4. data/README.md +164 -0
  5. data/ext/oj_windows/buf.h +85 -0
  6. data/ext/oj_windows/cache.c +339 -0
  7. data/ext/oj_windows/cache.h +22 -0
  8. data/ext/oj_windows/cache8.c +105 -0
  9. data/ext/oj_windows/cache8.h +21 -0
  10. data/ext/oj_windows/circarray.c +64 -0
  11. data/ext/oj_windows/circarray.h +22 -0
  12. data/ext/oj_windows/code.c +214 -0
  13. data/ext/oj_windows/code.h +40 -0
  14. data/ext/oj_windows/compat.c +239 -0
  15. data/ext/oj_windows/custom.c +1074 -0
  16. data/ext/oj_windows/debug.c +126 -0
  17. data/ext/oj_windows/dump.c +1556 -0
  18. data/ext/oj_windows/dump.h +110 -0
  19. data/ext/oj_windows/dump_compat.c +901 -0
  20. data/ext/oj_windows/dump_leaf.c +162 -0
  21. data/ext/oj_windows/dump_object.c +710 -0
  22. data/ext/oj_windows/dump_strict.c +405 -0
  23. data/ext/oj_windows/encode.h +16 -0
  24. data/ext/oj_windows/err.c +57 -0
  25. data/ext/oj_windows/err.h +67 -0
  26. data/ext/oj_windows/extconf.rb +77 -0
  27. data/ext/oj_windows/fast.c +1710 -0
  28. data/ext/oj_windows/intern.c +325 -0
  29. data/ext/oj_windows/intern.h +22 -0
  30. data/ext/oj_windows/mem.c +320 -0
  31. data/ext/oj_windows/mem.h +53 -0
  32. data/ext/oj_windows/mimic_json.c +919 -0
  33. data/ext/oj_windows/object.c +726 -0
  34. data/ext/oj_windows/odd.c +245 -0
  35. data/ext/oj_windows/odd.h +43 -0
  36. data/ext/oj_windows/oj.c +2097 -0
  37. data/ext/oj_windows/oj.h +420 -0
  38. data/ext/oj_windows/parse.c +1317 -0
  39. data/ext/oj_windows/parse.h +113 -0
  40. data/ext/oj_windows/parser.c +1600 -0
  41. data/ext/oj_windows/parser.h +103 -0
  42. data/ext/oj_windows/rails.c +1484 -0
  43. data/ext/oj_windows/rails.h +18 -0
  44. data/ext/oj_windows/reader.c +222 -0
  45. data/ext/oj_windows/reader.h +137 -0
  46. data/ext/oj_windows/resolve.c +80 -0
  47. data/ext/oj_windows/resolve.h +12 -0
  48. data/ext/oj_windows/rxclass.c +144 -0
  49. data/ext/oj_windows/rxclass.h +26 -0
  50. data/ext/oj_windows/saj.c +675 -0
  51. data/ext/oj_windows/saj2.c +584 -0
  52. data/ext/oj_windows/saj2.h +23 -0
  53. data/ext/oj_windows/scp.c +187 -0
  54. data/ext/oj_windows/simd.h +47 -0
  55. data/ext/oj_windows/sparse.c +946 -0
  56. data/ext/oj_windows/stream_writer.c +329 -0
  57. data/ext/oj_windows/strict.c +189 -0
  58. data/ext/oj_windows/string_writer.c +517 -0
  59. data/ext/oj_windows/trace.c +72 -0
  60. data/ext/oj_windows/trace.h +55 -0
  61. data/ext/oj_windows/usual.c +1218 -0
  62. data/ext/oj_windows/usual.h +69 -0
  63. data/ext/oj_windows/util.c +136 -0
  64. data/ext/oj_windows/util.h +20 -0
  65. data/ext/oj_windows/val_stack.c +101 -0
  66. data/ext/oj_windows/val_stack.h +151 -0
  67. data/ext/oj_windows/validate.c +46 -0
  68. data/ext/oj_windows/wab.c +584 -0
  69. data/lib/oj/active_support_helper.rb +39 -0
  70. data/lib/oj/bag.rb +95 -0
  71. data/lib/oj/easy_hash.rb +52 -0
  72. data/lib/oj/error.rb +21 -0
  73. data/lib/oj/json.rb +188 -0
  74. data/lib/oj/mimic.rb +301 -0
  75. data/lib/oj/saj.rb +80 -0
  76. data/lib/oj/schandler.rb +143 -0
  77. data/lib/oj/state.rb +135 -0
  78. data/lib/oj/version.rb +4 -0
  79. data/lib/oj_windows/active_support_helper.rb +39 -0
  80. data/lib/oj_windows/bag.rb +95 -0
  81. data/lib/oj_windows/easy_hash.rb +52 -0
  82. data/lib/oj_windows/error.rb +21 -0
  83. data/lib/oj_windows/json.rb +188 -0
  84. data/lib/oj_windows/mimic.rb +301 -0
  85. data/lib/oj_windows/saj.rb +80 -0
  86. data/lib/oj_windows/schandler.rb +143 -0
  87. data/lib/oj_windows/state.rb +135 -0
  88. data/lib/oj_windows/version.rb +4 -0
  89. data/lib/oj_windows.rb +15 -0
  90. data/pages/Advanced.md +38 -0
  91. data/pages/Compatibility.md +49 -0
  92. data/pages/Custom.md +37 -0
  93. data/pages/Encoding.md +61 -0
  94. data/pages/InstallOptions.md +20 -0
  95. data/pages/JsonGem.md +60 -0
  96. data/pages/Modes.md +94 -0
  97. data/pages/Options.md +339 -0
  98. data/pages/Parser.md +134 -0
  99. data/pages/Rails.md +85 -0
  100. data/pages/Security.md +43 -0
  101. data/pages/WAB.md +12 -0
  102. metadata +242 -0
@@ -0,0 +1,18 @@
1
+ // Copyright (c) 2017 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
3
+
4
+ #ifndef OJ_RAILS_H
5
+ #define OJ_RAILS_H
6
+
7
+ #include "dump.h"
8
+
9
+ extern void oj_mimic_rails_init(void);
10
+ extern ROpt oj_rails_get_opt(ROptTable rot, VALUE clas);
11
+
12
+ extern bool oj_rails_hash_opt;
13
+ extern bool oj_rails_array_opt;
14
+ extern bool oj_rails_float_opt;
15
+
16
+ extern VALUE oj_optimize_rails(VALUE self);
17
+
18
+ #endif /* OJ_RAILS_H */
@@ -0,0 +1,222 @@
1
+ // Copyright (c) 2011 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
3
+
4
+ #include <errno.h>
5
+ #include <stdio.h>
6
+ #include <stdlib.h>
7
+ #include <string.h>
8
+ #include <sys/types.h>
9
+ #ifdef NEEDS_UIO
10
+ #if NEEDS_UIO
11
+ #include <sys/uio.h>
12
+ #endif
13
+ #endif
14
+ #include <time.h>
15
+ #if !IS_WINDOWS
16
+ #include <unistd.h>
17
+ #endif
18
+
19
+ #include "mem.h"
20
+ #include "oj.h"
21
+ #include "reader.h"
22
+ #include "ruby.h"
23
+
24
+ #define BUF_PAD 4
25
+
26
+ static VALUE rescue_cb(VALUE rdr, VALUE err);
27
+ static VALUE io_cb(VALUE rdr);
28
+ static VALUE partial_io_cb(VALUE rdr);
29
+ static int read_from_io(Reader reader);
30
+ static int read_from_fd(Reader reader);
31
+ static int read_from_io_partial(Reader reader);
32
+ // static int read_from_str(Reader reader);
33
+
34
+ void oj_reader_init(Reader reader, VALUE io, int fd, bool to_s) {
35
+ VALUE io_class = rb_obj_class(io);
36
+ VALUE stat;
37
+ VALUE ftype;
38
+
39
+ reader->head = reader->base;
40
+ *((char *)reader->head) = '\0';
41
+ reader->end = reader->head + sizeof(reader->base) - BUF_PAD;
42
+ reader->tail = reader->head;
43
+ reader->read_end = reader->head;
44
+ reader->pro = 0;
45
+ reader->str = 0;
46
+ reader->pos = 0;
47
+ reader->line = 1;
48
+ reader->col = 0;
49
+ reader->free_head = 0;
50
+
51
+ if (0 != fd) {
52
+ reader->read_func = read_from_fd;
53
+ reader->fd = fd;
54
+ } else if (rb_cString == io_class) {
55
+ reader->read_func = 0;
56
+ reader->in_str = StringValuePtr(io);
57
+ reader->head = (char *)reader->in_str;
58
+ reader->tail = reader->head;
59
+ reader->read_end = reader->head + RSTRING_LEN(io);
60
+ } else if (oj_stringio_class == io_class) {
61
+ VALUE s = rb_funcall2(io, oj_string_id, 0, 0);
62
+
63
+ reader->read_func = 0;
64
+ reader->in_str = StringValuePtr(s);
65
+ reader->head = (char *)reader->in_str;
66
+ reader->tail = reader->head;
67
+ reader->read_end = reader->head + RSTRING_LEN(s);
68
+ } else if (rb_cFile == io_class && Qnil != (stat = rb_funcall(io, oj_stat_id, 0)) &&
69
+ Qnil != (ftype = rb_funcall(stat, oj_ftype_id, 0)) && 0 == strcmp("file", StringValuePtr(ftype)) &&
70
+ 0 == FIX2INT(rb_funcall(io, oj_pos_id, 0))) {
71
+ reader->read_func = read_from_fd;
72
+ reader->fd = FIX2INT(rb_funcall(io, oj_fileno_id, 0));
73
+ } else if (rb_respond_to(io, oj_readpartial_id)) {
74
+ reader->read_func = read_from_io_partial;
75
+ reader->io = io;
76
+ } else if (rb_respond_to(io, oj_read_id)) {
77
+ reader->read_func = read_from_io;
78
+ reader->io = io;
79
+ } else if (to_s) {
80
+ volatile VALUE rstr = oj_safe_string_convert(io);
81
+
82
+ reader->read_func = 0;
83
+ reader->in_str = StringValuePtr(rstr);
84
+ reader->head = (char *)reader->in_str;
85
+ reader->tail = reader->head;
86
+ reader->read_end = reader->head + RSTRING_LEN(rstr);
87
+ } else {
88
+ rb_raise(rb_eArgError, "parser io argument must be a String or respond to readpartial() or read().\n");
89
+ }
90
+ }
91
+
92
+ int oj_reader_read(Reader reader) {
93
+ int err;
94
+ size_t shift = 0;
95
+
96
+ if (0 == reader->read_func) {
97
+ return -1;
98
+ }
99
+ // if there is not much room to read into, shift or realloc a larger buffer.
100
+ if (reader->head < reader->tail && 4096 > reader->end - reader->tail) {
101
+ if (0 == reader->pro) {
102
+ shift = reader->tail - reader->head;
103
+ } else {
104
+ shift = reader->pro - reader->head - 1; // leave one character so we can backup one
105
+ }
106
+ if (0 >= shift) { /* no space left so allocate more */
107
+ const char *old = reader->head;
108
+ size_t size = reader->end - reader->head + BUF_PAD;
109
+
110
+ if (reader->head == reader->base) {
111
+ reader->head = OJ_R_ALLOC_N(char, size * 2);
112
+ memcpy((char *)reader->head, old, size);
113
+ } else {
114
+ OJ_R_REALLOC_N(reader->head, char, size * 2);
115
+ }
116
+ reader->free_head = 1;
117
+ reader->end = reader->head + size * 2 - BUF_PAD;
118
+ reader->tail = reader->head + (reader->tail - old);
119
+ reader->read_end = reader->head + (reader->read_end - old);
120
+ if (0 != reader->pro) {
121
+ reader->pro = reader->head + (reader->pro - old);
122
+ }
123
+ if (0 != reader->str) {
124
+ reader->str = reader->head + (reader->str - old);
125
+ }
126
+ } else {
127
+ memmove((char *)reader->head, reader->head + shift, reader->read_end - (reader->head + shift));
128
+ reader->tail -= shift;
129
+ reader->read_end -= shift;
130
+ if (0 != reader->pro) {
131
+ reader->pro -= shift;
132
+ }
133
+ if (0 != reader->str) {
134
+ reader->str -= shift;
135
+ }
136
+ }
137
+ }
138
+ err = reader->read_func(reader);
139
+ *(char *)reader->read_end = '\0';
140
+
141
+ return err;
142
+ }
143
+
144
+ static VALUE rescue_cb(VALUE rbuf, VALUE err) {
145
+ VALUE clas = rb_obj_class(err);
146
+
147
+ if (rb_eTypeError != clas && rb_eEOFError != clas) {
148
+ Reader reader = (Reader)rbuf;
149
+
150
+ rb_raise(clas, "at line %d, column %d\n", reader->line, reader->col);
151
+ }
152
+ return Qfalse;
153
+ }
154
+
155
+ static VALUE partial_io_cb(VALUE rbuf) {
156
+ Reader reader = (Reader)rbuf;
157
+ VALUE args[1];
158
+ VALUE rstr;
159
+ char *str;
160
+ size_t cnt;
161
+
162
+ args[0] = ULONG2NUM(reader->end - reader->tail);
163
+ rstr = rb_funcall2(reader->io, oj_readpartial_id, 1, args);
164
+ if (Qnil == rstr) {
165
+ return Qfalse;
166
+ }
167
+ str = StringValuePtr(rstr);
168
+ cnt = RSTRING_LEN(rstr);
169
+ strcpy(reader->tail, str);
170
+ reader->read_end = reader->tail + cnt;
171
+
172
+ return Qtrue;
173
+ }
174
+
175
+ static VALUE io_cb(VALUE rbuf) {
176
+ Reader reader = (Reader)rbuf;
177
+ VALUE args[1];
178
+ VALUE rstr;
179
+ char *str;
180
+ size_t cnt;
181
+
182
+ args[0] = ULONG2NUM(reader->end - reader->tail);
183
+ rstr = rb_funcall2(reader->io, oj_read_id, 1, args);
184
+ if (Qnil == rstr) {
185
+ return Qfalse;
186
+ }
187
+ str = StringValuePtr(rstr);
188
+ cnt = RSTRING_LEN(rstr);
189
+ strcpy(reader->tail, str);
190
+ reader->read_end = reader->tail + cnt;
191
+
192
+ return Qtrue;
193
+ }
194
+
195
+ static int read_from_io_partial(Reader reader) {
196
+ return (Qfalse == rb_rescue(partial_io_cb, (VALUE)reader, rescue_cb, (VALUE)reader));
197
+ }
198
+
199
+ static int read_from_io(Reader reader) {
200
+ return (Qfalse == rb_rescue(io_cb, (VALUE)reader, rescue_cb, (VALUE)reader));
201
+ }
202
+
203
+ static int read_from_fd(Reader reader) {
204
+ ssize_t cnt;
205
+ size_t max = reader->end - reader->tail;
206
+
207
+ cnt = read(reader->fd, reader->tail, max);
208
+ if (cnt <= 0) {
209
+ return -1;
210
+ } else if (0 != cnt) {
211
+ reader->read_end = reader->tail + cnt;
212
+ }
213
+ return 0;
214
+ }
215
+
216
+ // This is only called when the end of the string is reached so just return -1.
217
+ /*
218
+ static int
219
+ read_from_str(Reader reader) {
220
+ return -1;
221
+ }
222
+ */
@@ -0,0 +1,137 @@
1
+ // Copyright (c) 2011 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
3
+
4
+ #ifndef OJ_READER_H
5
+ #define OJ_READER_H
6
+
7
+ #include "mem.h"
8
+
9
+ typedef struct _reader {
10
+ char base[0x00001000];
11
+ char *head;
12
+ char *end;
13
+ char *tail;
14
+ char *read_end; /* one past last character read */
15
+ char *pro; /* protection start, buffer can not slide past this point */
16
+ char *str; /* start of current string being read */
17
+ long pos;
18
+ int line;
19
+ int col;
20
+ int free_head;
21
+ int (*read_func)(struct _reader *reader);
22
+ union {
23
+ int fd;
24
+ VALUE io;
25
+ const char *in_str;
26
+ };
27
+ } *Reader;
28
+
29
+ extern void oj_reader_init(Reader reader, VALUE io, int fd, bool to_s);
30
+ extern int oj_reader_read(Reader reader);
31
+
32
+ static inline char reader_get(Reader reader) {
33
+ // printf("*** drive get from '%s' from start: %ld buf: %p from read_end: %ld\n",
34
+ // reader->tail, reader->tail - reader->head, reader->head, reader->read_end - reader->tail);
35
+ if (reader->read_end <= reader->tail) {
36
+ if (0 != oj_reader_read(reader)) {
37
+ return '\0';
38
+ }
39
+ }
40
+ if ('\n' == *reader->tail) {
41
+ reader->line++;
42
+ reader->col = 0;
43
+ }
44
+ reader->col++;
45
+ reader->pos++;
46
+
47
+ return *reader->tail++;
48
+ }
49
+
50
+ static inline void reader_backup(Reader reader) {
51
+ reader->tail--;
52
+ reader->col--;
53
+ reader->pos--;
54
+ if (0 >= reader->col) {
55
+ reader->line--;
56
+ // allow col to be negative since we never backup twice in a row
57
+ }
58
+ }
59
+
60
+ static inline void reader_protect(Reader reader) {
61
+ reader->pro = reader->tail;
62
+ reader->str = reader->tail; // can't have str before pro
63
+ }
64
+
65
+ static inline void reader_release(Reader reader) {
66
+ reader->pro = 0;
67
+ }
68
+
69
+ /* Starts by reading a character so it is safe to use with an empty or
70
+ * compacted buffer.
71
+ */
72
+ static inline char reader_next_non_white(Reader reader) {
73
+ char c;
74
+
75
+ while ('\0' != (c = reader_get(reader))) {
76
+ switch (c) {
77
+ case ' ':
78
+ case '\t':
79
+ case '\f':
80
+ case '\n':
81
+ case '\r': break;
82
+ default: return c;
83
+ }
84
+ }
85
+ return '\0';
86
+ }
87
+
88
+ /* Starts by reading a character so it is safe to use with an empty or
89
+ * compacted buffer.
90
+ */
91
+ static inline char reader_next_white(Reader reader) {
92
+ char c;
93
+
94
+ while ('\0' != (c = reader_get(reader))) {
95
+ switch (c) {
96
+ case ' ':
97
+ case '\t':
98
+ case '\f':
99
+ case '\n':
100
+ case '\r':
101
+ case '\0': return c;
102
+ default: break;
103
+ }
104
+ }
105
+ return '\0';
106
+ }
107
+
108
+ static inline int reader_expect(Reader reader, const char *s) {
109
+ for (; '\0' != *s; s++) {
110
+ if (reader_get(reader) != *s) {
111
+ return -1;
112
+ }
113
+ }
114
+ return 0;
115
+ }
116
+
117
+ static inline void reader_cleanup(Reader reader) {
118
+ if (reader->free_head && 0 != reader->head) {
119
+ OJ_R_FREE((char *)reader->head);
120
+ reader->head = 0;
121
+ reader->free_head = 0;
122
+ }
123
+ }
124
+
125
+ static inline int is_white(char c) {
126
+ switch (c) {
127
+ case ' ':
128
+ case '\t':
129
+ case '\f':
130
+ case '\n':
131
+ case '\r': return 1;
132
+ default: break;
133
+ }
134
+ return 0;
135
+ }
136
+
137
+ #endif /* OJ_READER_H */
@@ -0,0 +1,80 @@
1
+ // Copyright (c) 2012 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
3
+
4
+ #include <stdio.h>
5
+ #include <stdlib.h>
6
+ #include <string.h>
7
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
8
+ #include <pthread.h>
9
+ #endif
10
+
11
+ #include "err.h"
12
+ #include "intern.h"
13
+ #include "oj.h"
14
+ #include "parse.h"
15
+
16
+ inline static VALUE resolve_classname(VALUE mod, const char *classname, int auto_define) {
17
+ VALUE clas;
18
+ ID ci = rb_intern(classname);
19
+
20
+ if (rb_const_defined_at(mod, ci)) {
21
+ clas = rb_const_get_at(mod, ci);
22
+ } else if (auto_define) {
23
+ clas = rb_define_class_under(mod, classname, oj_bag_class);
24
+ } else {
25
+ clas = Qundef;
26
+ }
27
+ return clas;
28
+ }
29
+
30
+ static VALUE resolve_classpath(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class) {
31
+ char class_name[1024];
32
+ VALUE clas;
33
+ char *end = class_name + sizeof(class_name) - 1;
34
+ char *s;
35
+ const char *n = name;
36
+
37
+ clas = rb_cObject;
38
+ for (s = class_name; 0 < len; n++, len--) {
39
+ if (':' == *n) {
40
+ *s = '\0';
41
+ n++;
42
+ len--;
43
+ if (':' != *n) {
44
+ return Qundef;
45
+ }
46
+ if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
47
+ return Qundef;
48
+ }
49
+ s = class_name;
50
+ } else if (end <= s) {
51
+ return Qundef;
52
+ } else {
53
+ *s++ = *n;
54
+ }
55
+ }
56
+ *s = '\0';
57
+ if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
58
+ oj_set_error_at(pi, error_class, __FILE__, __LINE__, "class %s is not defined", name);
59
+ if (Qnil != error_class) {
60
+ pi->err_class = error_class;
61
+ }
62
+ }
63
+ return clas;
64
+ }
65
+
66
+ VALUE
67
+ oj_name2class(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class) {
68
+ if (No == pi->options.class_cache) {
69
+ return resolve_classpath(pi, name, len, auto_define, error_class);
70
+ }
71
+ return oj_class_intern(name, len, true, pi, auto_define, error_class);
72
+ }
73
+
74
+ VALUE
75
+ oj_name2struct(ParseInfo pi, VALUE nameVal, VALUE error_class) {
76
+ size_t len = RSTRING_LEN(nameVal);
77
+ const char *str = StringValuePtr(nameVal);
78
+
79
+ return resolve_classpath(pi, str, len, 0, error_class);
80
+ }
@@ -0,0 +1,12 @@
1
+ // Copyright (c) 2011 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
3
+
4
+ #ifndef OJ_RESOLVE_H
5
+ #define OJ_RESOLVE_H
6
+
7
+ #include "ruby.h"
8
+
9
+ extern VALUE oj_name2class(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class);
10
+ extern VALUE oj_name2struct(ParseInfo pi, VALUE nameVal, VALUE error_class);
11
+
12
+ #endif /* OJ_RESOLVE_H */
@@ -0,0 +1,144 @@
1
+ // Copyright (c) 2017 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
3
+
4
+ #include <errno.h>
5
+ #include <stdio.h>
6
+ #include <stdlib.h>
7
+ #include <string.h>
8
+ #include <sys/types.h>
9
+ #if !IS_WINDOWS
10
+ #include <regex.h>
11
+ #endif
12
+
13
+ #include "mem.h"
14
+ #include "rxclass.h"
15
+
16
+ typedef struct _rxC {
17
+ struct _rxC *next;
18
+ VALUE rrx;
19
+ #if !IS_WINDOWS
20
+ regex_t rx;
21
+ #endif
22
+ VALUE clas;
23
+ char src[256];
24
+ } *RxC;
25
+
26
+ void oj_rxclass_init(RxClass rc) {
27
+ *rc->err = '\0';
28
+ rc->head = NULL;
29
+ rc->tail = NULL;
30
+ }
31
+
32
+ void oj_rxclass_cleanup(RxClass rc) {
33
+ RxC rxc;
34
+
35
+ while (NULL != (rxc = rc->head)) {
36
+ rc->head = rc->head->next;
37
+ #if !IS_WINDOWS
38
+ if (Qnil == rxc->rrx) {
39
+ regfree(&rxc->rx);
40
+ }
41
+ OJ_R_FREE(rxc);
42
+ #endif
43
+ }
44
+ }
45
+
46
+ void oj_rxclass_rappend(RxClass rc, VALUE rx, VALUE clas) {
47
+ RxC rxc = OJ_R_ALLOC_N(struct _rxC, 1);
48
+
49
+ memset(rxc, 0, sizeof(struct _rxC));
50
+ rxc->rrx = rx;
51
+ rxc->clas = clas;
52
+ if (NULL == rc->tail) {
53
+ rc->head = rxc;
54
+ } else {
55
+ rc->tail->next = rxc;
56
+ }
57
+ rc->tail = rxc;
58
+ }
59
+
60
+ // Attempt to compile the expression. If it fails populate the error code..
61
+ int oj_rxclass_append(RxClass rc, const char *expr, VALUE clas) {
62
+ RxC rxc;
63
+ #if !IS_WINDOWS
64
+ int err;
65
+ int flags = 0;
66
+ #endif
67
+ if (sizeof(rxc->src) <= strlen(expr)) {
68
+ snprintf(rc->err,
69
+ sizeof(rc->err),
70
+ "expressions must be less than %lu characters",
71
+ (unsigned long)sizeof(rxc->src));
72
+ return EINVAL;
73
+ }
74
+ rxc = OJ_R_ALLOC_N(struct _rxC, 1);
75
+ rxc->next = 0;
76
+ rxc->clas = clas;
77
+
78
+ #if IS_WINDOWS
79
+ rxc->rrx = rb_funcall(rb_cRegexp, rb_intern("new"), 1, rb_str_new2(expr));
80
+ #else
81
+ rxc->rrx = Qnil;
82
+ if (0 != (err = regcomp(&rxc->rx, expr, flags))) {
83
+ regerror(err, &rxc->rx, rc->err, sizeof(rc->err));
84
+ OJ_FREE(rxc);
85
+ return err;
86
+ }
87
+ #endif
88
+ if (NULL == rc->tail) {
89
+ rc->head = rxc;
90
+ } else {
91
+ rc->tail->next = rxc;
92
+ }
93
+ rc->tail = rxc;
94
+
95
+ return 0;
96
+ }
97
+
98
+ VALUE
99
+ oj_rxclass_match(RxClass rc, const char *str, int len) {
100
+ RxC rxc;
101
+ char buf[4096];
102
+
103
+ for (rxc = rc->head; NULL != rxc; rxc = rxc->next) {
104
+ if (Qnil != rxc->rrx) {
105
+ // Must use a valiabel for this to work.
106
+ volatile VALUE rstr = rb_str_new(str, len);
107
+
108
+ // if (Qtrue == rb_funcall(rxc->rrx, rb_intern("match?"), 1, rstr)) {
109
+ if (Qnil != rb_funcall(rxc->rrx, rb_intern("match"), 1, rstr)) {
110
+ return rxc->clas;
111
+ }
112
+ } else if (len < (int)sizeof(buf)) {
113
+ #if !IS_WINDOWS
114
+ // string is not \0 terminated so copy and attempt a match
115
+ memcpy(buf, str, len);
116
+ buf[len] = '\0';
117
+ if (0 == regexec(&rxc->rx, buf, 0, NULL, 0)) { // match
118
+ return rxc->clas;
119
+ }
120
+ #endif
121
+ } else {
122
+ // TBD allocate a larger buffer and attempt
123
+ }
124
+ }
125
+ return Qnil;
126
+ }
127
+
128
+ void oj_rxclass_copy(RxClass src, RxClass dest) {
129
+ dest->head = NULL;
130
+ dest->tail = NULL;
131
+ if (NULL != src->head) {
132
+ RxC rxc;
133
+
134
+ for (rxc = src->head; NULL != rxc; rxc = rxc->next) {
135
+ if (Qnil != rxc->rrx) {
136
+ oj_rxclass_rappend(dest, rxc->rrx, rxc->clas);
137
+ } else {
138
+ #if !IS_WINDOWS
139
+ oj_rxclass_append(dest, rxc->src, rxc->clas);
140
+ #endif
141
+ }
142
+ }
143
+ }
144
+ }
@@ -0,0 +1,26 @@
1
+ // Copyright (c) 2017 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
3
+
4
+ #ifndef OJ_RXCLASS_H
5
+ #define OJ_RXCLASS_H
6
+
7
+ #include <stdbool.h>
8
+
9
+ #include "ruby.h"
10
+
11
+ struct _rxC;
12
+
13
+ typedef struct _rxClass {
14
+ struct _rxC *head;
15
+ struct _rxC *tail;
16
+ char err[128];
17
+ } *RxClass;
18
+
19
+ extern void oj_rxclass_init(RxClass rc);
20
+ extern void oj_rxclass_cleanup(RxClass rc);
21
+ extern int oj_rxclass_append(RxClass rc, const char *expr, VALUE clas);
22
+ extern VALUE oj_rxclass_match(RxClass rc, const char *str, int len);
23
+ extern void oj_rxclass_copy(RxClass src, RxClass dest);
24
+ extern void oj_rxclass_rappend(RxClass rc, VALUE rx, VALUE clas);
25
+
26
+ #endif /* OJ_RXCLASS_H */