mirror of
https://github.com/Orc/discount.git
synced 2026-09-25 04:10:00 +03:00
A few bug fixes and a feature enhancement.
The bug fixes (bugs reported by Mike Schiraldi @ reddit) are 1. If -fautolink is turned on, a naked @ becomes a mailto: link. Fixed by only triggering `maybe_tag_or_link()` on alphabetic characters. 2. If -fnohtml is set, forced linebreaks become <br/>. Fixed by filtering out nonprinting nonwhitespace characters on the input and using ^C as the <br/> generator character instead of converting the forced linebreak directly to <br/>. 3. inline links (via []()) don't allow spaces or escaped ) characters. Fixed by rewriting `linkyurl()` so it builds a new `Cstring` for link.link (which needs to be deleted after use, so I added a new `deallocate` field to the bookmark record for `linkylinky` to use,) changing the link gobbler to absorb input until a terminator instead of until whitespace or a terminator) and allowing \ to escape ), =, or ". 4. Change `Qchar` to take an integer instead of a char. The feature enhancement is the `abbr:` pseudo-protocol, which I had not implemented because it collided with the old 'eat until whitespace' version of `linkyurl()`
This commit is contained in:
+51
-35
@@ -114,7 +114,7 @@ shift(MMIOT *f, int i)
|
||||
/* Qchar()
|
||||
*/
|
||||
static void
|
||||
Qchar(char c, MMIOT *f)
|
||||
Qchar(int c, MMIOT *f)
|
||||
{
|
||||
block *cur;
|
||||
|
||||
@@ -393,8 +393,8 @@ linkylabel(MMIOT *f, int *sizep)
|
||||
* `text`, where I extract until I reach a ')' or
|
||||
* whitespace.
|
||||
*/
|
||||
static char*
|
||||
linkyurl(MMIOT *f, int *sizep)
|
||||
static int
|
||||
linkyurl(MMIOT *f, Footnote *p, char *fin)
|
||||
{
|
||||
int size = 0;
|
||||
char *ptr;
|
||||
@@ -403,27 +403,31 @@ linkyurl(MMIOT *f, int *sizep)
|
||||
if ( (c = eatspace(f)) == EOF )
|
||||
return 0;
|
||||
|
||||
ptr = cursor(f);
|
||||
|
||||
/* if I do (title:blah blah blah) embedded links, I need to subvert
|
||||
* linkyurl to do a lookahead for the pseudo-protocol, then snarf
|
||||
* up everything up to the terminating ')'
|
||||
*/
|
||||
p->dealloc = 1;
|
||||
CREATE(p->link);
|
||||
|
||||
if ( c == '<' ) {
|
||||
pull(f);
|
||||
ptr++;
|
||||
ptr = cursor(f);
|
||||
if ( (size = parenthetical('<', '>', f)) == EOF )
|
||||
return 0;
|
||||
SUFFIX(p->link, ptr, size);
|
||||
}
|
||||
else {
|
||||
for ( ; ((c=pull(f)) != ')') && !isspace(c); size++)
|
||||
if ( c == EOF ) return 0;
|
||||
if ( c == ')' )
|
||||
shift(f, -1);
|
||||
while (1) {
|
||||
if ( (c = pull(f)) == EOF )
|
||||
return 0;
|
||||
else if ( strchr(fin, c) ) {
|
||||
shift(f, -1);
|
||||
break;
|
||||
}
|
||||
if ( (c == '\\') && strchr(fin, peek(f,1)) )
|
||||
c = pull(f);
|
||||
EXPAND(p->link) = c;
|
||||
}
|
||||
___mkd_tidy(&p->link);
|
||||
}
|
||||
*sizep = size;
|
||||
return ptr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -497,6 +501,7 @@ linkykey(int image, Footnote *val, MMIOT *f)
|
||||
{
|
||||
Footnote *ret;
|
||||
Cstring mylabel;
|
||||
Cstring *url;
|
||||
int here;
|
||||
|
||||
memset(val, 0, sizeof *val);
|
||||
@@ -509,7 +514,7 @@ linkykey(int image, Footnote *val, MMIOT *f)
|
||||
switch ( pull(f) ) {
|
||||
case '(':
|
||||
/* embedded link */
|
||||
if ( (T(val->link) = linkyurl(f,&S(val->link))) == 0 )
|
||||
if ( !linkyurl(f, val, image ? "='\")" : "'\")") )
|
||||
return 0;
|
||||
|
||||
if ( image && !linkysize(f, &val->height, &val->width) )
|
||||
@@ -592,12 +597,14 @@ typedef struct linkytype {
|
||||
char *text_pfx; /* text prefix (eg: ">" */
|
||||
char *text_sfx; /* text suffix (eg: "</a>" */
|
||||
int flags; /* reparse flags */
|
||||
int kind; /* tag is url or something else? */
|
||||
#define IS_URL 0x01
|
||||
} linkytype;
|
||||
|
||||
static linkytype imaget = { 0, 0, "<img src=\"", "\"",
|
||||
1, " alt=\"", "\" />", DENY_IMG|INSIDE_TAG };
|
||||
1, " alt=\"", "\" />", DENY_IMG|INSIDE_TAG, IS_URL };
|
||||
static linkytype linkt = { 0, 0, "<a href=\"", "\"",
|
||||
0, ">", "</a>", DENY_A };
|
||||
0, ">", "</a>", DENY_A, IS_URL };
|
||||
|
||||
/*
|
||||
* pseudo-protocols for [][];
|
||||
@@ -607,9 +614,10 @@ static linkytype linkt = { 0, 0, "<a href=\"", "\"",
|
||||
* raw: just dump the link without any processing
|
||||
*/
|
||||
static linkytype specials[] = {
|
||||
{ "id:", 3, "<a id=\"", "\"", 0, ">", "</a>", 0 },
|
||||
{ "class:", 6, "<span class=\"", "\"", 0, ">", "</span>", 0 },
|
||||
{ "raw:", 4, 0, 0, 0, 0, 0, 0 },
|
||||
{ "id:", 3, "<a id=\"", "\"", 0, ">", "</a>", 0, IS_URL },
|
||||
{ "class:", 6, "<span class=\"", "\"", 0, ">", "</span>", 0, 0 },
|
||||
{ "raw:", 4, 0, 0, 0, 0, 0, 0, 0 },
|
||||
{ "abbr:", 5, "<abbr title=\"", "\"", 0, ">", "</abbr>", 0, 0 },
|
||||
} ;
|
||||
|
||||
#define NR(x) (sizeof x / sizeof x[0])
|
||||
@@ -642,7 +650,8 @@ linkylinky(int image, MMIOT *f)
|
||||
linkytype *tag;
|
||||
|
||||
if ( !linkykey(image, &link, f) ) {
|
||||
mmiotseek(f, start);
|
||||
failed: mmiotseek(f, start);
|
||||
if ( link.dealloc ) DELETE(link.link);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -654,22 +663,25 @@ linkylinky(int image, MMIOT *f)
|
||||
*/
|
||||
if ( (f->flags & SAFELINK) && (T(link.link)[0] != '/')
|
||||
&& !isautoprefix(T(link.link)) ) {
|
||||
mmiotseek(f, start);
|
||||
return 0;
|
||||
goto failed;
|
||||
}
|
||||
tag = &linkt;
|
||||
}
|
||||
|
||||
if ( f->flags & tag-> flags ) {
|
||||
mmiotseek(f, start);
|
||||
return 0;
|
||||
}
|
||||
if ( f->flags & tag->flags )
|
||||
goto failed;
|
||||
|
||||
if ( tag->link_pfx ) {
|
||||
Qstring(tag->link_pfx, f);
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
if ( tag->WxH && link.height && link.width ) {
|
||||
@@ -690,6 +702,7 @@ linkylinky(int image, MMIOT *f)
|
||||
else
|
||||
Qwrite(T(link.link) + tag->szpat, S(link.link) - tag->szpat, f);
|
||||
|
||||
if ( link.dealloc ) DELETE(link.link);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -957,7 +970,7 @@ text(MMIOT *f)
|
||||
int smartyflags = 0;
|
||||
|
||||
while (1) {
|
||||
if (f->flags & AUTOLINK)
|
||||
if ( (f->flags & AUTOLINK) && isalpha(peek(f,1)) )
|
||||
maybe_tag_or_link(f, EOF);
|
||||
|
||||
c = pull(f);
|
||||
@@ -970,6 +983,9 @@ text(MMIOT *f)
|
||||
switch (c) {
|
||||
case 0: break;
|
||||
|
||||
case 3: Qstring("<br/>", f);
|
||||
break;
|
||||
|
||||
case '>': if ( tag_text(f) )
|
||||
Qstring(">", f);
|
||||
else
|
||||
@@ -1185,10 +1201,10 @@ printblock(Paragraph *pp, MMIOT *f)
|
||||
if ( S(t->text) > 2 && T(t->text)[S(t->text)-2] == ' '
|
||||
&& T(t->text)[S(t->text)-1] == ' ') {
|
||||
push(T(t->text), S(t->text)-2, f);
|
||||
push("<br/>\n", 6, f);
|
||||
push("\003\n", 2, f);
|
||||
}
|
||||
else {
|
||||
___mkd_tidy(t);
|
||||
___mkd_tidy(&t->text);
|
||||
push(T(t->text), S(t->text), f);
|
||||
if ( t->next )
|
||||
push("\n", 1, f);
|
||||
|
||||
+4
-4
@@ -127,10 +127,10 @@ skipempty(Line *p)
|
||||
|
||||
|
||||
void
|
||||
___mkd_tidy(Line *t)
|
||||
___mkd_tidy(Cstring *t)
|
||||
{
|
||||
while ( S(t->text) && isspace(T(t->text)[S(t->text)-1]) )
|
||||
--S(t->text);
|
||||
while ( S(*t) && isspace(T(*t)[S(*t)-1]) )
|
||||
--S(*t);
|
||||
}
|
||||
|
||||
|
||||
@@ -871,7 +871,7 @@ compile(Line *ptr, int toplevel, MMIOT *f)
|
||||
/* HORRIBLE STANDARDS KLUDGE: the first line of every block
|
||||
* has trailing whitespace trimmed off.
|
||||
*/
|
||||
___mkd_tidy(p->text);
|
||||
___mkd_tidy(&p->text->text);
|
||||
}
|
||||
|
||||
ptr = codeblock(p);
|
||||
|
||||
+2
-1
@@ -11,6 +11,7 @@ typedef struct footnote {
|
||||
Cstring link; /* what this footnote points to */
|
||||
Cstring title; /* what it's called (TITLE= attribute) */
|
||||
int height, width; /* dimensions (for image link) */
|
||||
int dealloc; /* deallocation needed? */
|
||||
} Footnote;
|
||||
|
||||
/* each input line is read into a Line, which contains the line,
|
||||
@@ -138,6 +139,6 @@ extern void ___mkd_freeLineRange(Line *, Line *);
|
||||
extern void ___mkd_xml(char *, int, FILE *);
|
||||
extern void ___mkd_reparse(char *, int, int, MMIOT*);
|
||||
extern void ___mkd_emblock(MMIOT*);
|
||||
extern void ___mkd_tidy(Line *);
|
||||
extern void ___mkd_tidy(Cstring *);
|
||||
|
||||
#endif/*_MARKDOWN_D*/
|
||||
|
||||
@@ -113,7 +113,7 @@ populate(getc_func getc, void* ctx, int flags)
|
||||
queue(a, &line);
|
||||
S(line) = 0;
|
||||
}
|
||||
else
|
||||
else if ( isprint(c) || isspace(c) || (c & 0x80) )
|
||||
EXPAND(line) = c;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
./echo 'Reddit-style embedded links'
|
||||
rc=0
|
||||
|
||||
./echo -n ' single link ...................... '
|
||||
|
||||
V="http://www.pell.portland.or.us/~orc/Code/discount"
|
||||
Q=`echo "$V" | ./markdown -fautolink | grep -i '<a href=' | wc -l`
|
||||
|
||||
if [ ${Q:-0} -eq 1 ]; then
|
||||
./echo "ok"
|
||||
else
|
||||
./echo "FAILED"
|
||||
rc=1
|
||||
fi
|
||||
|
||||
./echo -n ' link surrounded by text .......... '
|
||||
|
||||
V="here http://it is?"
|
||||
Q=`echo "$V" | ./markdown -fautolink`
|
||||
|
||||
case "$Q" in
|
||||
'<p>here <a href="http://it">http://it</a> is?</p>') ./echo "ok" ;;
|
||||
*) ./echo "FAILED"
|
||||
rc=1;;
|
||||
esac
|
||||
|
||||
./echo -n ' naked @ .......................... '
|
||||
|
||||
V="@"
|
||||
Q=`echo "$V" | ./markdown -fautolink`
|
||||
|
||||
case "$Q" in
|
||||
'<p>@</p>') ./echo "ok" ;;
|
||||
*) ./echo "FAILED"
|
||||
rc=1;;
|
||||
esac
|
||||
|
||||
exit $rc
|
||||
+36
-21
@@ -12,15 +12,6 @@ else
|
||||
rc=1
|
||||
fi
|
||||
|
||||
./echo -n ' quote link title with () ......... '
|
||||
|
||||
if ./echo '[hehehe](url (link title))' | ./markdown | grep -i 'title="link title"' >/dev/null; then
|
||||
./echo "ok"
|
||||
else
|
||||
./echo "FAILED"
|
||||
rc=1
|
||||
fi
|
||||
|
||||
./echo -n ' url contains + ................... '
|
||||
|
||||
if ./echo '[hehehe](u+rl)' | ./markdown | grep -i '+' >/dev/null; then
|
||||
@@ -48,6 +39,33 @@ else
|
||||
rc=1
|
||||
fi
|
||||
|
||||
./echo -n ' url contains whitespace .......... '
|
||||
|
||||
if ./echo '[hehehe](r u)' | ./markdown | grep -i '"r%20u"' >/dev/null; then
|
||||
./echo "ok"
|
||||
else
|
||||
./echo "FAILED"
|
||||
rc=1
|
||||
fi
|
||||
|
||||
./echo -n ' url contains whitespace & title .. '
|
||||
|
||||
if ./echo '[hehehe](r u "there")' | ./markdown | grep -i '"r%20u"' >/dev/null; then
|
||||
./echo "ok"
|
||||
else
|
||||
./echo "FAILED"
|
||||
rc=1
|
||||
fi
|
||||
|
||||
./echo -n ' url contains escaped ) ........... '
|
||||
|
||||
if ./echo '[hehehe](u\))' | ./markdown | grep -i '"u)"' >/dev/null; then
|
||||
./echo "ok"
|
||||
else
|
||||
./echo "FAILED"
|
||||
rc=1
|
||||
fi
|
||||
|
||||
./echo -n ' label contains < ................. '
|
||||
|
||||
if ./echo '' | ./markdown | grep -i '<' >/dev/null; then
|
||||
@@ -116,6 +134,15 @@ else
|
||||
rc=1
|
||||
fi
|
||||
|
||||
./echo -n ' pseudo-protocol "abbr:" .......... '
|
||||
|
||||
if ./echo '[foo](abbr:bar)' | ./markdown | fgrep '<abbr title="bar">' >/dev/null; then
|
||||
./echo "ok"
|
||||
else
|
||||
./echo "FAILED"
|
||||
rc=1
|
||||
fi
|
||||
|
||||
./echo -n ' nested [][]s ..................... '
|
||||
|
||||
count=`./echo '[[z](y)](x)' | ./markdown | tr '>' '\n' | grep -i '<a href' | wc -l`
|
||||
@@ -144,16 +171,4 @@ else
|
||||
rc=1
|
||||
fi
|
||||
|
||||
./echo -n ' Reddit-style embedded links ...... '
|
||||
V="http://www.pell.portland.or.us/~orc/Code/discount"
|
||||
|
||||
Q=`echo "$V" | ./markdown -fautolink | grep -i '<a href=' | wc -l`
|
||||
|
||||
if [ ${Q:-0} -eq 1 ]; then
|
||||
./echo "ok"
|
||||
else
|
||||
./echo "FAILED"
|
||||
rc=1
|
||||
fi
|
||||
|
||||
exit $rc
|
||||
|
||||
@@ -82,4 +82,15 @@ else
|
||||
./echo "ok"
|
||||
fi
|
||||
|
||||
./echo -n ' markdown <br/> with -fnohtml ..... '
|
||||
|
||||
count=`echo "foo " | ./markdown -fnohtml | grep '<p>foo<br/>' | wc -l`
|
||||
|
||||
if [ $count -eq 1 ] ;then
|
||||
./echo "ok"
|
||||
else
|
||||
./echo "FAILED"
|
||||
rc=1
|
||||
fi
|
||||
|
||||
exit $rc
|
||||
|
||||
Reference in New Issue
Block a user