dtext_rb 1.3.0 → 1.4.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/dtext/dtext.h DELETED
@@ -1,4 +0,0 @@
1
- #ifndef DTEXT_H
2
- #define DTEXT_H
3
-
4
- #endif
data/ext/dtext/dtext.rl DELETED
@@ -1,1454 +0,0 @@
1
- // situationally print newlines to make the generated html
2
- // easier to read
3
- #define PRETTY_PRINT 0
4
-
5
- #include <ruby.h>
6
- #include <ruby/encoding.h>
7
- #include <stdio.h>
8
- #include <stdint.h>
9
- #include <stdbool.h>
10
- #include <glib.h>
11
-
12
- typedef struct StateMachine {
13
- size_t top;
14
- int cs;
15
- int act;
16
- const char * p;
17
- const char * pb;
18
- const char * pe;
19
- const char * eof;
20
- const char * ts;
21
- const char * te;
22
-
23
- const char * a1;
24
- const char * a2;
25
- const char * b1;
26
- const char * b2;
27
- bool f_inline;
28
- bool f_strip;
29
- bool f_mentions;
30
- bool list_mode;
31
- bool header_mode;
32
- GString * output;
33
- GArray * stack;
34
- GQueue * dstack;
35
- int list_nest;
36
- int d;
37
- int b;
38
- int quote;
39
- } StateMachine;
40
-
41
- static const size_t MAX_STACK_DEPTH = 512;
42
-
43
- static const int BLOCK_P = 1;
44
- static const int INLINE_SPOILER = 2;
45
- static const int BLOCK_SPOILER = 3;
46
- static const int BLOCK_QUOTE = 4;
47
- static const int BLOCK_EXPAND = 5;
48
- static const int BLOCK_NODTEXT = 6;
49
- static const int BLOCK_CODE = 7;
50
- static const int BLOCK_TD = 8;
51
- static const int INLINE_NODTEXT = 9;
52
- static const int INLINE_B = 10;
53
- static const int INLINE_I = 11;
54
- static const int INLINE_U = 12;
55
- static const int INLINE_S = 13;
56
- static const int INLINE_TN = 14;
57
- static const int BLOCK_TN = 15;
58
- static const int BLOCK_TABLE = 16;
59
- static const int BLOCK_THEAD = 17;
60
- static const int BLOCK_TBODY = 18;
61
- static const int BLOCK_TR = 19;
62
- static const int BLOCK_UL = 20;
63
- static const int BLOCK_LI = 21;
64
- static const int BLOCK_TH = 22;
65
- static const int BLOCK_H1 = 23;
66
- static const int BLOCK_H2 = 24;
67
- static const int BLOCK_H3 = 25;
68
- static const int BLOCK_H4 = 26;
69
- static const int BLOCK_H5 = 27;
70
- static const int BLOCK_H6 = 28;
71
-
72
- %%{
73
- machine dtext;
74
-
75
- access sm->;
76
- variable p sm->p;
77
- variable pe sm->pe;
78
- variable eof sm->eof;
79
- variable top sm->top;
80
- variable ts sm->ts;
81
- variable te sm->te;
82
- variable act sm->act;
83
- variable stack ((int *)sm->stack->data);
84
-
85
- prepush {
86
- size_t len = sm->stack->len;
87
-
88
- if (len > MAX_STACK_DEPTH) {
89
- free_machine(sm);
90
- rb_raise(rb_eSyntaxError, "too many nested elements");
91
- }
92
-
93
- if (sm->top >= len) {
94
- sm->stack = g_array_set_size(sm->stack, len + 16);
95
- }
96
- }
97
-
98
- action mark_a1 {
99
- sm->a1 = sm->p;
100
- }
101
-
102
- action mark_a2 {
103
- sm->a2 = sm->p;
104
- }
105
-
106
- action mark_b1 {
107
- sm->b1 = sm->p;
108
- }
109
-
110
- action mark_b2 {
111
- sm->b2 = sm->p;
112
- }
113
-
114
- newline = '\r\n' | '\n';
115
-
116
- nonnewline = any - (newline | '\0' | '\r');
117
- nonquote = ^'"';
118
- nonbracket = ^']';
119
- nonpipe = ^'|';
120
- nonpipebracket = nonpipe & nonbracket;
121
- noncurly = ^'}';
122
-
123
- utf8graph = (0x00..0x7F) & graph
124
- | 0xC2..0xDF 0x80..0xBF
125
- | 0xE0..0xEF 0x80..0xBF 0x80..0xBF
126
- | 0xF0..0xF4 0x80..0xBF 0x80..0xBF 0x80..0xBF;
127
-
128
-
129
- mention = '@' utf8graph+ >mark_a1 %mark_a2;
130
-
131
- url = 'http' 's'? '://' utf8graph+;
132
- internal_url = '/' utf8graph+;
133
- basic_textile_link = '"' nonquote+ >mark_a1 '"' >mark_a2 ':' (url | internal_url) >mark_b1 %mark_b2;
134
- bracketed_textile_link = '"' nonquote+ >mark_a1 '"' >mark_a2 ':[' (url | internal_url) >mark_b1 %mark_b2 :>> ']';
135
-
136
- basic_wiki_link = '[[' (nonbracket nonpipebracket*) >mark_a1 %mark_a2 ']]';
137
- aliased_wiki_link = '[[' nonpipebracket+ >mark_a1 %mark_a2 '|' nonpipebracket+ >mark_b1 %mark_b2 ']]';
138
-
139
- post_link = '{{' noncurly+ >mark_a1 %mark_a2 '}}';
140
-
141
- spoilers_open = '[spoiler'i 's'i? ']';
142
- spoilers_close = '[/spoiler'i 's'i? ']';
143
-
144
- post_id = 'post #'i digit+ >mark_a1 %mark_a2;
145
- forum_post_id = 'forum #'i digit+ >mark_a1 %mark_a2;
146
- forum_topic_id = 'topic #'i digit+ >mark_a1 %mark_a2;
147
- forum_topic_paged_id = 'topic #'i digit+ >mark_a1 %mark_a2 '/p' digit+ >mark_b1 %mark_b2;
148
- comment_id = 'comment #'i digit+ >mark_a1 %mark_a2;
149
- pool_id = 'pool #'i digit+ >mark_a1 %mark_a2;
150
- user_id = 'user #'i digit+ >mark_a1 %mark_a2;
151
- artist_id = 'artist #'i digit+ >mark_a1 %mark_a2;
152
- github_issue_id = 'issue #'i digit+ >mark_a1 %mark_a2;
153
- pixiv_id = 'pixiv #'i digit+ >mark_a1 %mark_a2;
154
- pixiv_paged_id = 'pixiv #'i digit+ >mark_a1 %mark_a2 '/p' digit+ >mark_b1 %mark_b2;
155
-
156
- ws = ' ' | '\t';
157
- nonperiod = graph - ('.' | '"');
158
- header = 'h'i [123456] >mark_a1 %mark_a2 '.' ws*;
159
- header_with_id = 'h'i [123456] >mark_a1 %mark_a2 '#' nonperiod+ >mark_b1 %mark_b2 '.' ws*;
160
- aliased_expand = '[expand='i (nonbracket+ >mark_a1 %mark_a2) ']';
161
-
162
- list_item = '*'+ >mark_a1 %mark_a2 ws+ nonnewline+ >mark_b1 %mark_b2;
163
-
164
- inline := |*
165
- post_id => {
166
- append(sm, true, "<a href=\"/posts/");
167
- append_segment(sm, true, sm->a1, sm->a2 - 1);
168
- append(sm, true, "\">");
169
- append(sm, false, "post #");
170
- append_segment(sm, false, sm->a1, sm->a2 - 1);
171
- append(sm, true, "</a>");
172
- };
173
-
174
- forum_post_id => {
175
- append(sm, true, "<a href=\"/forum_posts/");
176
- append_segment(sm, true, sm->a1, sm->a2 - 1);
177
- append(sm, true, "\">");
178
- append(sm, false, "forum #");
179
- append_segment(sm, false, sm->a1, sm->a2 - 1);
180
- append(sm, true, "</a>");
181
- };
182
-
183
- forum_topic_id => {
184
- append(sm, true, "<a href=\"/forum_topics/");
185
- append_segment(sm, true, sm->a1, sm->a2 - 1);
186
- append(sm, true, "\">");
187
- append(sm, false, "topic #");
188
- append_segment(sm, false, sm->a1, sm->a2 - 1);
189
- append(sm, true, "</a>");
190
- };
191
-
192
- forum_topic_paged_id => {
193
- append(sm, true, "<a href=\"/forum_topics/");
194
- append_segment(sm, true, sm->a1, sm->a2 - 1);
195
- append(sm, true, "?page=");
196
- append_segment(sm, true, sm->b1, sm->b2 - 1);
197
- append(sm, true, "\">");
198
- append(sm, false, "topic #");
199
- append_segment(sm, false, sm->a1, sm->a2 - 1);
200
- append(sm, false, "/p");
201
- append_segment(sm, false, sm->b1, sm->b2 - 1);
202
- append(sm, true, "</a>");
203
- };
204
-
205
- comment_id => {
206
- append(sm, true, "<a href=\"/comments/");
207
- append_segment(sm, true, sm->a1, sm->a2 - 1);
208
- append(sm, true, "\">");
209
- append(sm, false, "comment #");
210
- append_segment(sm, false, sm->a1, sm->a2 - 1);
211
- append(sm, true, "</a>");
212
- };
213
-
214
- pool_id => {
215
- append(sm, true, "<a href=\"/pools/");
216
- append_segment(sm, true, sm->a1, sm->a2 - 1);
217
- append(sm, true, "\">");
218
- append(sm, false, "pool #");
219
- append_segment(sm, false, sm->a1, sm->a2 - 1);
220
- append(sm, true, "</a>");
221
- };
222
-
223
- user_id => {
224
- append(sm, true, "<a href=\"/users/");
225
- append_segment(sm, true, sm->a1, sm->a2 - 1);
226
- append(sm, true, "\">");
227
- append(sm, false, "user #");
228
- append_segment(sm, false, sm->a1, sm->a2 - 1);
229
- append(sm, true, "</a>");
230
- };
231
-
232
- artist_id => {
233
- append(sm, true, "<a href=\"/artists/");
234
- append_segment(sm, true, sm->a1, sm->a2 - 1);
235
- append(sm, true, "\">");
236
- append(sm, false, "artist #");
237
- append_segment(sm, false, sm->a1, sm->a2 - 1);
238
- append(sm, true, "</a>");
239
- };
240
-
241
- github_issue_id => {
242
- append(sm, true, "<a href=\"https://github.com/r888888888/danbooru/issues/");
243
- append_segment(sm, true, sm->a1, sm->a2 - 1);
244
- append(sm, true, "\">");
245
- append(sm, false, "issue #");
246
- append_segment(sm, false, sm->a1, sm->a2 - 1);
247
- append(sm, true, "</a>");
248
- };
249
-
250
- pixiv_id => {
251
- append(sm, true, "<a href=\"http://www.pixiv.net/member_illust.php?mode=medium&illust_id=");
252
- append_segment(sm, true, sm->a1, sm->a2 - 1);
253
- append(sm, true, "\">");
254
- append(sm, false, "pixiv #");
255
- append_segment(sm, false, sm->a1, sm->a2 - 1);
256
- append(sm, true, "</a>");
257
- };
258
-
259
- pixiv_paged_id => {
260
- append(sm, true, "<a href=\"http://www.pixiv.net/member_illust.php?mode=manga_big&illust_id=");
261
- append_segment(sm, true, sm->a1, sm->a2 - 1);
262
- append(sm, true, "&page=");
263
- append_segment(sm, true, sm->b1, sm->b2 - 1);
264
- append(sm, true, "\">");
265
- append(sm, false, "pixiv #");
266
- append_segment(sm, false, sm->a1, sm->a2 - 1);
267
- append(sm, false, "/p");
268
- append_segment(sm, false, sm->b1, sm->b2 - 1);
269
- append(sm, true, "</a>");
270
- };
271
-
272
- post_link => {
273
- append(sm, true, "<a rel=\"nofollow\" href=\"/posts?tags=");
274
- append_segment_uri_escaped(sm, sm->a1, sm->a2 - 1);
275
- append(sm, true, "\">");
276
- append_segment_html_escaped(sm, sm->a1, sm->a2 - 1);
277
- append(sm, true, "</a>");
278
- };
279
-
280
- basic_wiki_link => {
281
- GString * segment = g_string_new_len(sm->a1, sm->a2 - sm->a1);
282
- GString * lowercase_segment = NULL;
283
- underscore_string(segment->str, segment->len);
284
-
285
- if (g_utf8_validate(segment->str, -1, NULL)) {
286
- lowercase_segment = g_string_new(g_utf8_strdown(segment->str, -1));
287
- } else {
288
- lowercase_segment = g_string_new(g_ascii_strdown(segment->str, -1));
289
- }
290
-
291
- append(sm, true, "<a href=\"/wiki_pages/show_or_new?title=");
292
- append_segment_uri_escaped(sm, lowercase_segment->str, lowercase_segment->str + lowercase_segment->len - 1);
293
- append(sm, true, "\">");
294
- append_segment_html_escaped(sm, sm->a1, sm->a2 - 1);
295
- append(sm, true, "</a>");
296
-
297
- g_string_free(lowercase_segment, TRUE);
298
- g_string_free(segment, TRUE);
299
- };
300
-
301
- aliased_wiki_link => {
302
- GString * segment = g_string_new_len(sm->a1, sm->a2 - sm->a1);
303
- GString * lowercase_segment = NULL;
304
- underscore_string(segment->str, segment->len);
305
-
306
- if (g_utf8_validate(segment->str, -1, NULL)) {
307
- lowercase_segment = g_string_new(g_utf8_strdown(segment->str, -1));
308
- } else {
309
- lowercase_segment = g_string_new(g_ascii_strdown(segment->str, -1));
310
- }
311
-
312
- append(sm, true, "<a href=\"/wiki_pages/show_or_new?title=");
313
- append_segment_uri_escaped(sm, lowercase_segment->str, lowercase_segment->str + lowercase_segment->len - 1);
314
- append(sm, true, "\">");
315
- append_segment_html_escaped(sm, sm->b1, sm->b2 - 1);
316
- append(sm, true, "</a>");
317
-
318
- g_string_free(lowercase_segment, TRUE);
319
- g_string_free(segment, TRUE);
320
- };
321
-
322
- basic_textile_link => {
323
- if (is_boundary_c(fc)) {
324
- sm->d = 2;
325
- sm->b = true;
326
- } else {
327
- sm->d = 1;
328
- sm->b = false;
329
- }
330
-
331
- append(sm, true, "<a href=\"");
332
- append_segment_html_escaped(sm, sm->b1, sm->b2 - sm->d);
333
- append(sm, true, "\">");
334
- link_content_sm = parse_helper(sm->a1, sm->a2 - sm->a1, false, true, false);
335
- append(sm, true, link_content_sm->output->str);
336
- free_machine(link_content_sm);
337
- link_content_sm = NULL;
338
- append(sm, true, "</a>");
339
-
340
- if (sm->b) {
341
- append_c_html_escaped(sm, fc);
342
- }
343
- };
344
-
345
- bracketed_textile_link => {
346
- append(sm, true, "<a href=\"");
347
- append_segment_html_escaped(sm, sm->b1, sm->b2 - 1);
348
- append(sm, true, "\">");
349
- append_segment_html_escaped(sm, sm->a1, sm->a2 - 1);
350
- append(sm, true, "</a>");
351
- };
352
-
353
- url => {
354
- if (is_boundary_c(fc)) {
355
- sm->b = true;
356
- sm->d = 2;
357
- } else {
358
- sm->b = false;
359
- sm->d = 1;
360
- }
361
-
362
- append(sm, true, "<a href=\"");
363
- append_segment_html_escaped(sm, sm->ts, sm->te - sm->d);
364
- append(sm, true, "\">");
365
- append_segment_html_escaped(sm, sm->ts, sm->te - sm->d);
366
- append(sm, true, "</a>");
367
-
368
- if (sm->b) {
369
- append_c_html_escaped(sm, fc);
370
- }
371
- };
372
-
373
- # probably a tag. examples include @.@ and @_@
374
- '@' graph '@' => {
375
- append_segment_html_escaped(sm, sm->ts, sm->te - 1);
376
- };
377
-
378
- mention => {
379
- if (!sm->f_mentions || (sm->a1 > sm->pb && sm->a1 - 1 > sm->pb && sm->a1[-2] != ' ' && sm->a1[-2] != '\r' && sm->a1[-2] != '\n')) {
380
- // handle emails
381
- append_c(sm, '@');
382
- append_segment_html_escaped(sm, sm->a1, sm->a2 - 1);
383
-
384
- } else {
385
- if (is_boundary_c(fc)) {
386
- sm->b = true;
387
- sm->d = 2;
388
- } else {
389
- sm->b = false;
390
- sm->d = 1;
391
- }
392
-
393
- append(sm, true, "<a rel=\"nofollow\" href=\"/users?name=");
394
- append_segment_uri_escaped(sm, sm->a1, sm->a2 - sm->d);
395
- append(sm, true, "\">");
396
- append_c(sm, '@');
397
- append_segment_html_escaped(sm, sm->a1, sm->a2 - sm->d);
398
- append(sm, true, "</a>");
399
-
400
- if (sm->b) {
401
- append_c_html_escaped(sm, fc);
402
- }
403
- }
404
- };
405
-
406
- newline list_item => {
407
- g_debug("inline list");
408
-
409
- if (dstack_check(sm, BLOCK_LI)) {
410
- g_debug(" rewind li");
411
- dstack_rewind(sm);
412
- } else if (dstack_check(sm, BLOCK_P)) {
413
- g_debug(" rewind p");
414
- dstack_rewind(sm);
415
- } else if (sm->header_mode) {
416
- g_debug(" rewind header");
417
- dstack_rewind(sm);
418
- }
419
-
420
- g_debug(" next list");
421
- fexec sm->ts + 1;
422
- fnext list;
423
- };
424
-
425
- '[b]'i => {
426
- dstack_push(sm, &INLINE_B);
427
- append(sm, true, "<strong>");
428
- };
429
-
430
- '[/b]'i => {
431
- if (dstack_check(sm, INLINE_B)) {
432
- dstack_pop(sm);
433
- append(sm, true, "</strong>");
434
- } else {
435
- append(sm, true, "[/b]");
436
- }
437
- };
438
-
439
- '[i]'i => {
440
- dstack_push(sm, &INLINE_I);
441
- append(sm, true, "<em>");
442
- };
443
-
444
- '[/i]'i => {
445
- if (dstack_check(sm, INLINE_I)) {
446
- dstack_pop(sm);
447
- append(sm, true, "</em>");
448
- } else {
449
- append(sm, true, "[/i]");
450
- }
451
- };
452
-
453
- '[s]'i => {
454
- dstack_push(sm, &INLINE_S);
455
- append(sm, true, "<s>");
456
- };
457
-
458
- '[/s]'i => {
459
- if (dstack_check(sm, INLINE_S)) {
460
- dstack_pop(sm);
461
- append(sm, true, "</s>");
462
- } else {
463
- append(sm, true, "[/s]");
464
- }
465
- };
466
-
467
- '[u]'i => {
468
- dstack_push(sm, &INLINE_U);
469
- append(sm, true, "<u>");
470
- };
471
-
472
- '[/u]'i => {
473
- if (dstack_check(sm, INLINE_U)) {
474
- dstack_pop(sm);
475
- append(sm, true, "</u>");
476
- } else {
477
- append(sm, true, "[/u]");
478
- }
479
- };
480
-
481
- '[tn]'i => {
482
- dstack_push(sm, &INLINE_TN);
483
- append(sm, true, "<span class=\"tn\">");
484
- };
485
-
486
- '[/tn]'i => {
487
- dstack_close_before_block(sm);
488
-
489
- if (dstack_check(sm, BLOCK_TN)) {
490
- dstack_pop(sm);
491
- fret;
492
- } else if (dstack_check(sm, INLINE_TN)) {
493
- dstack_pop(sm);
494
- append(sm, true, "</span>");
495
- } else {
496
- append_block(sm, "[/tn]");
497
- }
498
- };
499
-
500
- spoilers_open => {
501
- g_debug("inline [spoiler]");
502
- g_debug(" push <span>");
503
- dstack_push(sm, &INLINE_SPOILER);
504
- append(sm, true, "<span class=\"spoiler\">");
505
- };
506
-
507
- spoilers_close => {
508
- g_debug("inline [/spoiler]");
509
- dstack_close_before_block(sm);
510
-
511
- if (dstack_check(sm, INLINE_SPOILER)) {
512
- g_debug(" pop dstack");
513
- g_debug(" print </span>");
514
- dstack_pop(sm);
515
- append(sm, true, "</span>");
516
- } else if (dstack_check(sm, BLOCK_SPOILER)) {
517
- g_debug(" pop dstack");
518
- g_debug(" print </div>");
519
- g_debug(" return");
520
- dstack_pop(sm);
521
- append_block(sm, "</div>");
522
- fret;
523
- } else {
524
- append_block(sm, "[/spoiler]");
525
- }
526
- };
527
-
528
- '[nodtext]'i => {
529
- dstack_push(sm, &INLINE_NODTEXT);
530
- g_debug("push inline nodtext");
531
- fcall nodtext;
532
- };
533
-
534
- # these are block level elements that should kick us out of the inline
535
- # scanner
536
-
537
- '[quote]'i => {
538
- g_debug("inline [quote]");
539
- dstack_close_before_block(sm);
540
- fexec sm->ts;
541
- fret;
542
- };
543
-
544
- '[/quote]'i space* => {
545
- g_debug("inline [/quote]");
546
- dstack_close_before_block(sm);
547
-
548
- if (dstack_check(sm, BLOCK_LI)) {
549
- dstack_close_list(sm);
550
- }
551
-
552
- if (dstack_check(sm, BLOCK_QUOTE)) {
553
- dstack_rewind(sm);
554
- fret;
555
- } else {
556
- append_block(sm, "[/quote]");
557
- }
558
- };
559
-
560
- '[expand]'i => {
561
- g_debug("inline [expand]");
562
- dstack_rewind(sm);
563
- fexec(sm->p - 7);
564
- fret;
565
- };
566
-
567
- '[/expand]'i => {
568
- dstack_close_before_block(sm);
569
-
570
- if (dstack_check(sm, BLOCK_EXPAND)) {
571
- append_block(sm, "</div></div>");
572
- dstack_pop(sm);
573
- fret;
574
- } else {
575
- append_block(sm, "[/expand]");
576
- }
577
- };
578
-
579
- '[/th]'i => {
580
- if (dstack_check(sm, BLOCK_TH)) {
581
- dstack_pop(sm);
582
- append_block(sm, "</th>");
583
- fret;
584
- } else {
585
- append_block(sm, "[/th]");
586
- }
587
- };
588
-
589
- '[/td]'i => {
590
- if (dstack_check(sm, BLOCK_TD)) {
591
- dstack_pop(sm);
592
- append_block(sm, "</td>");
593
- fret;
594
- } else {
595
- append_block(sm, "[/td]");
596
- }
597
- };
598
-
599
- '\0' => {
600
- g_debug("inline 0");
601
- g_debug(" return");
602
-
603
- fhold;
604
- fret;
605
- };
606
-
607
- newline{2,} => {
608
- g_debug("inline newline2");
609
- g_debug(" return");
610
-
611
- if (sm->list_mode) {
612
- dstack_close_list(sm);
613
- }
614
-
615
- fexec sm->ts;
616
- fret;
617
- };
618
-
619
- newline => {
620
- g_debug("inline newline");
621
-
622
- if (sm->header_mode) {
623
- sm->header_mode = false;
624
- dstack_rewind(sm);
625
- fret;
626
- } else {
627
- append(sm, true, "<br>");
628
- }
629
- };
630
-
631
- '\r' => {
632
- append_c(sm, ' ');
633
- };
634
-
635
- any => {
636
- g_debug("inline char: %c", fc);
637
- append_c_html_escaped(sm, fc);
638
- };
639
- *|;
640
-
641
- code := |*
642
- '[/code]'i => {
643
- if (dstack_check(sm, BLOCK_CODE)) {
644
- dstack_rewind(sm);
645
- } else {
646
- append(sm, true, "[/code]");
647
- }
648
- fret;
649
- };
650
-
651
- '\0' => {
652
- fhold;
653
- fret;
654
- };
655
-
656
- any => {
657
- append_c_html_escaped(sm, fc);
658
- };
659
- *|;
660
-
661
- nodtext := |*
662
- '[/nodtext]'i => {
663
- if (dstack_check2(sm, BLOCK_NODTEXT)) {
664
- g_debug("block dstack check");
665
- dstack_pop(sm);
666
- dstack_pop(sm);
667
- append_block(sm, "</p>");
668
- fret;
669
- } else if (dstack_check(sm, INLINE_NODTEXT)) {
670
- g_debug("inline dstack check");
671
- dstack_pop(sm);
672
- fret;
673
- } else {
674
- g_debug("else dstack check");
675
- append(sm, true, "[/nodtext]");
676
- }
677
- };
678
-
679
- '\0' => {
680
- fhold;
681
- fret;
682
- };
683
-
684
- any => {
685
- append_c_html_escaped(sm, fc);
686
- };
687
- *|;
688
-
689
- table := |*
690
- '[thead]'i => {
691
- dstack_push(sm, &BLOCK_THEAD);
692
- append_block(sm, "<thead>");
693
- };
694
-
695
- '[/thead]'i => {
696
- if (dstack_check(sm, BLOCK_THEAD)) {
697
- dstack_pop(sm);
698
- append_block(sm, "</thead>");
699
- } else {
700
- append(sm, true, "[/thead]");
701
- }
702
- };
703
-
704
- '[tbody]'i => {
705
- dstack_push(sm, &BLOCK_TBODY);
706
- append_block(sm, "<tbody>");
707
- };
708
-
709
- '[/tbody]'i => {
710
- if (dstack_check(sm, BLOCK_TBODY)) {
711
- dstack_pop(sm);
712
- append_block(sm, "</tbody>");
713
- } else {
714
- append(sm, true, "[/tbody]");
715
- }
716
- };
717
-
718
- '[th]'i => {
719
- dstack_push(sm, &BLOCK_TH);
720
- append_block(sm, "<th>");
721
- fcall inline;
722
- };
723
-
724
- '[tr]'i => {
725
- dstack_push(sm, &BLOCK_TR);
726
- append_block(sm, "<tr>");
727
- };
728
-
729
- '[/tr]'i => {
730
- if (dstack_check(sm, BLOCK_TR)) {
731
- dstack_pop(sm);
732
- append_block(sm, "</tr>");
733
- } else {
734
- append(sm, true, "[/tr]");
735
- }
736
- };
737
-
738
- '[td]'i => {
739
- dstack_push(sm, &BLOCK_TD);
740
- append_block(sm, "<td>");
741
- fcall inline;
742
- };
743
-
744
- '[/table]'i => {
745
- if (dstack_check(sm, BLOCK_TABLE)) {
746
- dstack_pop(sm);
747
- append_block(sm, "</table>");
748
- fret;
749
- } else {
750
- append(sm, true, "[/table]");
751
- }
752
- };
753
-
754
- '\0' => {
755
- fhold;
756
- fret;
757
- };
758
-
759
- any;
760
- *|;
761
-
762
- list := |*
763
- list_item => {
764
- int prev_nest = sm->list_nest;
765
- append_closing_p_if(sm);
766
- g_debug("list start");
767
- sm->list_mode = true;
768
- sm->list_nest = sm->a2 - sm->a1;
769
- fexec sm->b1;
770
-
771
- if (sm->list_nest > prev_nest) {
772
- int i=0;
773
- for (i=prev_nest; i<sm->list_nest; ++i) {
774
- g_debug(" dstack push ul");
775
- g_debug(" print <ul>");
776
- append_block(sm, "<ul>");
777
- dstack_push(sm, &BLOCK_UL);
778
- }
779
- } else if (sm->list_nest < prev_nest) {
780
- int i=0;
781
- for (i=sm->list_nest; i<prev_nest; ++i) {
782
- if (dstack_check(sm, BLOCK_UL)) {
783
- g_debug(" dstack pop");
784
- g_debug(" print </ul>");
785
- dstack_pop(sm);
786
- append_block(sm, "</ul>");
787
- }
788
- }
789
- }
790
-
791
- append_block(sm, "<li>");
792
- dstack_push(sm, &BLOCK_LI);
793
-
794
- g_debug(" print <li>");
795
- g_debug(" push li");
796
- g_debug(" call inline");
797
-
798
- fcall inline;
799
- };
800
-
801
- # exit list
802
- (newline{2,} | '\0') => {
803
- dstack_close_list(sm);
804
- fexec sm->ts;
805
- fret;
806
- };
807
-
808
- newline;
809
-
810
- any => {
811
- dstack_rewind(sm);
812
- fhold;
813
- fret;
814
- };
815
- *|;
816
-
817
- main := |*
818
- header_with_id => {
819
- char header = *sm->a1;
820
- GString * id_name = g_string_new_len(sm->b1, sm->b2 - sm->b1);
821
- id_name = g_string_prepend(id_name, "dtext-");
822
-
823
- if (sm->f_inline) {
824
- header = '6';
825
- }
826
-
827
- if (!sm->f_strip) {
828
- switch (header) {
829
- case '1':
830
- dstack_push(sm, &BLOCK_H1);
831
- append_block(sm, "<h1 id=\"");
832
- append_block(sm, id_name->str);
833
- append_block(sm, "\">");
834
- break;
835
-
836
- case '2':
837
- dstack_push(sm, &BLOCK_H2);
838
- append_block(sm, "<h2 id=\"");
839
- append_block(sm, id_name->str);
840
- append_block(sm, "\">");
841
- break;
842
-
843
- case '3':
844
- dstack_push(sm, &BLOCK_H3);
845
- append_block(sm, "<h3 id=\"");
846
- append_block(sm, id_name->str);
847
- append_block(sm, "\">");
848
- break;
849
-
850
- case '4':
851
- dstack_push(sm, &BLOCK_H4);
852
- append_block(sm, "<h4 id=\"");
853
- append_block(sm, id_name->str);
854
- append_block(sm, "\">");
855
- break;
856
-
857
- case '5':
858
- dstack_push(sm, &BLOCK_H5);
859
- append_block(sm, "<h5 id=\"");
860
- append_block(sm, id_name->str);
861
- append_block(sm, "\">");
862
- break;
863
-
864
- case '6':
865
- dstack_push(sm, &BLOCK_H6);
866
- append_block(sm, "<h6 id=\"");
867
- append_block(sm, id_name->str);
868
- append_block(sm, "\">");
869
- break;
870
- }
871
- }
872
-
873
- sm->header_mode = true;
874
- g_string_free(id_name, false);
875
- id_name = NULL;
876
- fcall inline;
877
- };
878
-
879
- header => {
880
- char header = *sm->a1;
881
-
882
- if (sm->f_inline) {
883
- header = '6';
884
- }
885
-
886
- if (!sm->f_strip) {
887
- switch (header) {
888
- case '1':
889
- dstack_push(sm, &BLOCK_H1);
890
- append_block(sm, "<h1>");
891
- break;
892
-
893
- case '2':
894
- dstack_push(sm, &BLOCK_H2);
895
- append_block(sm, "<h2>");
896
- break;
897
-
898
- case '3':
899
- dstack_push(sm, &BLOCK_H3);
900
- append_block(sm, "<h3>");
901
- break;
902
-
903
- case '4':
904
- dstack_push(sm, &BLOCK_H4);
905
- append_block(sm, "<h4>");
906
- break;
907
-
908
- case '5':
909
- dstack_push(sm, &BLOCK_H5);
910
- append_block(sm, "<h5>");
911
- break;
912
-
913
- case '6':
914
- dstack_push(sm, &BLOCK_H6);
915
- append_block(sm, "<h6>");
916
- break;
917
- }
918
- }
919
-
920
- sm->header_mode = true;
921
- fcall inline;
922
- };
923
-
924
- '[quote]'i space* => {
925
- g_debug("block [quote]");
926
- g_debug(" push quote");
927
- g_debug(" print <blockquote>");
928
- dstack_close_before_block(sm);
929
- dstack_push(sm, &BLOCK_QUOTE);
930
- append_block(sm, "<blockquote>");
931
- };
932
-
933
- spoilers_open space* => {
934
- g_debug("block [spoiler]");
935
- g_debug(" push spoiler");
936
- g_debug(" print <div>");
937
- dstack_close_before_block(sm);
938
- dstack_push(sm, &BLOCK_SPOILER);
939
- append_block(sm, "<div class=\"spoiler\">");
940
- };
941
-
942
- spoilers_close => {
943
- g_debug("block [/spoiler]");
944
- dstack_close_before_block(sm);
945
- if (dstack_check(sm, BLOCK_SPOILER)) {
946
- g_debug(" rewind");
947
- dstack_rewind(sm);
948
- }
949
- };
950
-
951
- '[code]'i space* => {
952
- g_debug("block [code]");
953
- dstack_close_before_block(sm);
954
- dstack_push(sm, &BLOCK_CODE);
955
- append_block(sm, "<pre>");
956
- fcall code;
957
- };
958
-
959
- '[expand]'i space* => {
960
- g_debug("block [expand]");
961
- dstack_close_before_block(sm);
962
- dstack_push(sm, &BLOCK_EXPAND);
963
- append_block(sm, "<div class=\"expandable\"><div class=\"expandable-header\">");
964
- append_block(sm, "<input type=\"button\" value=\"Show\" class=\"expandable-button\"/></div>");
965
- append_block(sm, "<div class=\"expandable-content\">");
966
- };
967
-
968
- aliased_expand space* => {
969
- g_debug("block [expand=]");
970
- dstack_close_before_block(sm);
971
- dstack_push(sm, &BLOCK_EXPAND);
972
- append_block(sm, "<div class=\"expandable\"><div class=\"expandable-header\">");
973
- append(sm, true, "<span>");
974
- append_segment_html_escaped(sm, sm->a1, sm->a2 - 1);
975
- append(sm, true, "</span>");
976
- append_block(sm, "<input type=\"button\" value=\"Show\" class=\"expandable-button\"/></div>");
977
- append_block(sm, "<div class=\"expandable-content\">");
978
- };
979
-
980
- '[nodtext]'i space* => {
981
- g_debug("block [nodtext]");
982
- dstack_close_before_block(sm);
983
- dstack_push(sm, &BLOCK_NODTEXT);
984
- dstack_push(sm, &BLOCK_P);
985
- g_debug("push block nodtext");
986
- g_debug("push block p");
987
- append_block(sm, "<p>");
988
- fcall nodtext;
989
- };
990
-
991
- '[table]'i => {
992
- dstack_close_before_block(sm);
993
- dstack_push(sm, &BLOCK_TABLE);
994
- append_block(sm, "<table class=\"striped\">");
995
- fcall table;
996
- };
997
-
998
- '[tn]'i => {
999
- dstack_push(sm, &BLOCK_TN);
1000
- append_block(sm, "<p class=\"tn\">");
1001
- fcall inline;
1002
- };
1003
-
1004
- list_item => {
1005
- g_debug("block list");
1006
- g_debug(" call list");
1007
- sm->list_nest = 0;
1008
- sm->list_mode = true;
1009
- append_closing_p_if(sm);
1010
- fexec sm->ts;
1011
- fcall list;
1012
- };
1013
-
1014
- '\0' => {
1015
- g_debug("block 0");
1016
- g_debug(" close dstack");
1017
- dstack_close(sm);
1018
- };
1019
-
1020
- newline{2,} => {
1021
- g_debug("block newline2");
1022
-
1023
- if (sm->header_mode) {
1024
- sm->header_mode = false;
1025
- dstack_rewind(sm);
1026
- } else if (sm->list_mode) {
1027
- dstack_close_list(sm);
1028
- } else {
1029
- dstack_close_before_block(sm);
1030
- }
1031
- };
1032
-
1033
- newline => {
1034
- g_debug("block newline");
1035
- };
1036
-
1037
- any => {
1038
- g_debug("block char: %c", fc);
1039
- fhold;
1040
-
1041
- if (g_queue_is_empty(sm->dstack) || dstack_check(sm, BLOCK_QUOTE) || dstack_check(sm, BLOCK_SPOILER) || dstack_check(sm, BLOCK_EXPAND)) {
1042
- g_debug(" push p");
1043
- g_debug(" print <p>");
1044
- dstack_push(sm, &BLOCK_P);
1045
- append_block(sm, "<p>");
1046
- }
1047
-
1048
- fcall inline;
1049
- };
1050
- *|;
1051
-
1052
- }%%
1053
-
1054
- %% write data;
1055
-
1056
- static inline void underscore_string(char * str, size_t len) {
1057
- for (size_t i=0; i<len; ++i) {
1058
- if (str[i] == ' ') {
1059
- str[i] = '_';
1060
- }
1061
- }
1062
- }
1063
-
1064
- static inline void dstack_push(StateMachine * sm, const int * element) {
1065
- g_queue_push_tail(sm->dstack, (gpointer)element);
1066
- }
1067
-
1068
- static inline int * dstack_pop(StateMachine * sm) {
1069
- return g_queue_pop_tail(sm->dstack);
1070
- }
1071
-
1072
- static inline int * dstack_peek(StateMachine * sm) {
1073
- return g_queue_peek_tail(sm->dstack);
1074
- }
1075
-
1076
- static inline bool dstack_search(StateMachine * sm, const int * element) {
1077
- return g_queue_find(sm->dstack, (gconstpointer)element);
1078
- }
1079
-
1080
- static inline bool dstack_check(StateMachine * sm, int expected_element) {
1081
- int * top = dstack_peek(sm);
1082
- return top && *top == expected_element;
1083
- }
1084
-
1085
- static inline bool dstack_check2(StateMachine * sm, int expected_element) {
1086
- int * top2 = NULL;
1087
-
1088
- if (sm->dstack->length < 2) {
1089
- return false;
1090
- }
1091
-
1092
- top2 = g_queue_peek_nth(sm->dstack, sm->dstack->length - 2);
1093
- return top2 && *top2 == expected_element;
1094
- }
1095
-
1096
- static inline void append(StateMachine * sm, bool is_markup, const char * s) {
1097
- if (!(is_markup && sm->f_strip)) {
1098
- sm->output = g_string_append(sm->output, s);
1099
- }
1100
- }
1101
-
1102
- static inline void append_c(StateMachine * sm, char s) {
1103
- sm->output = g_string_append_c(sm->output, s);
1104
- }
1105
-
1106
- static inline void append_c_html_escaped(StateMachine * sm, char s) {
1107
- switch (s) {
1108
- case '<':
1109
- sm->output = g_string_append(sm->output, "&lt;");
1110
- break;
1111
-
1112
- case '>':
1113
- sm->output = g_string_append(sm->output, "&gt;");
1114
- break;
1115
-
1116
- case '&':
1117
- sm->output = g_string_append(sm->output, "&amp;");
1118
- break;
1119
-
1120
- case '"':
1121
- sm->output = g_string_append(sm->output, "&quot;");
1122
- break;
1123
-
1124
- default:
1125
- sm->output = g_string_append_c(sm->output, s);
1126
- break;
1127
- }
1128
- }
1129
-
1130
- static inline void append_segment(StateMachine * sm, bool is_markup, const char * a, const char * b) {
1131
- if (!(is_markup && sm->f_strip)) {
1132
- sm->output = g_string_append_len(sm->output, a, b - a + 1);
1133
- }
1134
- }
1135
-
1136
- static inline void append_segment_uri_escaped(StateMachine * sm, const char * a, const char * b) {
1137
- if (sm->f_strip) {
1138
- return;
1139
- }
1140
-
1141
- char * segment1 = NULL;
1142
- char * segment2 = NULL;
1143
- GString * segment_string = g_string_new_len(a, b - a + 1);
1144
-
1145
- segment1 = g_uri_escape_string(segment_string->str, NULL, TRUE);
1146
- segment2 = g_markup_escape_text(segment1, -1);
1147
- sm->output = g_string_append(sm->output, segment2);
1148
- g_string_free(segment_string, TRUE);
1149
- g_free(segment1);
1150
- g_free(segment2);
1151
- }
1152
-
1153
- static inline void append_segment_html_escaped(StateMachine * sm, const char * a, const char * b) {
1154
- gchar * segment = g_markup_escape_text(a, b - a + 1);
1155
- sm->output = g_string_append(sm->output, segment);
1156
- g_free(segment);
1157
- }
1158
-
1159
- static inline void append_block(StateMachine * sm, const char * s) {
1160
- if (sm->f_inline) {
1161
- // sm->output = g_string_append_c(sm->output, ' ');
1162
- } else if (sm->f_strip) {
1163
- // do nothing
1164
- } else {
1165
- sm->output = g_string_append(sm->output, s);
1166
- }
1167
- }
1168
-
1169
- static void append_closing_p(StateMachine * sm) {
1170
- size_t i = sm->output->len;
1171
-
1172
- if (i > 4 && !strncmp(sm->output->str + i - 4, "<br>", 4)) {
1173
- sm->output = g_string_truncate(sm->output, sm->output->len - 4);
1174
- }
1175
-
1176
- if (i > 3 && !strncmp(sm->output->str + i - 3, "<p>", 3)) {
1177
- sm->output = g_string_truncate(sm->output, sm->output->len - 3);
1178
- return;
1179
- }
1180
-
1181
- append_block(sm, "</p>");
1182
- }
1183
-
1184
- static void append_closing_p_if(StateMachine * sm) {
1185
- if (!dstack_check(sm, BLOCK_P)) {
1186
- return;
1187
- }
1188
-
1189
- dstack_pop(sm);
1190
- append_closing_p(sm);
1191
- }
1192
-
1193
- static void dstack_rewind(StateMachine * sm) {
1194
- int * element = dstack_pop(sm);
1195
-
1196
- if (element == NULL) {
1197
- return;
1198
- }
1199
-
1200
- if (*element == BLOCK_P) {
1201
- append_closing_p(sm);
1202
-
1203
- } else if (*element == INLINE_SPOILER) {
1204
- append(sm, true, "</span>");
1205
-
1206
- } else if (*element == BLOCK_SPOILER) {
1207
- append_block(sm, "</div>");
1208
-
1209
- } else if (*element == BLOCK_QUOTE) {
1210
- append_block(sm, "</blockquote>");
1211
-
1212
- } else if (*element == BLOCK_EXPAND) {
1213
- append_block(sm, "</div></div>");
1214
-
1215
- } else if (*element == BLOCK_NODTEXT) {
1216
- append_closing_p(sm);
1217
-
1218
- } else if (*element == BLOCK_CODE) {
1219
- append_block(sm, "</pre>");
1220
-
1221
- } else if (*element == BLOCK_TD) {
1222
- append_block(sm, "</td>");
1223
-
1224
- } else if (*element == INLINE_NODTEXT) {
1225
-
1226
- } else if (*element == INLINE_B) {
1227
- append(sm, true, "</strong>");
1228
-
1229
- } else if (*element == INLINE_I) {
1230
- append(sm, true, "</em>");
1231
-
1232
- } else if (*element == INLINE_U) {
1233
- append(sm, true, "</u>");
1234
-
1235
- } else if (*element == INLINE_S) {
1236
- append(sm, true, "</s>");
1237
-
1238
- } else if (*element == INLINE_TN) {
1239
- append(sm, true, "</span>");
1240
-
1241
- } else if (*element == BLOCK_TN) {
1242
- append_closing_p(sm);
1243
-
1244
- } else if (*element == BLOCK_TABLE) {
1245
- append_block(sm, "</table>");
1246
-
1247
- } else if (*element == BLOCK_THEAD) {
1248
- append_block(sm, "</thead>");
1249
-
1250
- } else if (*element == BLOCK_TBODY) {
1251
- append_block(sm, "</tbody>");
1252
-
1253
- } else if (*element == BLOCK_TR) {
1254
- append_block(sm, "</tr>");
1255
-
1256
- } else if (*element == BLOCK_UL) {
1257
- append_block(sm, "</ul>");
1258
-
1259
- } else if (*element == BLOCK_LI) {
1260
- append_block(sm, "</li>");
1261
-
1262
- } else if (*element == BLOCK_H6) {
1263
- append_block(sm, "</h6>");
1264
-
1265
- } else if (*element == BLOCK_H5) {
1266
- append_block(sm, "</h5>");
1267
-
1268
- } else if (*element == BLOCK_H4) {
1269
- append_block(sm, "</h4>");
1270
-
1271
- } else if (*element == BLOCK_H3) {
1272
- append_block(sm, "</h3>");
1273
-
1274
- } else if (*element == BLOCK_H2) {
1275
- append_block(sm, "</h2>");
1276
-
1277
- } else if (*element == BLOCK_H1) {
1278
- append_block(sm, "</h1>");
1279
- }
1280
- }
1281
-
1282
- static void dstack_close_before_block(StateMachine * sm) {
1283
- while (1) {
1284
- if (dstack_check(sm, BLOCK_P)) {
1285
- dstack_pop(sm);
1286
- append_closing_p(sm);
1287
- } else if (dstack_check(sm, BLOCK_LI) || dstack_check(sm, BLOCK_UL)) {
1288
- dstack_rewind(sm);
1289
- } else {
1290
- return;
1291
- }
1292
- }
1293
- }
1294
-
1295
- static void dstack_close(StateMachine * sm) {
1296
- while (dstack_peek(sm) != NULL) {
1297
- dstack_rewind(sm);
1298
- }
1299
- }
1300
-
1301
- static void dstack_close_list(StateMachine * sm) {
1302
- while (dstack_check(sm, BLOCK_LI) || dstack_check(sm, BLOCK_UL)) {
1303
- dstack_rewind(sm);
1304
- }
1305
-
1306
- sm->list_mode = false;
1307
- sm->list_nest = 0;
1308
- }
1309
-
1310
- static inline bool is_boundary_c(char c) {
1311
- switch (c) {
1312
- case ':':
1313
- case ';':
1314
- case '.':
1315
- case ',':
1316
- case '!':
1317
- case '?':
1318
- case ')':
1319
- case ']':
1320
- case '<':
1321
- case '>':
1322
- return true;
1323
- }
1324
-
1325
- return false;
1326
- }
1327
-
1328
- static bool print_machine(StateMachine * sm) {
1329
- printf("p=%c\n", *sm->p);
1330
- return true;
1331
- }
1332
-
1333
- static void init_machine(StateMachine * sm, const char * src, size_t len) {
1334
- size_t output_length = 0;
1335
- sm->p = src;
1336
- sm->pb = sm->p;
1337
- sm->pe = sm->p + len;
1338
- sm->eof = sm->pe;
1339
- sm->ts = NULL;
1340
- sm->te = NULL;
1341
- sm->cs = 0;
1342
- sm->act = 0;
1343
- sm->top = 0;
1344
- output_length = len;
1345
- if (output_length < (INT16_MAX / 2)) {
1346
- output_length *= 2;
1347
- }
1348
- sm->output = g_string_sized_new(output_length);
1349
- sm->a1 = NULL;
1350
- sm->a2 = NULL;
1351
- sm->b1 = NULL;
1352
- sm->b2 = NULL;
1353
- sm->f_inline = false;
1354
- sm->f_strip = false;
1355
- sm->f_mentions = true;
1356
- sm->stack = g_array_sized_new(FALSE, TRUE, sizeof(int), 16);
1357
- sm->dstack = g_queue_new();
1358
- sm->list_nest = 0;
1359
- sm->list_mode = false;
1360
- sm->header_mode = false;
1361
- sm->d = 0;
1362
- sm->b = 0;
1363
- sm->quote = 0;
1364
- }
1365
-
1366
- static void free_machine(StateMachine * sm) {
1367
- g_string_free(sm->output, TRUE);
1368
- g_array_free(sm->stack, FALSE);
1369
- g_queue_free(sm->dstack);
1370
- g_free(sm);
1371
- }
1372
-
1373
- static StateMachine * parse_helper(const char * src, size_t len, bool f_strip, bool f_inline, bool f_mentions) {
1374
- StateMachine * sm = NULL;
1375
- StateMachine * link_content_sm = NULL;
1376
-
1377
- sm = (StateMachine *)g_malloc0(sizeof(StateMachine));
1378
- init_machine(sm, src, len);
1379
- sm->f_strip = f_strip;
1380
- sm->f_inline = f_inline;
1381
- sm->f_mentions = f_mentions;
1382
-
1383
- %% write init;
1384
- %% write exec;
1385
-
1386
- dstack_close(sm);
1387
-
1388
- return sm;
1389
- }
1390
-
1391
- static VALUE parse(int argc, VALUE * argv, VALUE self) {
1392
- VALUE input;
1393
- VALUE input0;
1394
- VALUE options;
1395
- VALUE opt_inline;
1396
- VALUE opt_strip;
1397
- VALUE opt_mentions;
1398
- VALUE ret;
1399
- rb_encoding * encoding = NULL;
1400
- StateMachine * sm = NULL;
1401
- bool f_strip = false;
1402
- bool f_inline = false;
1403
- bool f_mentions = true;
1404
-
1405
- g_debug("start\n");
1406
-
1407
- if (argc == 0) {
1408
- rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)");
1409
- }
1410
-
1411
- input = argv[0];
1412
-
1413
- if (NIL_P(input)) {
1414
- return Qnil;
1415
- }
1416
-
1417
- input0 = rb_str_dup(input);
1418
- input0 = rb_str_cat(input0, "\0", 1);
1419
-
1420
- if (argc > 1) {
1421
- options = argv[1];
1422
-
1423
- if (!NIL_P(options)) {
1424
- opt_strip = rb_hash_aref(options, ID2SYM(rb_intern("strip")));
1425
- if (RTEST(opt_strip)) {
1426
- f_strip = true;
1427
- }
1428
-
1429
- opt_inline = rb_hash_aref(options, ID2SYM(rb_intern("inline")));
1430
- if (RTEST(opt_inline)) {
1431
- f_inline = true;
1432
- }
1433
-
1434
- opt_mentions = rb_hash_aref(options, ID2SYM(rb_intern("disable_mentions")));
1435
- if (RTEST(opt_mentions)) {
1436
- f_mentions = false;
1437
- }
1438
- }
1439
- }
1440
-
1441
- sm = parse_helper(RSTRING_PTR(input0), RSTRING_LEN(input0), f_strip, f_inline, f_mentions);
1442
-
1443
- encoding = rb_enc_find("utf-8");
1444
- ret = rb_enc_str_new(sm->output->str, sm->output->len, encoding);
1445
-
1446
- free_machine(sm);
1447
-
1448
- return ret;
1449
- }
1450
-
1451
- void Init_dtext() {
1452
- VALUE mDTextRagel = rb_define_module("DTextRagel");
1453
- rb_define_singleton_method(mDTextRagel, "parse", parse, -1);
1454
- }