mirror of
https://github.com/Orc/discount.git
synced 2026-09-25 04:10:00 +03:00
Rework all of linkylinky() to make it a little bit less of a huge
monster bodge. It's no shorter, but it's a little bit clearer, I hope, and now I can revisit it and rework the whole link name gathering scheme if need be.
This commit is contained in:
@@ -26,9 +26,9 @@ Csprintf(Cstring *iot, char *fmt, ...)
|
||||
do {
|
||||
RESERVE(*iot, siz);
|
||||
va_start(ptr, fmt);
|
||||
siz = vsnprintf(T(*iot)+S(*iot), ALL(*iot)-S(*iot), fmt, ptr);
|
||||
siz = vsnprintf(T(*iot)+S(*iot), ALLOCATED(*iot)-S(*iot), fmt, ptr);
|
||||
va_end(ptr);
|
||||
} while ( siz > (ALL(*iot)-S(*iot)) );
|
||||
} while ( siz > (ALLOCATED(*iot)-S(*iot)) );
|
||||
|
||||
S(*iot) += siz;
|
||||
return siz;
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
: (T(x) = T(x) ? realloc(T(x), sizeof T(x)[0] * ((x).alloc += 100)) \
|
||||
: malloc(sizeof T(x)[0] * ((x).alloc += 100)) )]
|
||||
|
||||
#define DELETE(x) (x).alloc ? (free(T(x)), S(x) = (x).alloc = 0) \
|
||||
: ( S(x) = 0 )
|
||||
#define DELETE(x) ALLOCATED(x) ? (free(T(x)), S(x) = (x).alloc = 0) \
|
||||
: ( S(x) = 0 )
|
||||
#define CLIP(t,i,sz) \
|
||||
( ((i) >= 0) && ((sz) > 0) && (((i)+(sz)) <= S(t)) ) ? \
|
||||
(memmove(&T(t)[i], &T(t)[i+sz], (S(t)-(i+sz)+1)*sizeof(T(t)[0])), \
|
||||
@@ -50,7 +50,7 @@
|
||||
*/
|
||||
#define T(x) (x).text
|
||||
#define S(x) (x).size
|
||||
#define ALL(x) (x).alloc
|
||||
#define ALLOCATED(x) (x).alloc
|
||||
|
||||
/* abstract anchor type that defines a list base
|
||||
* with a function that attaches an element to
|
||||
|
||||
+145
-153
@@ -370,19 +370,23 @@ parenthetical(int in, int out, MMIOT *f)
|
||||
else if ( c == out )
|
||||
--indent;
|
||||
}
|
||||
return size-1;
|
||||
return size ? (size-1) : 0;
|
||||
}
|
||||
|
||||
|
||||
/* extract a []-delimited label from the input stream.
|
||||
*/
|
||||
static char *
|
||||
linkylabel(MMIOT *f, int *sizep)
|
||||
static int
|
||||
linkylabel(MMIOT *f, Cstring *res)
|
||||
{
|
||||
char *ptr = cursor(f);
|
||||
int size;
|
||||
|
||||
if ( (*sizep = parenthetical('[',']',f)) != EOF )
|
||||
return ptr;
|
||||
if ( (size = parenthetical('[',']',f)) != EOF ) {
|
||||
T(*res) = ptr;
|
||||
S(*res) = size;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -390,23 +394,20 @@ linkylabel(MMIOT *f, int *sizep)
|
||||
/* extract a (-prefixed url from the input stream.
|
||||
* the label is either of the format `<link>`, where I
|
||||
* extract until I find a >, or it is of the format
|
||||
* `text`, where I extract until I reach a ')' or
|
||||
* whitespace.
|
||||
* `text`, where I extract until I reach a ')', a quote,
|
||||
* or (if image) a '='
|
||||
*/
|
||||
static int
|
||||
linkyurl(MMIOT *f, Footnote *p, char *fin)
|
||||
linkyurl(MMIOT *f, int image, Footnote *p)
|
||||
{
|
||||
int size = 0;
|
||||
char *ptr;
|
||||
int c;
|
||||
char *stopper = image ? "='\")" : "'\")";
|
||||
|
||||
if ( (c = eatspace(f)) == EOF )
|
||||
return 0;
|
||||
|
||||
p->dealloc = 1;
|
||||
CREATE(p->link);
|
||||
RESERVE(p->link,50);
|
||||
|
||||
if ( c == '<' ) {
|
||||
pull(f);
|
||||
ptr = cursor(f);
|
||||
@@ -418,9 +419,9 @@ linkyurl(MMIOT *f, Footnote *p, char *fin)
|
||||
while (1) {
|
||||
if ( (c = peek(f,1)) == EOF )
|
||||
return 0;
|
||||
else if ( strchr(fin, c) )
|
||||
else if ( strchr(stopper, c) )
|
||||
break;
|
||||
else if ( (c == '\\') && strchr(fin, peek(f,2)) )
|
||||
else if ( (c == '\\') && strchr(stopper, peek(f,2)) )
|
||||
pull(f);
|
||||
EXPAND(p->link) = pull(f);
|
||||
}
|
||||
@@ -433,14 +434,14 @@ linkyurl(MMIOT *f, Footnote *p, char *fin)
|
||||
/* extract a =HHHxWWW size from the input stream
|
||||
*/
|
||||
static int
|
||||
linkysize(MMIOT *f, int *heightp, int *widthp)
|
||||
linkysize(MMIOT *f, int image, Footnote *ref)
|
||||
{
|
||||
int height=0, width=0;
|
||||
int c;
|
||||
|
||||
*heightp = 0;
|
||||
*widthp = 0;
|
||||
|
||||
if ( !image )
|
||||
return 1;
|
||||
|
||||
if ( (c = eatspace(f)) != '=' )
|
||||
return (c != EOF);
|
||||
pull(f); /* eat '=' */
|
||||
@@ -454,8 +455,8 @@ linkysize(MMIOT *f, int *heightp, int *widthp)
|
||||
|
||||
if ( c != EOF ) {
|
||||
if ( !isspace(c) ) shift(f, -1);
|
||||
*heightp = height;
|
||||
*widthp = width;
|
||||
ref->height = height;
|
||||
ref->width = width;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -465,96 +466,33 @@ linkysize(MMIOT *f, int *heightp, int *widthp)
|
||||
|
||||
/* extract a )-terminated title from the input stream.
|
||||
*/
|
||||
static char*
|
||||
linkytitle(MMIOT *f, int *sizep)
|
||||
{
|
||||
int countq=0, qc, c, size;
|
||||
char *ret, *lastqc = 0;
|
||||
|
||||
eatspace(f);
|
||||
if ( (qc=pull(f)) != '"' && qc != '\'' && qc != '(' )
|
||||
return 0;
|
||||
|
||||
if ( qc == '(' ) qc = ')';
|
||||
|
||||
for ( ret = cursor(f); (c = pull(f)) != EOF; ) {
|
||||
if ( (c == ')') && countq ) {
|
||||
size = (lastqc ? lastqc : cursor(f)) - ret;
|
||||
*sizep = size-1;
|
||||
return ret;
|
||||
}
|
||||
else if ( c == qc ) {
|
||||
lastqc = cursor(f);
|
||||
countq++;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* look up (or construct) a footnote from the [xxx] link
|
||||
* at the head of the stream.
|
||||
*/
|
||||
static int
|
||||
linkykey(int image, Footnote *val, MMIOT *f)
|
||||
linkytitle(MMIOT *f, Footnote *ref)
|
||||
{
|
||||
Footnote *ret;
|
||||
Cstring mylabel;
|
||||
int here;
|
||||
int countq=0, qc, c;
|
||||
char *title, *lastqc = 0;
|
||||
|
||||
memset(val, 0, sizeof *val);
|
||||
|
||||
if ( (T(val->tag) = linkylabel(f, &S(val->tag))) == 0 )
|
||||
if ( (qc = eatspace(f)) == '"' || qc == '\'' ) {
|
||||
pull(f);
|
||||
title = cursor(f);
|
||||
while ( (c = peek(f,1)) != EOF ) {
|
||||
if ( (c == ')') && countq ) {
|
||||
S(ref->title) = (lastqc - title);
|
||||
T(ref->title) = title;
|
||||
return 1;
|
||||
}
|
||||
else if ( c == qc ) {
|
||||
lastqc = cursor(f);
|
||||
countq++;
|
||||
}
|
||||
pull(f);
|
||||
}
|
||||
return 0;
|
||||
|
||||
here = mmiottell(f);
|
||||
eatspace(f);
|
||||
switch ( pull(f) ) {
|
||||
case '(':
|
||||
/* embedded link */
|
||||
if ( !linkyurl(f, val, image ? "='\")" : "'\")") )
|
||||
return 0;
|
||||
|
||||
if ( image && !linkysize(f, &val->height, &val->width) )
|
||||
return 0;
|
||||
|
||||
T(val->title) = linkytitle(f, &S(val->title));
|
||||
|
||||
return peek(f,0) == ')';
|
||||
|
||||
case '[': /* footnote links /as defined in the standard/ */
|
||||
default: /* footnote links -- undocumented extension */
|
||||
/* footnote link */
|
||||
mylabel = val->tag;
|
||||
if ( peek(f,0) == '[' ) {
|
||||
if ( (T(val->tag) = linkylabel(f, &S(val->tag))) == 0 )
|
||||
return 0;
|
||||
|
||||
if ( !S(val->tag) )
|
||||
val->tag = mylabel;
|
||||
}
|
||||
else if ( f->flags & MKD_1_COMPAT )
|
||||
break;
|
||||
else
|
||||
mmiotseek(f,here);
|
||||
|
||||
ret = bsearch(val, T(*f->footnotes), S(*f->footnotes),
|
||||
sizeof *val, (stfu)__mkd_footsort);
|
||||
|
||||
if ( ret ) {
|
||||
val->tag = mylabel;
|
||||
val->link = ret->link;
|
||||
val->title = ret->title;
|
||||
val->height = ret->height;
|
||||
val->width = ret->width;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* prefixes for <automatic links>
|
||||
*/
|
||||
static struct {
|
||||
@@ -570,6 +508,7 @@ static struct {
|
||||
};
|
||||
#define NRPROTOCOLS (sizeof protocol / sizeof protocol[0])
|
||||
|
||||
|
||||
static int
|
||||
isautoprefix(char *text)
|
||||
{
|
||||
@@ -623,7 +562,7 @@ static linkytype specials[] = {
|
||||
/* see if t contains one of our pseudo-protocols.
|
||||
*/
|
||||
static linkytype *
|
||||
extratag(Cstring t)
|
||||
pseudo(Cstring t)
|
||||
{
|
||||
int i;
|
||||
linkytype *r;
|
||||
@@ -637,6 +576,64 @@ extratag(Cstring t)
|
||||
}
|
||||
|
||||
|
||||
/* print out a linky (or fail if it's Not Allowed)
|
||||
*/
|
||||
static int
|
||||
linkyformat(MMIOT *f, Cstring text, int image, Footnote *ref)
|
||||
{
|
||||
linkytype *tag;
|
||||
|
||||
if ( image )
|
||||
tag = &imaget;
|
||||
else if ( (f->flags & NO_PSEUDO_PROTO) || (tag = pseudo(ref->link)) == 0 ) {
|
||||
/* if SAFELINK, only accept links that are local or
|
||||
* a well-known protocol
|
||||
*/
|
||||
if ( (f->flags & SAFELINK) && T(ref->link)
|
||||
&& (T(ref->link)[0] != '/')
|
||||
&& !isautoprefix(T(ref->link)) )
|
||||
return 0;
|
||||
tag = &linkt;
|
||||
}
|
||||
|
||||
if ( f->flags & tag->flags )
|
||||
return 0;
|
||||
|
||||
if ( tag->link_pfx ) {
|
||||
Qstring(tag->link_pfx, f);
|
||||
|
||||
if ( tag->kind & IS_URL ) {
|
||||
if ( f->base && T(ref->link) && (T(ref->link)[tag->szpat] == '/') )
|
||||
puturl(f->base, strlen(f->base), f);
|
||||
puturl(T(ref->link) + tag->szpat, S(ref->link) - tag->szpat, f);
|
||||
}
|
||||
else
|
||||
___mkd_reparse(T(ref->link) + tag->szpat, S(ref->link) - tag->szpat, INSIDE_TAG, f);
|
||||
|
||||
Qstring(tag->link_sfx, f);
|
||||
|
||||
if ( tag->WxH && ref->height && ref->width ) {
|
||||
Qprintf(f," height=\"%d\"", ref->height);
|
||||
Qprintf(f, " width=\"%d\"", ref->width);
|
||||
}
|
||||
|
||||
if ( S(ref->title) ) {
|
||||
Qstring(" title=\"", f);
|
||||
___mkd_reparse(T(ref->title), S(ref->title), INSIDE_TAG, f);
|
||||
Qchar('"', f);
|
||||
}
|
||||
|
||||
Qstring(tag->text_pfx, f);
|
||||
___mkd_reparse(T(text), S(text), tag->flags, f);
|
||||
Qstring(tag->text_sfx, f);
|
||||
}
|
||||
else
|
||||
Qwrite(T(ref->link) + tag->szpat, S(ref->link) - tag->szpat, f);
|
||||
|
||||
return 1;
|
||||
} /* linkyformat */
|
||||
|
||||
|
||||
/*
|
||||
* process embedded links and images
|
||||
*/
|
||||
@@ -644,64 +641,59 @@ static int
|
||||
linkylinky(int image, MMIOT *f)
|
||||
{
|
||||
int start = mmiottell(f);
|
||||
Footnote link;
|
||||
linkytype *tag;
|
||||
int implicit_mark;
|
||||
Cstring name;
|
||||
Footnote key, *ref;
|
||||
|
||||
int status = 0;
|
||||
|
||||
if ( !linkykey(image, &link, f) ) {
|
||||
failed: mmiotseek(f, start);
|
||||
if ( link.dealloc ) DELETE(link.link);
|
||||
return 0;
|
||||
}
|
||||
CREATE(name);
|
||||
bzero(&key, sizeof key);
|
||||
|
||||
if ( image )
|
||||
tag = &imaget;
|
||||
else if ( (f->flags & NO_PSEUDO_PROTO) || (tag = extratag(link.link)) == 0 ) {
|
||||
/* if SAFELINK, only accept links that are local or
|
||||
* a well-known protocol
|
||||
*/
|
||||
if ( (f->flags & SAFELINK) && (T(link.link)[0] != '/')
|
||||
&& !isautoprefix(T(link.link)) ) {
|
||||
goto failed;
|
||||
}
|
||||
tag = &linkt;
|
||||
}
|
||||
if ( linkylabel(f, &name) ) {
|
||||
implicit_mark = mmiottell(f);
|
||||
eatspace(f);
|
||||
|
||||
if ( f->flags & tag->flags )
|
||||
goto failed;
|
||||
|
||||
if ( tag->link_pfx ) {
|
||||
Qstring(tag->link_pfx, f);
|
||||
switch ( pull(f) ) {
|
||||
case '(': /* embedded link */
|
||||
if ( linkyurl(f, image, &key) && linkysize(f, image, &key)
|
||||
&& linkytitle(f, &key) ) {
|
||||
if ( peek(f, 1) == ')' ) {
|
||||
pull(f);
|
||||
status = linkyformat(f, name, image, &key);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
if ( tag->kind & IS_URL ) {
|
||||
if ( f->base && (T(link.link)[tag->szpat] == '/') )
|
||||
puturl(f->base, strlen(f->base), f);
|
||||
puturl(T(link.link) + tag->szpat, S(link.link) - tag->szpat, f);
|
||||
}
|
||||
else
|
||||
___mkd_reparse(T(link.link) + tag->szpat, S(link.link) - tag->szpat, INSIDE_TAG, f);
|
||||
|
||||
Qstring(tag->link_sfx, f);
|
||||
case '[':/* footnote link */
|
||||
default: /* (undocumented) implicit link */
|
||||
if ( peek(f, 0) != '[' ) {
|
||||
mmiotseek(f, implicit_mark);
|
||||
if ( f->flags & MKD_1_COMPAT )
|
||||
break;
|
||||
}
|
||||
else if ( !linkylabel(f, &key.tag) )
|
||||
break;
|
||||
|
||||
if ( !S(key.tag) ) {
|
||||
DELETE(key.tag);
|
||||
T(key.tag) = T(name);
|
||||
S(key.tag) = S(name);
|
||||
}
|
||||
|
||||
if ( tag->WxH && link.height && link.width ) {
|
||||
Qprintf(f," height=\"%d\"", link.height);
|
||||
Qprintf(f, " width=\"%d\"", link.width);
|
||||
if ( ref = bsearch(&key, T(*f->footnotes), S(*f->footnotes),
|
||||
sizeof key, (stfu)__mkd_footsort) )
|
||||
status = linkyformat(f, name, image, ref);
|
||||
}
|
||||
|
||||
if ( S(link.title) ) {
|
||||
Qstring(" title=\"", f);
|
||||
___mkd_reparse(T(link.title), S(link.title), INSIDE_TAG, f);
|
||||
Qchar('"', f);
|
||||
}
|
||||
|
||||
Qstring(tag->text_pfx, f);
|
||||
___mkd_reparse(T(link.tag), S(link.tag), tag->flags, f);
|
||||
Qstring(tag->text_sfx, f);
|
||||
}
|
||||
else
|
||||
Qwrite(T(link.link) + tag->szpat, S(link.link) - tag->szpat, f);
|
||||
|
||||
if ( link.dealloc ) DELETE(link.link);
|
||||
return 1;
|
||||
DELETE(name);
|
||||
___mkd_freefootnote(&key);
|
||||
|
||||
if ( status == 0 )
|
||||
mmiotseek(f, start);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+13
-5
@@ -55,6 +55,17 @@ ___mkd_freeParagraph(Paragraph *p)
|
||||
}
|
||||
|
||||
|
||||
/* bye bye footnote.
|
||||
*/
|
||||
void
|
||||
___mkd_freefootnote(Footnote *f)
|
||||
{
|
||||
DELETE(f->tag);
|
||||
DELETE(f->link);
|
||||
DELETE(f->title);
|
||||
}
|
||||
|
||||
|
||||
/* bye bye footnotes.
|
||||
*/
|
||||
void
|
||||
@@ -63,11 +74,8 @@ ___mkd_freefootnotes(MMIOT *f)
|
||||
int i;
|
||||
|
||||
if ( f->footnotes ) {
|
||||
for (i=0; i < S(*f->footnotes); i++) {
|
||||
DELETE(T(*f->footnotes)[i].tag);
|
||||
DELETE(T(*f->footnotes)[i].link);
|
||||
DELETE(T(*f->footnotes)[i].title);
|
||||
}
|
||||
for (i=0; i < S(*f->footnotes); i++)
|
||||
___mkd_freefootnote( &T(*f->footnotes)[i] );
|
||||
DELETE(*f->footnotes);
|
||||
free(f->footnotes);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user