berns 4.1.2 → 4.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/ext/berns/berns.c CHANGED
@@ -1,5 +1,13 @@
1
- #include "ruby.h"
1
+ #include <stdbool.h>
2
+
2
3
  #include "hescape.h"
4
+ #include "ruby.h"
5
+ #include "strxcat.h"
6
+ #include "strxcpy.h"
7
+ #include "strxempty.h"
8
+ #include "strxfree.h"
9
+ #include "strxnew.h"
10
+ #include "strxresize.h"
3
11
 
4
12
  static const char *attr_close = "\"";
5
13
  static const size_t attr_clen = 1;
@@ -28,576 +36,574 @@ static const size_t sllen = 1;
28
36
  * content.
29
37
  */
30
38
  #define CONTENT_FROM_BLOCK \
31
- VALUE content; \
32
- \
33
- if (rb_block_given_p()) { \
34
- content = rb_yield(Qnil); \
35
- \
36
- if (TYPE(content) == T_NIL || TYPE(content) == T_FALSE) { \
37
- content = rb_utf8_str_new_cstr(""); \
38
- } else if (TYPE(content) != T_STRING) { \
39
- content = rb_funcall(content, rb_intern("to_s"), 0); \
40
- } \
41
- } else { \
42
- content = rb_utf8_str_new_cstr(""); \
43
- }
39
+ VALUE content; \
40
+ \
41
+ if (rb_block_given_p()) { \
42
+ content = rb_yield(Qnil); \
43
+ \
44
+ if (TYPE(content) == T_NIL || TYPE(content) == T_FALSE) { \
45
+ content = rb_utf8_str_new_cstr(""); \
46
+ } else if (TYPE(content) != T_STRING) { \
47
+ content = rb_funcall(content, rb_intern("to_s"), 0); \
48
+ } \
49
+ } else { \
50
+ content = rb_utf8_str_new_cstr(""); \
51
+ }
44
52
 
45
53
  /*
46
54
  * Macro to define a "dynamic" function that generates a void element.
47
55
  */
48
56
  #define VOID_ELEMENT(element_name) \
49
- static VALUE external_##element_name##_element(int argc, VALUE *argv, RB_UNUSED_VAR(VALUE self)) { \
50
- rb_check_arity(argc, 0, 1); \
51
- \
52
- const char *tag = #element_name; \
53
- char *string = void_element(tag, strlen(tag), argv[0]); \
54
- VALUE rstring = rb_utf8_str_new_cstr(string); \
55
- free(string); \
56
- \
57
- return rstring; \
58
- }
57
+ static VALUE external_##element_name##_element(int argc, VALUE *argv, RB_UNUSED_VAR(VALUE self)) { \
58
+ rb_check_arity(argc, 0, 1); \
59
+ \
60
+ const char *tag = #element_name; \
61
+ char *string; \
62
+ \
63
+ if (argc == 1) { \
64
+ string = void_element_with_attributes(tag, strlen(tag), argv[0]); \
65
+ } else { \
66
+ string = void_element_without_attributes(tag, strlen(tag)); \
67
+ } \
68
+ VALUE rstring = rb_utf8_str_new_cstr(string); \
69
+ strxfree(string); \
70
+ \
71
+ return rstring; \
72
+ }
59
73
 
60
74
  /*
61
75
  * Macro to define a "dynamic" function that generates a standard element.
62
76
  */
63
77
  #define STANDARD_ELEMENT(element_name) \
64
- static VALUE external_##element_name##_element(int argc, VALUE *argv, RB_UNUSED_VAR(VALUE self)) { \
65
- rb_check_arity(argc, 0, 1); \
66
- \
67
- CONTENT_FROM_BLOCK \
68
- const char *tag = #element_name; \
69
- char *string = element(tag, strlen(tag), RSTRING_PTR(content), RSTRING_LEN(content), argv[0]); \
70
- VALUE rstring = rb_utf8_str_new_cstr(string); \
71
- free(string); \
72
- \
73
- return rstring; \
74
- }
75
-
76
-
77
- /*
78
- * "Safe strcpy" - https://twitter.com/hyc_symas/status/1102573036534972416?s=12
79
- */
80
- static char * stecpy(char *destination, const char *source, const char *end) {
81
- if (end) {
82
- end--;
83
- }
84
-
85
- while (*source && destination < end) {
86
- *destination++ = *source++;
87
- }
88
-
89
- if (destination) {
90
- *destination = '\0';
91
- }
92
-
93
- return destination;
94
- }
78
+ static VALUE external_##element_name##_element(int argc, VALUE *argv, RB_UNUSED_VAR(VALUE self)) { \
79
+ rb_check_arity(argc, 0, 1); \
80
+ \
81
+ CONTENT_FROM_BLOCK \
82
+ const char *tag = #element_name; \
83
+ char *string; \
84
+ \
85
+ if (argc == 1) { \
86
+ string = element_with_attributes(tag, strlen(tag), RSTRING_PTR(content), RSTRING_LEN(content), argv[0]); \
87
+ } else { \
88
+ string = element_without_attributes(tag, strlen(tag), RSTRING_PTR(content), RSTRING_LEN(content)); \
89
+ } \
90
+ VALUE rstring = rb_utf8_str_new_cstr(string); \
91
+ strxfree(string); \
92
+ \
93
+ return rstring; \
94
+ }
95
95
 
96
96
  /*
97
97
  * The external API for Berns.sanitize
98
98
  *
99
- * string should be a string or nil, anything else will raise an error.
99
+ * string should be a string or nil, anything else will raise an error.
100
100
  *
101
101
  */
102
102
  static VALUE external_sanitize(RB_UNUSED_VAR(VALUE self), VALUE string) {
103
- if (TYPE(string) == T_NIL) {
104
- return Qnil;
105
- }
106
-
107
- StringValue(string);
108
-
109
- size_t slen = RSTRING_LEN(string);
110
- char *str = RSTRING_PTR(string);
111
-
112
- char dest[slen + 1];
113
-
114
- unsigned int index = 0;
115
- unsigned int open = 0;
116
- unsigned int modified = 0;
117
- unsigned int entity = 0;
118
-
119
- for (unsigned int i = 0; i < slen; i++) {
120
- if (str[i] == '<') {
121
- open = 1;
122
- modified = 1;
123
- } else if (str[i] == '>') {
124
- open = 0;
125
- } else if (str[i] == '&') {
126
- entity = 1;
127
- modified = 1;
128
- } else if (str[i] == ';') {
129
- entity = 0;
130
- } else if (!open && !entity) {
131
- dest[index++] = str[i];
132
- }
133
- }
134
-
135
- dest[index] = '\0';
136
-
137
- /*
138
- * If the string was never modified, return the original string, otherwise
139
- * create a new string from our destination buffer.
140
- */
141
- if (modified) {
142
- return rb_utf8_str_new_cstr(dest);
143
- } else {
144
- return string;
145
- }
103
+ if (TYPE(string) == T_NIL) {
104
+ return Qnil;
105
+ }
106
+
107
+ StringValue(string);
108
+
109
+ size_t slen = RSTRING_LEN(string);
110
+ char *str = RSTRING_PTR(string);
111
+
112
+ char dest[slen + 1];
113
+
114
+ bool entity = false;
115
+ bool modified = false;
116
+ bool open = false;
117
+ unsigned int index = 0;
118
+
119
+ for (unsigned int i = 0; i < slen; i++) {
120
+ switch(str[i]) {
121
+ case '<':
122
+ open = true;
123
+ modified = true;
124
+ break;
125
+ case '>':
126
+ open = false;
127
+ break;
128
+ case '&':
129
+ entity = true;
130
+ modified = true;
131
+ break;
132
+ case ';':
133
+ entity = false;
134
+ break;
135
+ default:
136
+ if (!open && !entity) {
137
+ dest[index++] = str[i];
138
+ }
139
+
140
+ break;
141
+ }
142
+ }
143
+
144
+ dest[index] = '\0';
145
+
146
+ /*
147
+ * If the string was never modified, return the original string, otherwise
148
+ * create a new string from our destination buffer.
149
+ */
150
+ if (modified) {
151
+ return rb_utf8_str_new_cstr(dest);
152
+ } else {
153
+ return string;
154
+ }
146
155
  }
147
156
 
148
157
  /*
149
158
  * The external API for Berns.escape_html.
150
159
  *
151
- * string should be a string, anything else will raise an error.
160
+ * Anything other than a string will raise an error.
152
161
  *
153
162
  */
154
163
  static VALUE external_escape_html(RB_UNUSED_VAR(VALUE self), VALUE string) {
155
- StringValue(string);
164
+ StringValue(string);
156
165
 
157
- uint8_t *dest = NULL;
158
- size_t slen = RSTRING_LEN(string);
159
- size_t esclen = hesc_escape_html(&dest, RSTRING_PTR(string), slen);
166
+ uint8_t *dest = NULL;
167
+ size_t slen = RSTRING_LEN(string);
168
+ size_t esclen = hesc_escape_html(&dest, RSTRING_PTR(string), slen);
160
169
 
161
- VALUE rstring;
170
+ VALUE rstring;
162
171
 
163
- if (esclen > slen) {
164
- rstring = rb_utf8_str_new_cstr(dest);
165
- free(dest);
166
- } else {
167
- rstring = string;
168
- }
172
+ if (esclen > slen) {
173
+ rstring = rb_utf8_str_new_cstr(dest);
174
+ free(dest);
175
+ } else {
176
+ rstring = string;
177
+ }
169
178
 
170
- return rstring;
179
+ return rstring;
171
180
  }
172
181
 
173
182
  /*
174
183
  * Return a freeable piece of memory with a copy of the attribute passed in it.
175
184
  * Why does this exist? So we can free the memory created by this without having
176
- * branch further in other places.
185
+ * to branch further in other places.
177
186
  */
178
- static char * empty_value_to_attribute(const char *attr, const size_t attrlen) {
179
- size_t total_size = attrlen + 1;
180
- char *dest = malloc(total_size);
181
- char *end = dest + total_size;
187
+ static inline char * empty_value_to_attribute(const char *attr, const size_t attrlen) {
188
+ size_t total_size = attrlen + 1;
189
+ char *dest = strxnew(total_size);
182
190
 
183
- stecpy(dest, attr, end);
191
+ strxcat(dest, total_size, attr);
184
192
 
185
- return dest;
193
+ return dest;
186
194
  }
187
195
 
188
196
  /*
189
- * Takes a string attribute name and value pair and converts them into a string ready to use in HTML
190
- *
191
- * "class" + "bg-primary" => 'class="bg-primary"'
192
- */
197
+ * Takes a string attribute name and value pair and converts them into a string
198
+ * ready to use in HTML
199
+ */
193
200
  static char * string_value_to_attribute(const char *attr, const size_t attrlen, const char *value, const size_t vallen) {
194
- if (vallen == 0) {
195
- size_t total_size = attrlen + 1;
196
- char *dest = malloc(total_size);
197
- char *end = dest + total_size;
198
-
199
- stecpy(dest, attr, end);
200
-
201
- return dest;
202
- } else {
203
- uint8_t *edest = NULL;
204
- size_t esclen = hesc_escape_html(&edest, value, vallen);
205
-
206
- size_t total_size = attrlen + attr_eqlen + esclen + attr_clen + 1;
207
- char *dest = malloc(total_size);
208
- char *ptr = NULL;
209
- char *end = dest + total_size;
210
-
211
- ptr = stecpy(dest, attr, end);
212
- ptr = stecpy(ptr, attr_equals, end);
213
- ptr = stecpy(ptr, edest, end);
214
- ptr = stecpy(ptr, attr_close, end);
215
-
216
- if (esclen > vallen) {
217
- free(edest);
218
- }
219
-
220
- return dest;
221
- }
201
+ if (vallen == 0) {
202
+ size_t total_size = attrlen + 1;
203
+ char *dest = strxnew(total_size);
204
+
205
+ strxcat(dest, total_size, attr);
206
+
207
+ return dest;
208
+ } else {
209
+ uint8_t *edest = NULL;
210
+ size_t esclen = hesc_escape_html(&edest, value, vallen);
211
+
212
+ size_t total_size = attrlen + attr_eqlen + esclen + attr_clen + 1;
213
+ char *dest = strxnew(total_size);
214
+
215
+ strxcat(dest, total_size, attr, attr_equals, edest, attr_close);
216
+
217
+ if (esclen > vallen) {
218
+ free(edest);
219
+ }
220
+
221
+ return dest;
222
+ }
222
223
  }
223
224
 
224
225
  static char * hash_value_to_attribute(const char *attr, const size_t attrlen, VALUE value) {
225
- if (TYPE(value) == T_IMEMO) {
226
- return strdup("");
227
- }
228
-
229
- Check_Type(value, T_HASH);
230
-
231
- if (RHASH_SIZE(value) == 0) {
232
- return strdup("");
233
- }
234
-
235
- VALUE subkey;
236
- VALUE subvalue;
237
-
238
- const VALUE keys = rb_funcall(value, rb_intern("keys"), 0);
239
- const VALUE length = RARRAY_LEN(keys);
240
-
241
- size_t allocated = 256;
242
- size_t occupied = 0;
243
-
244
- char *destination = malloc(allocated);
245
- char *position = destination;
246
- char *end = destination + allocated;
247
-
248
- for (unsigned int i = 0; i < length; i++) {
249
- subkey = rb_ary_entry(keys, i);
250
- subvalue = rb_hash_aref(value, subkey);
251
-
252
- switch(TYPE(subkey)) {
253
- case T_STRING:
254
- break;
255
- case T_NIL:
256
- subkey = rb_utf8_str_new_cstr("");
257
- break;
258
- case T_SYMBOL:
259
- subkey = rb_sym2str(subkey);
260
- break;
261
- default:
262
- free(destination);
263
- rb_raise(rb_eTypeError, "Berns.to_attribute value keys must be Strings, Symbols, or nil.");
264
- break;
265
- }
266
-
267
- size_t subattr_len = attrlen;
268
- size_t subkey_len = RSTRING_LEN(subkey);
269
-
270
- if (attrlen > 0 && subkey_len > 0) {
271
- subattr_len += dlen;
272
- }
273
-
274
- if (subkey_len > 0) {
275
- subattr_len += subkey_len;
276
- }
277
-
278
- char subattr[subattr_len + 1];
279
- char *ptr = subattr;
280
- char *subend = subattr + subattr_len + 1;
281
-
282
- if (attrlen > 0) {
283
- ptr = stecpy(ptr, attr, subend);
284
- }
285
-
286
- if (attrlen > 0 && subkey_len > 0) {
287
- ptr = stecpy(ptr, dash, subend);
288
- }
289
-
290
- stecpy(ptr, RSTRING_PTR(subkey), subend);
291
-
292
- char *combined;
293
-
294
- switch(TYPE(subvalue)) {
295
- case T_FALSE:
296
- combined = strdup("");
297
- break;
298
-
299
- case T_NIL:
300
- /* Fall through. */
301
- case T_TRUE:
302
- combined = empty_value_to_attribute(subattr, subattr_len);
303
- break;
304
-
305
- case T_STRING:
306
- combined = string_value_to_attribute(subattr, subattr_len, RSTRING_PTR(subvalue), RSTRING_LEN(subvalue));
307
- break;
308
-
309
- case T_SYMBOL:
310
- subvalue = rb_sym2str(subvalue);
311
- combined = string_value_to_attribute(subattr, subattr_len, RSTRING_PTR(subvalue), RSTRING_LEN(subvalue));
312
- break;
313
-
314
- case T_HASH:
315
- combined = hash_value_to_attribute(subattr, subattr_len, subvalue);
316
- break;
317
-
318
- default:
319
- subvalue = rb_funcall(subvalue, rb_intern("to_s"), 0);
320
- combined = string_value_to_attribute(subattr, subattr_len, RSTRING_PTR(subvalue), RSTRING_LEN(subvalue));
321
- break;
322
- }
323
-
324
- size_t combined_len = strlen(combined);
325
- size_t size_to_append = combined_len + 1;
326
-
327
- if (i > 0) {
328
- size_to_append += splen;
329
- }
330
-
331
- if ((size_to_append + occupied) > allocated) {
332
- /* To avoid an abundance of reallocations, this is a multiple of 256. */
333
- double multiple = (double) (size_to_append + occupied) / 256;
334
- size_t new_size_to_allocate = (unsigned int) ceil(multiple) * 256;
335
-
336
- char *tmp = realloc(destination, new_size_to_allocate);
337
-
338
- if (tmp == NULL) {
339
- free(destination);
340
- rb_raise(rb_eNoMemError, "Berns could not allocate sufficient memory.");
341
- }
342
-
343
- allocated = new_size_to_allocate;
344
- destination = tmp;
345
- position = destination + occupied;
346
- end = destination + allocated;
347
- }
348
-
349
- if (i > 0) {
350
- position = stecpy(position, space, end);
351
- occupied += splen;
352
- }
353
-
354
- position = stecpy(position, combined, end);
355
- occupied += combined_len;
356
-
357
- free(combined);
358
- }
359
-
360
- /*
361
- * Reallocate destination to final size. This is generally a reduction in the
362
- * allocated memory since we chunk allocations in 256 byte multiples.
363
- */
364
- char *rightsizeddest = realloc(destination, occupied + 1);
226
+ Check_Type(value, T_HASH);
227
+
228
+ if (RHASH_SIZE(value) == 0) {
229
+ return strxempty();
230
+ }
231
+
232
+ VALUE subkey;
233
+ VALUE subvalue;
234
+
235
+ const VALUE keys = rb_funcall(value, rb_intern("keys"), 0);
236
+ const VALUE length = RARRAY_LEN(keys);
237
+
238
+ size_t allocated = 256;
239
+ size_t occupied = 0;
240
+
241
+ char *destination = strxnew(allocated);
242
+ char *position = destination;
243
+
244
+ for (unsigned int i = 0; i < length; i++) {
245
+ subkey = rb_ary_entry(keys, i);
246
+ subvalue = rb_hash_aref(value, subkey);
247
+
248
+ switch(TYPE(subkey)) {
249
+ case T_STRING:
250
+ break;
251
+ case T_NIL:
252
+ subkey = rb_utf8_str_new_cstr("");
253
+ break;
254
+ case T_SYMBOL:
255
+ subkey = rb_sym2str(subkey);
256
+ break;
257
+ default:
258
+ strxfree(destination);
259
+ rb_raise(rb_eTypeError, "Berns.to_attribute value keys must be Strings, Symbols, or nil.");
260
+ break;
261
+ }
262
+
263
+ size_t subattr_len = attrlen;
264
+ size_t subkey_len = RSTRING_LEN(subkey);
265
+
266
+ if (attrlen > 0 && subkey_len > 0) {
267
+ subattr_len += dlen;
268
+ }
269
+
270
+ if (subkey_len > 0) {
271
+ subattr_len += subkey_len;
272
+ }
273
+
274
+ char subattr[subattr_len + 1];
275
+ char *ptr = subattr;
276
+ char *subend = subattr + subattr_len + 1;
277
+
278
+ if (attrlen > 0) {
279
+ ptr = strxcat(ptr, attrlen + 1, attr);
280
+ }
281
+
282
+ if (attrlen > 0 && subkey_len > 0) {
283
+ ptr = strxcat(ptr, dlen + 1, dash);
284
+ }
285
+
286
+ strxcat(ptr, subkey_len + 1, RSTRING_PTR(subkey));
287
+
288
+ char *combined;
289
+
290
+ switch(TYPE(subvalue)) {
291
+ case T_FALSE:
292
+ combined = strxempty();
293
+ break;
294
+
295
+ case T_NIL:
296
+ /* Fall through. */
297
+ case T_TRUE:
298
+ combined = empty_value_to_attribute(subattr, subattr_len);
299
+ break;
300
+
301
+ case T_STRING:
302
+ combined = string_value_to_attribute(subattr, subattr_len, RSTRING_PTR(subvalue), RSTRING_LEN(subvalue));
303
+ break;
304
+
305
+ case T_SYMBOL:
306
+ subvalue = rb_sym2str(subvalue);
307
+ combined = string_value_to_attribute(subattr, subattr_len, RSTRING_PTR(subvalue), RSTRING_LEN(subvalue));
308
+ break;
309
+
310
+ case T_HASH:
311
+ combined = hash_value_to_attribute(subattr, subattr_len, subvalue);
312
+ break;
313
+
314
+ default:
315
+ subvalue = rb_funcall(subvalue, rb_intern("to_s"), 0);
316
+ combined = string_value_to_attribute(subattr, subattr_len, RSTRING_PTR(subvalue), RSTRING_LEN(subvalue));
317
+ break;
318
+ }
319
+
320
+ size_t combined_len = strlen(combined);
321
+ size_t size_to_append = combined_len + 1;
322
+
323
+ if (i > 0) {
324
+ size_to_append += splen;
325
+ }
326
+
327
+ if ((size_to_append + occupied) > allocated) {
328
+ /* To avoid an abundance of reallocations, this is a multiple of 256. */
329
+ double multiple = (double) (size_to_append + occupied) / 256;
330
+ size_t new_size_to_allocate = (unsigned int) ceil(multiple) * 256;
331
+
332
+ char *tmp = strxresize(destination, new_size_to_allocate);
333
+
334
+ allocated = new_size_to_allocate;
335
+ destination = tmp;
336
+ position = destination + occupied;
337
+ }
338
+
339
+ if (i > 0) {
340
+ position = strxcat(position, splen + 1, space);
341
+ occupied += splen;
342
+ }
343
+
344
+ position = strxcat(position, combined_len + 1, combined);
345
+ occupied += combined_len;
346
+
347
+ strxfree(combined);
348
+ }
349
+
350
+ /*
351
+ * Reallocate destination to final size. This is generally a reduction in the
352
+ * allocated memory since we chunk allocations in 256 byte multiples.
353
+ */
354
+ char *rightsizeddest = strxresize(destination, occupied + 1);
355
+
356
+ rightsizeddest[occupied] = '\0';
365
357
 
366
- if (rightsizeddest == NULL) {
367
- free(destination);
368
- rb_raise(rb_eNoMemError, "Berns could not allocate sufficient memory.");
369
- }
370
-
371
- rightsizeddest[occupied] = '\0';
372
-
373
- return rightsizeddest;
358
+ return rightsizeddest;
374
359
  }
375
360
 
376
361
  /*
377
362
  * Convert an attribute name and value into a string.
378
363
  */
379
364
  static char * to_attribute(VALUE attr, VALUE value) {
380
- switch(TYPE(attr)) {
381
- case T_SYMBOL:
382
- attr = rb_sym2str(attr);
383
- break;
384
- default:
385
- break;
386
- }
387
-
388
- StringValue(attr);
389
-
390
- char *val = NULL;
391
- VALUE str;
392
-
393
- switch(TYPE(value)) {
394
- case T_NIL:
395
- /* Fall through. */
396
- case T_TRUE:
397
- val = empty_value_to_attribute(RSTRING_PTR(attr), RSTRING_LEN(attr));
398
- break;
399
- case T_FALSE:
400
- val = strdup("");
401
- break;
402
- case T_HASH:
403
- val = hash_value_to_attribute(RSTRING_PTR(attr), RSTRING_LEN(attr), value);
404
- break;
405
- case T_STRING:
406
- val = string_value_to_attribute(RSTRING_PTR(attr), RSTRING_LEN(attr), RSTRING_PTR(value), RSTRING_LEN(value));
407
- break;
408
- case T_SYMBOL:
409
- str = rb_sym2str(value);
410
- val = string_value_to_attribute(RSTRING_PTR(attr), RSTRING_LEN(attr), RSTRING_PTR(str), RSTRING_LEN(str));
411
- break;
412
- default:
413
- str = rb_funcall(value, rb_intern("to_s"), 0);
414
- val = string_value_to_attribute(RSTRING_PTR(attr), RSTRING_LEN(attr), RSTRING_PTR(str), RSTRING_LEN(str));
415
- break;
416
- }
417
-
418
- return val;
365
+ switch(TYPE(attr)) {
366
+ case T_SYMBOL:
367
+ attr = rb_sym2str(attr);
368
+ break;
369
+ default:
370
+ break;
371
+ }
372
+
373
+ StringValue(attr);
374
+
375
+ char *val = NULL;
376
+ VALUE str;
377
+
378
+ switch(TYPE(value)) {
379
+ case T_NIL:
380
+ /* Fall through. */
381
+ case T_TRUE:
382
+ val = empty_value_to_attribute(RSTRING_PTR(attr), RSTRING_LEN(attr));
383
+ break;
384
+ case T_FALSE:
385
+ val = strxempty();
386
+ break;
387
+ case T_HASH:
388
+ val = hash_value_to_attribute(RSTRING_PTR(attr), RSTRING_LEN(attr), value);
389
+ break;
390
+ case T_STRING:
391
+ val = string_value_to_attribute(RSTRING_PTR(attr), RSTRING_LEN(attr), RSTRING_PTR(value), RSTRING_LEN(value));
392
+ break;
393
+ case T_SYMBOL:
394
+ str = rb_sym2str(value);
395
+ val = string_value_to_attribute(RSTRING_PTR(attr), RSTRING_LEN(attr), RSTRING_PTR(str), RSTRING_LEN(str));
396
+ break;
397
+ default:
398
+ str = rb_funcall(value, rb_intern("to_s"), 0);
399
+ val = string_value_to_attribute(RSTRING_PTR(attr), RSTRING_LEN(attr), RSTRING_PTR(str), RSTRING_LEN(str));
400
+ break;
401
+ }
402
+
403
+ return val;
419
404
  }
420
405
 
421
406
  /*
422
407
  * The external API for Berns.to_attribute.
423
408
  *
424
- * attr should be either a symbol or string, otherwise an error is raised.
425
- * value can be anything to responds to #to_s
409
+ * attr should be either a symbol or string, otherwise an error is raised. value
410
+ * can be anything to responds to #to_s
426
411
  *
427
412
  */
428
413
  static VALUE external_to_attribute(RB_UNUSED_VAR(VALUE self), VALUE attr, VALUE value) {
429
- switch(TYPE(attr)) {
430
- case T_SYMBOL:
431
- attr = rb_sym2str(attr);
432
- break;
433
- default:
434
- break;
435
- }
414
+ if (TYPE(attr) == T_SYMBOL) {
415
+ attr = rb_sym2str(attr);
416
+ }
436
417
 
437
- StringValue(attr);
418
+ StringValue(attr);
438
419
 
439
- char *val = to_attribute(attr, value);
440
- VALUE rstring = rb_utf8_str_new_cstr(val);
441
- free(val);
420
+ char *val = to_attribute(attr, value);
421
+ VALUE rstring = rb_utf8_str_new_cstr(val);
422
+ strxfree(val);
442
423
 
443
- return rstring;
424
+ return rstring;
444
425
  }
445
426
 
446
427
  /*
447
428
  * The external API for Berns.to_attributes.
448
429
  *
449
- * attributes should be a hash, otherwise an error is raised.
430
+ * attributes should be a hash, otherwise an error is raised.
450
431
  *
451
432
  */
452
433
  static VALUE external_to_attributes(RB_UNUSED_VAR(VALUE self), VALUE attributes) {
453
- Check_Type(attributes, T_HASH);
454
-
455
- if (RHASH_SIZE(attributes) == 0) {
456
- return rb_utf8_str_new_cstr("");
457
- }
434
+ Check_Type(attributes, T_HASH);
458
435
 
459
- const char *empty = "";
460
- char *attrs = hash_value_to_attribute(empty, 0, attributes);
436
+ if (RHASH_SIZE(attributes) == 0) {
437
+ return rb_utf8_str_new_cstr("");
438
+ }
461
439
 
462
- VALUE rstring = rb_utf8_str_new_cstr(attrs);
463
- free(attrs);
440
+ char *attrs = hash_value_to_attribute("", 0, attributes);
441
+ VALUE rstring = rb_utf8_str_new_cstr(attrs);
442
+ strxfree(attrs);
464
443
 
465
- return rstring;
444
+ return rstring;
466
445
  }
467
446
 
468
447
  /*
469
- * Create a void element i.e. one without children/content.
448
+ * Create a void element i.e. one without children/content but with attributes.
470
449
  */
471
- static char * void_element(const char *tag, size_t tlen, VALUE attributes) {
472
- const char *empty = "";
473
- char *attrs = hash_value_to_attribute(empty, 0, attributes);
474
- size_t alen = strlen(attrs);
450
+ static char * void_element_with_attributes(const char *tag, size_t tlen, VALUE attributes) {
451
+ char *attrs = hash_value_to_attribute("", 0, attributes);
475
452
 
476
- size_t total = tag_olen + tlen + tag_clen + 1;
453
+ size_t alen = strlen(attrs);
454
+ size_t total = tag_olen + tlen + tag_clen + 1;
477
455
 
478
- /* If we have some attributes, add a space and the attributes' length. */
479
- if (alen > 0) {
480
- total += splen + alen;
481
- }
456
+ /* If we have some attributes, add a space and the attributes' length. */
457
+ if (alen > 0) {
458
+ total += splen + alen;
459
+ }
482
460
 
483
- char *dest = malloc(total);
484
- char *ptr = NULL;
485
- char *end = dest + total;
461
+ char *dest = strxnew(total);
462
+ char *ptr = strxcat(dest, tag_olen + tlen + 1, tag_open, tag);
486
463
 
487
- ptr = stecpy(dest, tag_open, end);
488
- ptr = stecpy(ptr, tag, end);
464
+ if (alen > 0) {
465
+ ptr = strxcat(ptr, splen + alen + 1, space, attrs);
466
+ }
489
467
 
490
- if (alen > 0) {
491
- ptr = stecpy(ptr, space, end);
492
- ptr = stecpy(ptr, attrs, end);
493
- }
468
+ strxcat(ptr, tag_clen + 1, tag_close);
469
+ strxfree(attrs);
494
470
 
495
- ptr = stecpy(ptr, tag_close, end);
471
+ return dest;
472
+ }
496
473
 
497
- free(attrs);
474
+ /*
475
+ * Create a void element i.e. one without children/content or attributes.
476
+ */
477
+ static char * void_element_without_attributes(const char *tag, size_t tlen) {
478
+ size_t total = tag_olen + tlen + tag_clen + 1;
479
+
480
+ char *dest = strxnew(total);
481
+ strxcat(dest, total, tag_open, tag, tag_close);
498
482
 
499
- return dest;
483
+ return dest;
500
484
  }
501
485
 
502
486
  /*
503
487
  * The external API for Berns.void.
504
488
  *
505
- * The first argument should be a string or symbol, otherwise an error is raised.
506
- * The second argument must be a hash if present.
489
+ * The first argument should be a string or symbol, otherwise an error is
490
+ * raised. The second argument must be a hash if present.
507
491
  *
508
492
  */
509
493
  static VALUE external_void_element(int argc, VALUE *arguments, RB_UNUSED_VAR(VALUE self)) {
510
- rb_check_arity(argc, 1, 2);
494
+ rb_check_arity(argc, 1, 2);
495
+
496
+ VALUE tag = arguments[0];
497
+ VALUE attributes = arguments[1];
511
498
 
512
- VALUE tag = arguments[0];
513
- VALUE attributes = arguments[1];
499
+ if (TYPE(tag) == T_SYMBOL) {
500
+ tag = rb_sym2str(tag);
501
+ }
514
502
 
515
- if (TYPE(tag) == T_SYMBOL) {
516
- tag = rb_sym2str(tag);
517
- }
503
+ StringValue(tag);
518
504
 
519
- StringValue(tag);
505
+ char *string;
520
506
 
521
- char *string = void_element(RSTRING_PTR(tag), RSTRING_LEN(tag), attributes);
522
- VALUE rstring = rb_utf8_str_new_cstr(string);
507
+ if (argc == 2) {
508
+ string = void_element_with_attributes(RSTRING_PTR(tag), RSTRING_LEN(tag), attributes);
509
+ } else {
510
+ string = void_element_without_attributes(RSTRING_PTR(tag), RSTRING_LEN(tag));
511
+ }
523
512
 
524
- free(string);
513
+ VALUE rstring = rb_utf8_str_new_cstr(string);
514
+ strxfree(string);
525
515
 
526
- return rstring;
516
+ return rstring;
527
517
  }
528
518
 
529
- static char * element(const char *tag, size_t tlen, char *content, size_t conlen, VALUE attributes) {
530
- const char *empty = "";
531
- char *attrs = hash_value_to_attribute(empty, 0, attributes);
532
- size_t alen = strlen(attrs);
519
+ static char * element_with_attributes(const char *tag, size_t tlen, char *content, size_t conlen, VALUE attributes) {
520
+ char *attrs = hash_value_to_attribute("", 0, attributes);
521
+ size_t alen = strlen(attrs);
533
522
 
534
- size_t total = tag_olen + tlen + tag_clen + tag_olen + sllen + tlen + tag_clen + 1;
523
+ size_t total = tag_olen + tlen + tag_clen + tag_olen + sllen + tlen + tag_clen + 1;
535
524
 
536
- /* If we have some attributes, add a space and the attributes' length. */
537
- if (alen > 0) {
538
- total += splen + alen;
539
- }
525
+ /* If we have some attributes, add a space and the attributes' length. */
526
+ if (alen > 0) {
527
+ total += splen + alen;
528
+ }
540
529
 
541
- /* If we have some content, add the content length to our total. */
542
- if (conlen > 0) {
543
- total += conlen;
544
- }
530
+ /* If we have some content, add the content length to our total. */
531
+ if (conlen > 0) {
532
+ total += conlen;
533
+ }
545
534
 
546
- char *dest = malloc(total);
547
- char *ptr = NULL;
548
- char *end = dest + total;
535
+ char *dest = strxnew(total);
536
+ char *ptr = strxcat(dest, tag_olen + tlen + 1, tag_open, tag);
549
537
 
550
- ptr = stecpy(dest, tag_open, end);
551
- ptr = stecpy(ptr, tag, end);
538
+ if (alen > 0) {
539
+ ptr = strxcat(ptr, splen + alen + 1, space, attrs);
540
+ }
552
541
 
553
- if (alen > 0) {
554
- ptr = stecpy(ptr, space, end);
555
- ptr = stecpy(ptr, attrs, end);
556
- }
542
+ ptr = strxcat(ptr, tag_clen + 1, tag_close);
557
543
 
558
- ptr = stecpy(ptr, tag_close, end);
544
+ if (conlen > 0) {
545
+ ptr = strxcat(ptr, conlen + 1, content);
546
+ }
559
547
 
560
- if (conlen > 0) {
561
- ptr = stecpy(ptr, content, end);
562
- }
548
+ ptr = strxcat(ptr, tag_olen + sllen + tlen + tag_clen + 1, tag_open, slash, tag, tag_close);
549
+ strxfree(attrs);
563
550
 
564
- ptr = stecpy(ptr, tag_open, end);
565
- ptr = stecpy(ptr, slash, end);
566
- ptr = stecpy(ptr, tag, end);
567
- ptr = stecpy(ptr, tag_close, end);
551
+ return dest;
552
+ }
553
+
554
+ static char * element_without_attributes(const char *tag, size_t tlen, char *content, size_t conlen) {
555
+ size_t total = tag_olen + tlen + tag_clen + tag_olen + sllen + tlen + tag_clen + 1;
556
+
557
+ /* If we have some content, add the content length to our total. */
558
+ if (conlen > 0) {
559
+ total += conlen;
560
+ }
561
+
562
+ char *dest = strxnew(total);
563
+ char *ptr = strxcat(dest, tag_olen + tlen + tag_clen + 1, tag_open, tag, tag_close);
568
564
 
569
- free(attrs);
565
+ if (conlen > 0) {
566
+ ptr = strxcat(ptr, conlen + 1, content);
567
+ }
570
568
 
571
- return dest;
569
+ strxcat(ptr, tag_olen + sllen + tlen + tag_clen + 1, tag_open, slash, tag, tag_close);
570
+
571
+ return dest;
572
572
  }
573
573
 
574
574
  /*
575
575
  * The external API for Berns.element.
576
576
  *
577
- * The first argument should be a string or symbol, otherwise an error is raised.
578
- * The second argument must be a hash if present.
579
- * An optional block can be given which will used as the contents of the element.
577
+ * The first argument should be a string or symbol, otherwise an error is
578
+ * raised. The second argument must be a hash if present. An optional block can
579
+ * be given which will used as the contents of the element.
580
580
  *
581
581
  */
582
582
  static VALUE external_element(int argc, VALUE *arguments, RB_UNUSED_VAR(VALUE self)) {
583
- rb_check_arity(argc, 1, 2);
583
+ rb_check_arity(argc, 1, 2);
584
+
585
+ VALUE tag = arguments[0];
586
+
587
+ if (TYPE(tag) == T_SYMBOL) {
588
+ tag = rb_sym2str(tag);
589
+ }
584
590
 
585
- VALUE tag = arguments[0];
586
- VALUE attributes = arguments[1];
591
+ StringValue(tag);
587
592
 
588
- if (TYPE(tag) == T_SYMBOL) {
589
- tag = rb_sym2str(tag);
590
- }
593
+ CONTENT_FROM_BLOCK
591
594
 
592
- StringValue(tag);
595
+ char *string;
593
596
 
594
- CONTENT_FROM_BLOCK
597
+ if (argc == 2) {
598
+ string = element_with_attributes(RSTRING_PTR(tag), RSTRING_LEN(tag), RSTRING_PTR(content), RSTRING_LEN(content), arguments[1]);
599
+ } else {
600
+ string = element_without_attributes(RSTRING_PTR(tag), RSTRING_LEN(tag), RSTRING_PTR(content), RSTRING_LEN(content));
601
+ }
595
602
 
596
- char *string = element(RSTRING_PTR(tag), RSTRING_LEN(tag), RSTRING_PTR(content), RSTRING_LEN(content), attributes);
597
- VALUE rstring = rb_utf8_str_new_cstr(string);
598
- free(string);
603
+ VALUE rstring = rb_utf8_str_new_cstr(string);
604
+ strxfree(string);
599
605
 
600
- return rstring;
606
+ return rstring;
601
607
  }
602
608
 
603
609
  VOID_ELEMENT(area)
@@ -712,142 +718,142 @@ STANDARD_ELEMENT(var)
712
718
  STANDARD_ELEMENT(video)
713
719
 
714
720
  void Init_berns() {
715
- VALUE Berns = rb_define_module("Berns");
716
-
717
- rb_define_singleton_method(Berns, "element", external_element, -1);
718
- rb_define_singleton_method(Berns, "escape_html", external_escape_html, 1);
719
- rb_define_singleton_method(Berns, "sanitize", external_sanitize, 1);
720
- rb_define_singleton_method(Berns, "to_attribute", external_to_attribute, 2);
721
- rb_define_singleton_method(Berns, "to_attributes", external_to_attributes, 1);
722
- rb_define_singleton_method(Berns, "void", external_void_element, -1);
723
-
724
- /*
725
- * List of void elements - http://xahlee.info/js/html5_non-closing_tag.html
726
- *
727
- * area base br col embed hr img input link menuitem meta param source track wbr
728
- *
729
- */
730
- rb_define_singleton_method(Berns, "area", external_area_element, -1);
731
- rb_define_singleton_method(Berns, "base", external_base_element, -1);
732
- rb_define_singleton_method(Berns, "br", external_br_element, -1);
733
- rb_define_singleton_method(Berns, "col", external_col_element, -1);
734
- rb_define_singleton_method(Berns, "embed", external_embed_element, -1);
735
- rb_define_singleton_method(Berns, "hr", external_hr_element, -1);
736
- rb_define_singleton_method(Berns, "img", external_img_element, -1);
737
- rb_define_singleton_method(Berns, "input", external_input_element, -1);
738
- rb_define_singleton_method(Berns, "link", external_link_element, -1);
739
- rb_define_singleton_method(Berns, "menuitem", external_menuitem_element, -1);
740
- rb_define_singleton_method(Berns, "meta", external_meta_element, -1);
741
- rb_define_singleton_method(Berns, "param", external_param_element, -1);
742
- rb_define_singleton_method(Berns, "source", external_source_element, -1);
743
- rb_define_singleton_method(Berns, "track", external_track_element, -1);
744
- rb_define_singleton_method(Berns, "wbr", external_wbr_element, -1);
745
-
746
- /*
747
- * List of standard HTML5 elements - https://www.w3schools.com/TAgs/default.asp
748
- *
749
- * a abbr address article aside audio b bdi bdo blockquote body button
750
- * canvas caption cite code colgroup datalist dd del details dfn dialog div
751
- * dl dt em fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 head
752
- * header html i iframe ins kbd label legend li main map mark menu meter nav
753
- * noscript object ol optgroup option output p picture pre progress q rp rt
754
- * ruby s samp script section select small span strong style sub summary
755
- * table tbody td template textarea tfoot th thead time title tr u ul var
756
- * video
757
- *
758
- */
759
- rb_define_singleton_method(Berns, "a", external_a_element, -1);
760
- rb_define_singleton_method(Berns, "abbr", external_abbr_element, -1);
761
- rb_define_singleton_method(Berns, "address", external_address_element, -1);
762
- rb_define_singleton_method(Berns, "article", external_article_element, -1);
763
- rb_define_singleton_method(Berns, "aside", external_aside_element, -1);
764
- rb_define_singleton_method(Berns, "audio", external_audio_element, -1);
765
- rb_define_singleton_method(Berns, "b", external_b_element, -1);
766
- rb_define_singleton_method(Berns, "bdi", external_bdi_element, -1);
767
- rb_define_singleton_method(Berns, "bdo", external_bdo_element, -1);
768
- rb_define_singleton_method(Berns, "blockquote", external_blockquote_element, -1);
769
- rb_define_singleton_method(Berns, "body", external_body_element, -1);
770
- rb_define_singleton_method(Berns, "button", external_button_element, -1);
771
- rb_define_singleton_method(Berns, "canvas", external_canvas_element, -1);
772
- rb_define_singleton_method(Berns, "caption", external_caption_element, -1);
773
- rb_define_singleton_method(Berns, "cite", external_cite_element, -1);
774
- rb_define_singleton_method(Berns, "code", external_code_element, -1);
775
- rb_define_singleton_method(Berns, "colgroup", external_colgroup_element, -1);
776
- rb_define_singleton_method(Berns, "datalist", external_datalist_element, -1);
777
- rb_define_singleton_method(Berns, "dd", external_dd_element, -1);
778
- rb_define_singleton_method(Berns, "del", external_del_element, -1);
779
- rb_define_singleton_method(Berns, "details", external_details_element, -1);
780
- rb_define_singleton_method(Berns, "dfn", external_dfn_element, -1);
781
- rb_define_singleton_method(Berns, "dialog", external_dialog_element, -1);
782
- rb_define_singleton_method(Berns, "div", external_div_element, -1);
783
- rb_define_singleton_method(Berns, "dl", external_dl_element, -1);
784
- rb_define_singleton_method(Berns, "dt", external_dt_element, -1);
785
- rb_define_singleton_method(Berns, "em", external_em_element, -1);
786
- rb_define_singleton_method(Berns, "fieldset", external_fieldset_element, -1);
787
- rb_define_singleton_method(Berns, "figcaption", external_figcaption_element, -1);
788
- rb_define_singleton_method(Berns, "figure", external_figure_element, -1);
789
- rb_define_singleton_method(Berns, "footer", external_footer_element, -1);
790
- rb_define_singleton_method(Berns, "form", external_form_element, -1);
791
- rb_define_singleton_method(Berns, "h1", external_h1_element, -1);
792
- rb_define_singleton_method(Berns, "h2", external_h2_element, -1);
793
- rb_define_singleton_method(Berns, "h3", external_h3_element, -1);
794
- rb_define_singleton_method(Berns, "h4", external_h4_element, -1);
795
- rb_define_singleton_method(Berns, "h5", external_h5_element, -1);
796
- rb_define_singleton_method(Berns, "h6", external_h6_element, -1);
797
- rb_define_singleton_method(Berns, "head", external_head_element, -1);
798
- rb_define_singleton_method(Berns, "header", external_header_element, -1);
799
- rb_define_singleton_method(Berns, "html", external_html_element, -1);
800
- rb_define_singleton_method(Berns, "i", external_i_element, -1);
801
- rb_define_singleton_method(Berns, "iframe", external_iframe_element, -1);
802
- rb_define_singleton_method(Berns, "ins", external_ins_element, -1);
803
- rb_define_singleton_method(Berns, "kbd", external_kbd_element, -1);
804
- rb_define_singleton_method(Berns, "label", external_label_element, -1);
805
- rb_define_singleton_method(Berns, "legend", external_legend_element, -1);
806
- rb_define_singleton_method(Berns, "li", external_li_element, -1);
807
- rb_define_singleton_method(Berns, "main", external_main_element, -1);
808
- rb_define_singleton_method(Berns, "map", external_map_element, -1);
809
- rb_define_singleton_method(Berns, "mark", external_mark_element, -1);
810
- rb_define_singleton_method(Berns, "menu", external_menu_element, -1);
811
- rb_define_singleton_method(Berns, "meter", external_meter_element, -1);
812
- rb_define_singleton_method(Berns, "nav", external_nav_element, -1);
813
- rb_define_singleton_method(Berns, "noscript", external_noscript_element, -1);
814
- rb_define_singleton_method(Berns, "object", external_object_element, -1);
815
- rb_define_singleton_method(Berns, "ol", external_ol_element, -1);
816
- rb_define_singleton_method(Berns, "optgroup", external_optgroup_element, -1);
817
- rb_define_singleton_method(Berns, "option", external_option_element, -1);
818
- rb_define_singleton_method(Berns, "output", external_output_element, -1);
819
- rb_define_singleton_method(Berns, "p", external_p_element, -1);
820
- rb_define_singleton_method(Berns, "picture", external_picture_element, -1);
821
- rb_define_singleton_method(Berns, "pre", external_pre_element, -1);
822
- rb_define_singleton_method(Berns, "progress", external_progress_element, -1);
823
- rb_define_singleton_method(Berns, "q", external_q_element, -1);
824
- rb_define_singleton_method(Berns, "rp", external_rp_element, -1);
825
- rb_define_singleton_method(Berns, "rt", external_rt_element, -1);
826
- rb_define_singleton_method(Berns, "ruby", external_ruby_element, -1);
827
- rb_define_singleton_method(Berns, "s", external_s_element, -1);
828
- rb_define_singleton_method(Berns, "samp", external_samp_element, -1);
829
- rb_define_singleton_method(Berns, "script", external_script_element, -1);
830
- rb_define_singleton_method(Berns, "section", external_section_element, -1);
831
- rb_define_singleton_method(Berns, "select", external_select_element, -1);
832
- rb_define_singleton_method(Berns, "small", external_small_element, -1);
833
- rb_define_singleton_method(Berns, "span", external_span_element, -1);
834
- rb_define_singleton_method(Berns, "strong", external_strong_element, -1);
835
- rb_define_singleton_method(Berns, "style", external_style_element, -1);
836
- rb_define_singleton_method(Berns, "sub", external_sub_element, -1);
837
- rb_define_singleton_method(Berns, "summary", external_summary_element, -1);
838
- rb_define_singleton_method(Berns, "table", external_table_element, -1);
839
- rb_define_singleton_method(Berns, "tbody", external_tbody_element, -1);
840
- rb_define_singleton_method(Berns, "td", external_td_element, -1);
841
- rb_define_singleton_method(Berns, "template", external_template_element, -1);
842
- rb_define_singleton_method(Berns, "textarea", external_textarea_element, -1);
843
- rb_define_singleton_method(Berns, "tfoot", external_tfoot_element, -1);
844
- rb_define_singleton_method(Berns, "th", external_th_element, -1);
845
- rb_define_singleton_method(Berns, "thead", external_thead_element, -1);
846
- rb_define_singleton_method(Berns, "time", external_time_element, -1);
847
- rb_define_singleton_method(Berns, "title", external_title_element, -1);
848
- rb_define_singleton_method(Berns, "tr", external_tr_element, -1);
849
- rb_define_singleton_method(Berns, "u", external_u_element, -1);
850
- rb_define_singleton_method(Berns, "ul", external_ul_element, -1);
851
- rb_define_singleton_method(Berns, "var", external_var_element, -1);
852
- rb_define_singleton_method(Berns, "video", external_video_element, -1);
721
+ VALUE Berns = rb_define_module("Berns");
722
+
723
+ rb_define_singleton_method(Berns, "element", external_element, -1);
724
+ rb_define_singleton_method(Berns, "escape_html", external_escape_html, 1);
725
+ rb_define_singleton_method(Berns, "sanitize", external_sanitize, 1);
726
+ rb_define_singleton_method(Berns, "to_attribute", external_to_attribute, 2);
727
+ rb_define_singleton_method(Berns, "to_attributes", external_to_attributes, 1);
728
+ rb_define_singleton_method(Berns, "void", external_void_element, -1);
729
+
730
+ /*
731
+ * List of void elements - http://xahlee.info/js/html5_non-closing_tag.html
732
+ *
733
+ * area base br col embed hr img input link menuitem meta param source track
734
+ * wbr
735
+ *
736
+ */
737
+ rb_define_singleton_method(Berns, "area", external_area_element, -1);
738
+ rb_define_singleton_method(Berns, "base", external_base_element, -1);
739
+ rb_define_singleton_method(Berns, "br", external_br_element, -1);
740
+ rb_define_singleton_method(Berns, "col", external_col_element, -1);
741
+ rb_define_singleton_method(Berns, "embed", external_embed_element, -1);
742
+ rb_define_singleton_method(Berns, "hr", external_hr_element, -1);
743
+ rb_define_singleton_method(Berns, "img", external_img_element, -1);
744
+ rb_define_singleton_method(Berns, "input", external_input_element, -1);
745
+ rb_define_singleton_method(Berns, "link", external_link_element, -1);
746
+ rb_define_singleton_method(Berns, "menuitem", external_menuitem_element, -1);
747
+ rb_define_singleton_method(Berns, "meta", external_meta_element, -1);
748
+ rb_define_singleton_method(Berns, "param", external_param_element, -1);
749
+ rb_define_singleton_method(Berns, "source", external_source_element, -1);
750
+ rb_define_singleton_method(Berns, "track", external_track_element, -1);
751
+ rb_define_singleton_method(Berns, "wbr", external_wbr_element, -1);
752
+
753
+ /*
754
+ * List of standard HTML5 elements - https://www.w3schools.com/TAgs/default.asp
755
+ *
756
+ * a abbr address article aside audio b bdi bdo blockquote body button canvas
757
+ * caption cite code colgroup datalist dd del details dfn dialog div dl dt em
758
+ * fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 head header html i
759
+ * iframe ins kbd label legend li main map mark menu meter nav noscript object
760
+ * ol optgroup option output p picture pre progress q rp rt ruby s samp script
761
+ * section select small span strong style sub summary table tbody td template
762
+ * textarea tfoot th thead time title tr u ul var video
763
+ *
764
+ */
765
+ rb_define_singleton_method(Berns, "a", external_a_element, -1);
766
+ rb_define_singleton_method(Berns, "abbr", external_abbr_element, -1);
767
+ rb_define_singleton_method(Berns, "address", external_address_element, -1);
768
+ rb_define_singleton_method(Berns, "article", external_article_element, -1);
769
+ rb_define_singleton_method(Berns, "aside", external_aside_element, -1);
770
+ rb_define_singleton_method(Berns, "audio", external_audio_element, -1);
771
+ rb_define_singleton_method(Berns, "b", external_b_element, -1);
772
+ rb_define_singleton_method(Berns, "bdi", external_bdi_element, -1);
773
+ rb_define_singleton_method(Berns, "bdo", external_bdo_element, -1);
774
+ rb_define_singleton_method(Berns, "blockquote", external_blockquote_element, -1);
775
+ rb_define_singleton_method(Berns, "body", external_body_element, -1);
776
+ rb_define_singleton_method(Berns, "button", external_button_element, -1);
777
+ rb_define_singleton_method(Berns, "canvas", external_canvas_element, -1);
778
+ rb_define_singleton_method(Berns, "caption", external_caption_element, -1);
779
+ rb_define_singleton_method(Berns, "cite", external_cite_element, -1);
780
+ rb_define_singleton_method(Berns, "code", external_code_element, -1);
781
+ rb_define_singleton_method(Berns, "colgroup", external_colgroup_element, -1);
782
+ rb_define_singleton_method(Berns, "datalist", external_datalist_element, -1);
783
+ rb_define_singleton_method(Berns, "dd", external_dd_element, -1);
784
+ rb_define_singleton_method(Berns, "del", external_del_element, -1);
785
+ rb_define_singleton_method(Berns, "details", external_details_element, -1);
786
+ rb_define_singleton_method(Berns, "dfn", external_dfn_element, -1);
787
+ rb_define_singleton_method(Berns, "dialog", external_dialog_element, -1);
788
+ rb_define_singleton_method(Berns, "div", external_div_element, -1);
789
+ rb_define_singleton_method(Berns, "dl", external_dl_element, -1);
790
+ rb_define_singleton_method(Berns, "dt", external_dt_element, -1);
791
+ rb_define_singleton_method(Berns, "em", external_em_element, -1);
792
+ rb_define_singleton_method(Berns, "fieldset", external_fieldset_element, -1);
793
+ rb_define_singleton_method(Berns, "figcaption", external_figcaption_element, -1);
794
+ rb_define_singleton_method(Berns, "figure", external_figure_element, -1);
795
+ rb_define_singleton_method(Berns, "footer", external_footer_element, -1);
796
+ rb_define_singleton_method(Berns, "form", external_form_element, -1);
797
+ rb_define_singleton_method(Berns, "h1", external_h1_element, -1);
798
+ rb_define_singleton_method(Berns, "h2", external_h2_element, -1);
799
+ rb_define_singleton_method(Berns, "h3", external_h3_element, -1);
800
+ rb_define_singleton_method(Berns, "h4", external_h4_element, -1);
801
+ rb_define_singleton_method(Berns, "h5", external_h5_element, -1);
802
+ rb_define_singleton_method(Berns, "h6", external_h6_element, -1);
803
+ rb_define_singleton_method(Berns, "head", external_head_element, -1);
804
+ rb_define_singleton_method(Berns, "header", external_header_element, -1);
805
+ rb_define_singleton_method(Berns, "html", external_html_element, -1);
806
+ rb_define_singleton_method(Berns, "i", external_i_element, -1);
807
+ rb_define_singleton_method(Berns, "iframe", external_iframe_element, -1);
808
+ rb_define_singleton_method(Berns, "ins", external_ins_element, -1);
809
+ rb_define_singleton_method(Berns, "kbd", external_kbd_element, -1);
810
+ rb_define_singleton_method(Berns, "label", external_label_element, -1);
811
+ rb_define_singleton_method(Berns, "legend", external_legend_element, -1);
812
+ rb_define_singleton_method(Berns, "li", external_li_element, -1);
813
+ rb_define_singleton_method(Berns, "main", external_main_element, -1);
814
+ rb_define_singleton_method(Berns, "map", external_map_element, -1);
815
+ rb_define_singleton_method(Berns, "mark", external_mark_element, -1);
816
+ rb_define_singleton_method(Berns, "menu", external_menu_element, -1);
817
+ rb_define_singleton_method(Berns, "meter", external_meter_element, -1);
818
+ rb_define_singleton_method(Berns, "nav", external_nav_element, -1);
819
+ rb_define_singleton_method(Berns, "noscript", external_noscript_element, -1);
820
+ rb_define_singleton_method(Berns, "object", external_object_element, -1);
821
+ rb_define_singleton_method(Berns, "ol", external_ol_element, -1);
822
+ rb_define_singleton_method(Berns, "optgroup", external_optgroup_element, -1);
823
+ rb_define_singleton_method(Berns, "option", external_option_element, -1);
824
+ rb_define_singleton_method(Berns, "output", external_output_element, -1);
825
+ rb_define_singleton_method(Berns, "p", external_p_element, -1);
826
+ rb_define_singleton_method(Berns, "picture", external_picture_element, -1);
827
+ rb_define_singleton_method(Berns, "pre", external_pre_element, -1);
828
+ rb_define_singleton_method(Berns, "progress", external_progress_element, -1);
829
+ rb_define_singleton_method(Berns, "q", external_q_element, -1);
830
+ rb_define_singleton_method(Berns, "rp", external_rp_element, -1);
831
+ rb_define_singleton_method(Berns, "rt", external_rt_element, -1);
832
+ rb_define_singleton_method(Berns, "ruby", external_ruby_element, -1);
833
+ rb_define_singleton_method(Berns, "s", external_s_element, -1);
834
+ rb_define_singleton_method(Berns, "samp", external_samp_element, -1);
835
+ rb_define_singleton_method(Berns, "script", external_script_element, -1);
836
+ rb_define_singleton_method(Berns, "section", external_section_element, -1);
837
+ rb_define_singleton_method(Berns, "select", external_select_element, -1);
838
+ rb_define_singleton_method(Berns, "small", external_small_element, -1);
839
+ rb_define_singleton_method(Berns, "span", external_span_element, -1);
840
+ rb_define_singleton_method(Berns, "strong", external_strong_element, -1);
841
+ rb_define_singleton_method(Berns, "style", external_style_element, -1);
842
+ rb_define_singleton_method(Berns, "sub", external_sub_element, -1);
843
+ rb_define_singleton_method(Berns, "summary", external_summary_element, -1);
844
+ rb_define_singleton_method(Berns, "table", external_table_element, -1);
845
+ rb_define_singleton_method(Berns, "tbody", external_tbody_element, -1);
846
+ rb_define_singleton_method(Berns, "td", external_td_element, -1);
847
+ rb_define_singleton_method(Berns, "template", external_template_element, -1);
848
+ rb_define_singleton_method(Berns, "textarea", external_textarea_element, -1);
849
+ rb_define_singleton_method(Berns, "tfoot", external_tfoot_element, -1);
850
+ rb_define_singleton_method(Berns, "th", external_th_element, -1);
851
+ rb_define_singleton_method(Berns, "thead", external_thead_element, -1);
852
+ rb_define_singleton_method(Berns, "time", external_time_element, -1);
853
+ rb_define_singleton_method(Berns, "title", external_title_element, -1);
854
+ rb_define_singleton_method(Berns, "tr", external_tr_element, -1);
855
+ rb_define_singleton_method(Berns, "u", external_u_element, -1);
856
+ rb_define_singleton_method(Berns, "ul", external_ul_element, -1);
857
+ rb_define_singleton_method(Berns, "var", external_var_element, -1);
858
+ rb_define_singleton_method(Berns, "video", external_video_element, -1);
853
859
  }