diff --git a/Csio.c b/Csio.c index df4f7a0..4358b33 100644 --- a/Csio.c +++ b/Csio.c @@ -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; diff --git a/cstring.h b/cstring.h index 6c754de..c747282 100644 --- a/cstring.h +++ b/cstring.h @@ -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 diff --git a/generate.c b/generate.c index a0899a8..abb592f 100644 --- a/generate.c +++ b/generate.c @@ -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 ``, 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 */ 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; } diff --git a/resource.c b/resource.c index 34f375d..3e5628a 100644 --- a/resource.c +++ b/resource.c @@ -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); }