berns 4.1.2 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
  }