ragel/redcloth_inline.c.rl
/*
* redcloth_inline.c.rl
*
* Copyright (C) 2009 Jason Garber
*/
#define RSTRING_NOT_MODIFIED
#include <ruby.h>
#include "redcloth.h"
%%{
machine redcloth_inline;
include redcloth_common "redcloth_common.c.rl";
include redcloth_inline "redcloth_inline.rl";
}%%
%% write data nofinal;
VALUE
red_pass(VALUE self, VALUE regs, VALUE ref, ID meth, VALUE refs)
{
VALUE txt = rb_hash_aref(regs, ref);
if (!NIL_P(txt)) rb_hash_aset(regs, ref, redcloth_inline2(self, txt, refs));
return rb_funcall(self, meth, 1, regs);
}
VALUE
red_parse_attr(VALUE self, VALUE regs, VALUE ref)
{
VALUE txt = rb_hash_aref(regs, ref);
VALUE new_regs = redcloth_attributes(self, txt);
return rb_funcall(regs, rb_intern("merge!"), 1, new_regs);
}
VALUE
red_parse_link_attr(VALUE self, VALUE regs, VALUE ref)
{
VALUE txt = rb_hash_aref(regs, ref);
VALUE new_regs = red_parse_title(self, redcloth_link_attributes(self, txt), ref);
return rb_funcall(regs, rb_intern("merge!"), 1, new_regs);
}
VALUE
red_parse_image_attr(VALUE self, VALUE regs, VALUE ref)
{
return red_parse_title(self, regs, ref);
}
VALUE
red_parse_title(VALUE self, VALUE regs, VALUE ref)
{
// Store title/alt
VALUE txt = rb_hash_aref(regs, ref);
if ( txt != Qnil ) {
char *p = RSTRING_PTR(txt) + RSTRING_LEN(txt);
if (*(p - 1) == ')') {
signed char level = -1;
p--;
while (p > RSTRING_PTR(txt) && level < 0) {
switch(*(p - 1)) {
case '(': ++level; break;
case ')': --level; break;
}
--p;
}
VALUE title = STR_NEW(p + 1, RSTRING_PTR(txt) + RSTRING_LEN(txt) - 2 - p );
if (p > RSTRING_PTR(txt) && *(p - 1) == ' ') --p;
if (p != RSTRING_PTR(txt)) {
rb_hash_aset(regs, ref, STR_NEW(RSTRING_PTR(txt), p - RSTRING_PTR(txt) ));
rb_hash_aset(regs, ID2SYM(rb_intern("title")), title);
}
}
}
return regs;
}
VALUE
red_pass_code(VALUE self, VALUE regs, VALUE ref, ID meth)
{
VALUE txt = rb_hash_aref(regs, ref);
if (!NIL_P(txt)) {
VALUE txt2 = STR_NEW2("");
rb_str_cat_escaped_for_preformatted(self, txt2, RSTRING_PTR(txt), RSTRING_PTR(txt) + RSTRING_LEN(txt));
rb_hash_aset(regs, ref, txt2);
}
return rb_funcall(self, meth, 1, regs);
}
VALUE
red_block(VALUE self, VALUE regs, VALUE block, VALUE refs)
{
ID method;
VALUE fallback;
VALUE sym_text = ID2SYM(rb_intern("text"));
VALUE btype = rb_hash_aref(regs, ID2SYM(rb_intern("type")));
block = rb_funcall(block, rb_intern("strip"), 0);
VALUE attr_regs = rb_hash_new();
if ((!NIL_P(block)) && !NIL_P(btype))
{
method = rb_str_intern(btype);
if (method == ID2SYM(rb_intern("notextile"))) {
rb_hash_aset(regs, sym_text, block);
} else {
rb_hash_aset(regs, sym_text, redcloth_inline2(self, block, refs));
}
if (rb_ary_includes(rb_funcall(self, rb_intern("formatter_methods"), 0), method)) {
block = rb_funcall(self, SYM2ID(method), 1, regs);
} else {
fallback = rb_hash_aref(regs, ID2SYM(rb_intern("fallback")));
if (!NIL_P(fallback)) {
rb_str_append(fallback, rb_hash_aref(regs, sym_text));
CLEAR_REGS();
rb_hash_aset(regs, sym_text, fallback);
}
block = rb_funcall(self, rb_intern("p"), 1, regs);
}
}
return block;
}
VALUE
red_blockcode(VALUE self, VALUE regs, VALUE block)
{
VALUE btype = rb_hash_aref(regs, ID2SYM(rb_intern("type")));
if (RSTRING_LEN(block) > 0)
{
rb_hash_aset(regs, ID2SYM(rb_intern("text")), block);
block = rb_funcall(self, rb_intern(RSTRING_PTR(btype)), 1, regs);
}
return block;
}
void
red_inc(VALUE regs, VALUE ref)
{
int aint = 0;
VALUE aval = rb_hash_aref(regs, ref);
if (aval != Qnil) aint = NUM2INT(aval);
rb_hash_aset(regs, ref, INT2NUM(aint + 1));
}
VALUE
redcloth_inline(self, p, pe, refs)
VALUE self;
char *p, *pe;
VALUE refs;
{
int cs, act;
char *ts = NULL, *te = NULL, *reg = NULL, *attr_reg = NULL, *eof = NULL;
char *orig_p = p;
VALUE block = STR_NEW2("");
VALUE regs = Qnil;
VALUE attr_regs = Qnil;
%% write init;
%% write exec;
return block;
}
/** Append characters to a string, escaping (&, <, >, ", ') using the formatter's escape method.
* @param str ruby string
* @param ts start of character buffer to append
* @param te end of character buffer
*/
void
rb_str_cat_escaped(self, str, ts, te)
VALUE self, str;
char *ts, *te;
{
VALUE source_str = STR_NEW(ts, te-ts);
VALUE escaped_str = rb_funcall(self, rb_intern("escape"), 1, source_str);
rb_str_concat(str, escaped_str);
}
void
rb_str_cat_escaped_for_preformatted(self, str, ts, te)
VALUE self, str;
char *ts, *te;
{
VALUE source_str = STR_NEW(ts, te-ts);
VALUE escaped_str = rb_funcall(self, rb_intern("escape_pre"), 1, source_str);
rb_str_concat(str, escaped_str);
}
VALUE
redcloth_inline2(self, str, refs)
VALUE self, str, refs;
{
StringValue(str);
return redcloth_inline(self, RSTRING_PTR(str), RSTRING_PTR(str) + RSTRING_LEN(str) + 1, refs);
}