]> git.wincent.com - wikitext.git/blob - ext/wikitext.c
Teach wiki_append_sanitized_link_target to take a str_t
[wikitext.git] / ext / wikitext.c
1 // Copyright 2008-2009 Wincent Colaiuta. All rights reserved.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are met:
5 //
6 // 1. Redistributions of source code must retain the above copyright notice,
7 //    this list of conditions and the following disclaimer.
8 // 2. Redistributions in binary form must reproduce the above copyright notice,
9 //    this list of conditions and the following disclaimer in the documentation
10 //    and/or other materials provided with the distribution.
11 //
12 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
13 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
16 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
17 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
18 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
19 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
20 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
21 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
22 // POSSIBILITY OF SUCH DAMAGE.
23
24 #include "wikitext_ragel.h"
25 #include "parser.h"
26
27 VALUE mWikitext              = 0;   // module Wikitext
28 VALUE cWikitextParser        = 0;   // class Wikitext::Parser
29 VALUE eWikitextParserError   = 0;   // class Wikitext::Parser::Error
30 VALUE cWikitextParserToken   = 0;   // class Wikitext::Parser::Token
31
32 // In order to replicate this Ruby code:
33 //
34 //   ActiveSupport.on_load(:action_view) do
35 //     require 'wikitext/rails_template_handler'
36 //   end
37 //
38 // here in C we have to jump through some hoops using the following two
39 // functions.
40 //
41 // First we have wikitext_on_load_block(), which is a function which defines
42 // the "block" of code that we want to have evaluated.
43 //
44 // To actually pass this block in to the ActiveSupport::on_load method we
45 // need the help of an intermediate helper function,
46 // wikitext_block_forwarder(), which we invoke with the aid of rb_iterate()
47 // later on.
48 //
49 // This works because the rb_funcall() function in wikitext_block_forwarder()
50 // propagates the block through to the called method.
51 VALUE wikitext_on_load_block(VALUE yielded, VALUE other)
52 {
53     return rb_require("wikitext/rails_template_handler");
54 }
55
56 VALUE wikitext_block_forwarder(VALUE receiver)
57 {
58     return rb_funcall(receiver, rb_intern("on_load"), 1,
59         ID2SYM(rb_intern("action_view")));
60 }
61
62 void Init_wikitext()
63 {
64     // Wikitext
65     mWikitext = rb_define_module("Wikitext");
66
67     // Wikitext::Parser
68     cWikitextParser = rb_define_class_under(mWikitext, "Parser", rb_cObject);
69     rb_define_method(cWikitextParser, "initialize", Wikitext_parser_initialize, -1);
70     rb_define_method(cWikitextParser, "parse", Wikitext_parser_parse, -1);
71     rb_define_method(cWikitextParser, "profiling_parse", Wikitext_parser_profiling_parse, 1);
72     rb_define_method(cWikitextParser, "tokenize", Wikitext_parser_tokenize, 1);
73     rb_define_method(cWikitextParser, "benchmarking_tokenize", Wikitext_parser_benchmarking_tokenize, 1);
74     rb_define_method(cWikitextParser, "fulltext_tokenize", Wikitext_parser_fulltext_tokenize, -1);
75     rb_define_singleton_method(cWikitextParser, "sanitize_link_target", Wikitext_parser_sanitize_link_target, 1);
76     rb_define_singleton_method(cWikitextParser, "encode_link_target", Wikitext_parser_encode_link_target, 1);
77     rb_define_attr(cWikitextParser, "line_ending", Qtrue, Qtrue);
78     rb_define_attr(cWikitextParser, "internal_link_prefix", Qtrue, Qtrue);
79     rb_define_attr(cWikitextParser, "img_prefix", Qtrue, Qtrue);
80     rb_define_attr(cWikitextParser, "external_link_class", Qtrue, Qtrue);
81     rb_define_attr(cWikitextParser, "external_link_rel", Qtrue, Qtrue);
82     rb_define_attr(cWikitextParser, "mailto_class", Qtrue, Qtrue);
83     rb_define_attr(cWikitextParser, "autolink", Qtrue, Qtrue);
84     rb_define_attr(cWikitextParser, "space_to_underscore", Qtrue, Qtrue);
85     rb_define_attr(cWikitextParser, "minimum_fulltext_token_length", Qtrue, Qtrue);
86     rb_define_attr(cWikitextParser, "base_heading_level", Qtrue, Qtrue);
87     rb_define_attr(cWikitextParser, "output_style", Qtrue, Qtrue);
88
89     // Wikitext::Parser::Error
90     eWikitextParserError = rb_define_class_under(cWikitextParser, "Error", rb_eException);
91
92     // Wikitext::Parser::Token
93     cWikitextParserToken = rb_define_class_under(cWikitextParser, "Token", rb_cObject);
94     rb_define_singleton_method(cWikitextParserToken, "types", Wikitext_parser_token_types, 0);
95     rb_define_attr(cWikitextParserToken, "start", Qtrue, Qfalse);
96     rb_define_attr(cWikitextParserToken, "stop", Qtrue, Qfalse);
97     rb_define_attr(cWikitextParserToken, "line_start", Qtrue, Qfalse);
98     rb_define_attr(cWikitextParserToken, "line_stop", Qtrue, Qfalse);
99     rb_define_attr(cWikitextParserToken, "column_start", Qtrue, Qfalse);
100     rb_define_attr(cWikitextParserToken, "column_stop", Qtrue, Qfalse);
101     rb_define_attr(cWikitextParserToken, "code_point", Qtrue, Qfalse);
102     rb_define_attr(cWikitextParserToken, "token_type", Qtrue, Qfalse);
103     rb_define_attr(cWikitextParserToken, "string_value", Qtrue, Qfalse);
104
105     // check to see if ::ActiveSupport is defined
106     if (rb_funcall(rb_cObject, rb_intern("const_defined?"), 1,
107         ID2SYM(rb_intern("ActiveSupport"))) == Qtrue)
108     {
109         // we are running under Rails
110         rb_require("wikitext/nil_class");
111         rb_require("wikitext/string");
112
113         // now check for Rails version
114         VALUE active_support = rb_const_get(rb_cObject,
115             rb_intern("ActiveSupport"));
116         if (rb_respond_to(active_support, rb_intern("on_load")))
117             // running under Rails 3
118             rb_iterate(wikitext_block_forwarder, active_support,
119                 wikitext_on_load_block, Qnil);
120         else
121             // running under Rails 2
122             rb_require("wikitext/rails_template_handler");
123     }
124 }