ext/greenmat/gm_render.c in greenmat-3.2.2.4 vs ext/greenmat/gm_render.c in greenmat-3.5.1.0

- old
+ new

@@ -1,19 +1,25 @@ /* - * Copyright (c) 2011, Vicent Marti + * Copyright (c) 2015, Vicent Marti * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. */ #include "greenmat.h" #define SPAN_CALLBACK(method_name, ...) {\ @@ -32,14 +38,14 @@ Check_Type(ret, T_STRING);\ bufput(ob, RSTRING_PTR(ret), RSTRING_LEN(ret));\ } extern VALUE rb_mGreenmat; +extern VALUE rb_cRenderHTML_TOC; VALUE rb_mRender; VALUE rb_cRenderBase; VALUE rb_cRenderHTML; -VALUE rb_cRenderHTML_TOC; VALUE rb_mSmartyPants; #define buf2str(t) ((t) ? rb_enc_str_new((const char*)(t)->data, (t)->size, opt->active_enc) : Qnil) static void @@ -367,20 +373,26 @@ { if (rndr->options.link_attributes) rb_gc_mark(rndr->options.link_attributes); } +static void rndr_deallocate(void *rndr) +{ + xfree(rndr); +} + static VALUE rb_greenmat_rbase_alloc(VALUE klass) { struct rb_greenmat_rndr *rndr = ALLOC(struct rb_greenmat_rndr); memset(rndr, 0x0, sizeof(struct rb_greenmat_rndr)); - return Data_Wrap_Struct(klass, rb_greenmat_rbase_mark, NULL, rndr); + return Data_Wrap_Struct(klass, rb_greenmat_rbase_mark, rndr_deallocate, rndr); } static void rb_greenmat__overload(VALUE self, VALUE base_class) { struct rb_greenmat_rndr *rndr; + VALUE options_ivar; Data_Get_Struct(self, struct rb_greenmat_rndr, rndr); rndr->options.self = self; rndr->options.base_class = base_class; @@ -397,10 +409,14 @@ for (i = 0; i < rb_greenmat_method_count; ++i) { if (rb_respond_to(self, rb_intern(rb_greenmat_method_names[i]))) dest[i] = source[i]; } } + + options_ivar = rb_attr_get(self, rb_intern("@options")); + if (options_ivar == Qundef || options_ivar == Qnil) + rb_iv_set(self, "@options", rb_hash_new()); } static VALUE rb_greenmat_rbase_init(VALUE self) { rb_greenmat__overload(self, rb_cRenderBase); @@ -416,10 +432,13 @@ Data_Get_Struct(self, struct rb_greenmat_rndr, rndr); if (rb_scan_args(argc, argv, "01", &hash) == 1) { Check_Type(hash, T_HASH); + /* Give access to the passed options through `@options` */ + rb_iv_set(self, "@options", hash); + /* escape_html */ if (rb_hash_aref(hash, CSTR2SYM("escape_html")) == Qtrue) render_flags |= HTML_ESCAPE; /* filter_html */ @@ -470,27 +489,47 @@ } static VALUE rb_greenmat_htmltoc_init(int argc, VALUE *argv, VALUE self) { struct rb_greenmat_rndr *rndr; - int nesting_level = 6; - VALUE hash, key = Qnil; + unsigned int render_flags = HTML_TOC; + VALUE hash, nesting_level = Qnil; Data_Get_Struct(self, struct rb_greenmat_rndr, rndr); if (rb_scan_args(argc, argv, "01", &hash) == 1) { Check_Type(hash, T_HASH); - key = CSTR2SYM("nesting_level"); + /* Give access to the passed options through `@options` */ + rb_iv_set(self, "@options", hash); - if (RTEST(rb_hash_aref(hash, key))) { - Check_Type(rb_hash_aref(hash, key), T_FIXNUM); - nesting_level = NUM2INT(rb_hash_aref(hash, key)); - } + /* escape_html */ + if (rb_hash_aref(hash, CSTR2SYM("escape_html")) == Qtrue) + render_flags |= HTML_ESCAPE; + + /* Nesting level */ + nesting_level = rb_hash_aref(hash, CSTR2SYM("nesting_level")); } - sdhtml_toc_renderer(&rndr->callbacks, (struct html_renderopt *)&rndr->options.html, nesting_level); + sdhtml_toc_renderer(&rndr->callbacks, (struct html_renderopt *)&rndr->options.html, render_flags); rb_greenmat__overload(self, rb_cRenderHTML_TOC); + + /* Check whether we are dealing with a Range object by + checking whether the object responds to min and max */ + if (rb_respond_to(nesting_level, rb_intern("min")) && + rb_respond_to(nesting_level, rb_intern("max"))) { + int min = NUM2INT(rb_funcall(nesting_level, rb_intern("min"), 0)); + int max = NUM2INT(rb_funcall(nesting_level, rb_intern("max"), 0)); + + rndr->options.html.toc_data.nesting_bounds[0] = min; + rndr->options.html.toc_data.nesting_bounds[1] = max; + } else if (FIXNUM_P(nesting_level)) { + rndr->options.html.toc_data.nesting_bounds[0] = 1; + rndr->options.html.toc_data.nesting_bounds[1] = NUM2INT(nesting_level); + } else { + rndr->options.html.toc_data.nesting_bounds[0] = 1; + rndr->options.html.toc_data.nesting_bounds[1] = 6; + } return Qnil; } static VALUE rb_greenmat_smartypants_render(VALUE self, VALUE text)