Commit dcf2a3b1 authored by Alessandro Ghedini's avatar Alessandro Ghedini

Imported Upstream version 2.0.8

parent faa4de33
......@@ -10,6 +10,8 @@
ac_help='--enable-amalloc Enable memory allocation debugging
--with-tabstops=N Set tabstops to N characters (default is 4)
--with-dl=X Use Discount, Extra, or Both types of definition list
--with-id-anchor Use id= anchors for table-of-contents links
--with-github-tags Allow `_` and `-` in <> tags
--enable-all-features Turn on all stable optional features
--shared Build shared libraries (default is static)'
......@@ -51,6 +53,9 @@ BOTH) AC_DEFINE 'USE_EXTRA_DL' 1
*) AC_FAIL "Unknown value <$WITH_DL> for --with-dl (want 'discount', 'extra', or 'both')" ;;
esac
test "$WITH_ID_ANCHOR" && AC_DEFINE 'WITH_ID_ANCHOR' 1
test "$WITH_GITHUB_TAGS" && AC_DEFINE 'WITH_GITHUB_TAGS' 1
AC_PROG_CC
test "$TRY_SHARED" && AC_COMPILER_PIC && AC_CC_SHLIBS
......
......@@ -191,6 +191,7 @@ ___mkd_reparse(char *bfr, int size, int flags, MMIOT *f)
sub.flags = f->flags | flags;
sub.cb = f->cb;
sub.ref_prefix = f->ref_prefix;
push(bfr, size, &sub);
EXPAND(sub.in) = 0;
......@@ -564,6 +565,17 @@ printlinkyref(MMIOT *f, linkytype *tag, char *link, int size)
} /* printlinkyref */
/* helper function for php markdown extra footnotes; allow the user to
* define a prefix tag instead of just `fn`
*/
static char *
p_or_nothing(p)
MMIOT *p;
{
return p->ref_prefix ? p->ref_prefix : "fn";
}
/* php markdown extra/daring fireball style print footnotes
*/
static int
......@@ -577,8 +589,9 @@ extra_linky(MMIOT *f, Cstring text, Footnote *ref)
else {
ref->flags |= REFERENCED;
ref->refnumber = ++ f->reference;
Qprintf(f, "<sup id=\"fnref:%d\"><a href=\"#fn:%d\" rel=\"footnote\">%d</a></sup>",
ref->refnumber, ref->refnumber, ref->refnumber);
Qprintf(f, "<sup id=\"%sref:%d\"><a href=\"#%s:%d\" rel=\"footnote\">%d</a></sup>",
p_or_nothing(f), ref->refnumber,
p_or_nothing(f), ref->refnumber, ref->refnumber);
}
return 1;
} /* extra_linky */
......@@ -950,7 +963,11 @@ maybe_tag_or_link(MMIOT *f)
}
else if ( isspace(c) )
break;
#if WITH_GITHUB_TAGS
else if ( ! (c == '/' || c == '-' || c == '_' || isalnum(c) ) )
#else
else if ( ! (c == '/' || isalnum(c) ) )
#endif
maybetag=0;
}
......@@ -1298,6 +1315,15 @@ text(MMIOT *f)
Qchar(c, f);
break;
case ':': case '|':
if ( f->flags & MKD_NOTABLES ) {
Qchar('\\', f);
shift(f,-1);
break;
}
Qchar(c, f);
break;
case '>': case '#': case '.': case '-':
case '+': case '{': case '}': case ']':
case '!': case '[': case '*': case '_':
......@@ -1340,6 +1366,17 @@ text(MMIOT *f)
static void
printheader(Paragraph *pp, MMIOT *f)
{
#if WITH_ID_ANCHOR
Qprintf(f, "<h%d", pp->hnumber);
if ( f->flags & MKD_TOC ) {
Qstring(" id=\"", f);
mkd_string_to_anchor(T(pp->text->text),
S(pp->text->text),
(mkd_sta_function_t)Qchar, f, 1);
Qchar('"', f);
}
Qchar('>', f);
#else
if ( f->flags & MKD_TOC ) {
Qstring("<a name=\"", f);
mkd_string_to_anchor(T(pp->text->text),
......@@ -1348,6 +1385,7 @@ printheader(Paragraph *pp, MMIOT *f)
Qstring("\"></a>\n", f);
}
Qprintf(f, "<h%d>", pp->hnumber);
#endif
push(T(pp->text->text), S(pp->text->text), f);
text(f);
Qprintf(f, "</h%d>", pp->hnumber);
......@@ -1374,8 +1412,11 @@ splat(Line *p, char *block, Istring align, int force, MMIOT *f)
if ( force && (colno >= S(align)-1) )
idx = S(p->text);
else
while ( (idx < S(p->text)) && (T(p->text)[idx] != '|') )
while ( (idx < S(p->text)) && (T(p->text)[idx] != '|') ) {
if ( T(p->text)[idx] == '\\' )
++idx;
++idx;
}
Qprintf(f, "<%s%s>",
block,
......@@ -1423,7 +1464,9 @@ printtable(Paragraph *pp, MMIOT *f)
last=first=0;
for (end=start ; (end < S(dash->text)) && p[end] != '|'; ++ end ) {
if ( !isspace(p[end]) ) {
if ( p[end] == '\\' )
++ end;
else if ( !isspace(p[end]) ) {
if ( !first) first = p[end];
last = p[end];
}
......@@ -1662,10 +1705,11 @@ mkd_extra_footnotes(MMIOT *m)
for ( j=0; j < S(*m->footnotes); j++ ) {
t = &T(*m->footnotes)[j];
if ( (t->refnumber == i) && (t->flags & REFERENCED) ) {
Csprintf(&m->out, "<li id=\"fn:%d\">\n<p>", t->refnumber);
Csprintf(&m->out, "<li id=\"%s:%d\">\n<p>",
p_or_nothing(m), t->refnumber);
Csreparse(&m->out, T(t->title), S(t->title), 0);
Csprintf(&m->out, "<a href=\"#fnref:%d\" rev=\"footnote\">&#8617;</a>",
t->refnumber);
Csprintf(&m->out, "<a href=\"#%sref:%d\" rev=\"footnote\">&#8617;</a>",
p_or_nothing(m), t->refnumber);
Csprintf(&m->out, "</p></li>\n");
}
}
......
......@@ -36,39 +36,79 @@ basename(char *p)
char *pgm = "markdown";
static struct {
static struct _opt {
char *name;
char *desc;
int off;
int skip;
mkd_flag_t flag;
} opts[] = {
{ "tabstop", 0, MKD_TABSTOP },
{ "image", 1, MKD_NOIMAGE },
{ "links", 1, MKD_NOLINKS },
{ "relax", 1, MKD_STRICT },
{ "strict", 0, MKD_STRICT },
{ "tables", 1, MKD_NOTABLES },
{ "header", 1, MKD_NOHEADER },
{ "html", 1, MKD_NOHTML },
{ "ext", 1, MKD_NO_EXT },
{ "cdata", 0, MKD_CDATA },
{ "pants", 1, MKD_NOPANTS },
{ "smarty", 1, MKD_NOPANTS },
{ "toc", 0, MKD_TOC },
{ "autolink", 0, MKD_AUTOLINK },
{ "safelink", 0, MKD_SAFELINK },
{ "del", 1, MKD_NOSTRIKETHROUGH },
{ "strikethrough", 1, MKD_NOSTRIKETHROUGH },
{ "superscript", 1, MKD_NOSUPERSCRIPT },
{ "emphasis", 0, MKD_NORELAXED },
{ "divquote", 1, MKD_NODIVQUOTE },
{ "alphalist", 1, MKD_NOALPHALIST },
{ "definitionlist",1, MKD_NODLIST },
{ "1.0", 0, MKD_1_COMPAT },
{ "footnotes", 0, MKD_EXTRA_FOOTNOTE },
{ "footnote", 0, MKD_EXTRA_FOOTNOTE },
{ "tabstop", "default (4-space) tabstops", 0, 0, MKD_TABSTOP },
{ "image", "images", 1, 0, MKD_NOIMAGE },
{ "links", "links", 1, 0, MKD_NOLINKS },
{ "relax", "emphasis inside words", 1, 1, MKD_STRICT },
{ "strict", "emphasis inside words", 0, 0, MKD_STRICT },
{ "tables", "tables", 1, 0, MKD_NOTABLES },
{ "header", "pandoc-style headers", 1, 0, MKD_NOHEADER },
{ "html", "html", 1, 0, MKD_NOHTML },
{ "ext", "extended protocols", 1, 0, MKD_NO_EXT },
{ "cdata", "generate cdata", 0, 0, MKD_CDATA },
{ "smarty", "smartypants", 1, 0, MKD_NOPANTS },
{ "pants", "smartypants", 1, 1, MKD_NOPANTS },
{ "toc", "tables of contents", 0, 0, MKD_TOC },
{ "autolink", "autolinking", 0, 0, MKD_AUTOLINK },
{ "safelink", "safe links", 0, 0, MKD_SAFELINK },
{ "strikethrough", "strikethrough", 1, 0, MKD_NOSTRIKETHROUGH },
{ "del", "strikethrough", 1, 1, MKD_NOSTRIKETHROUGH },
{ "superscript", "superscript", 1, 0, MKD_NOSUPERSCRIPT },
{ "emphasis", "emphasis inside words", 0, 0, MKD_NORELAXED },
{ "divquote", ">%class% blockquotes", 1, 0, MKD_NODIVQUOTE },
{ "alphalist", "alpha lists", 1, 0, MKD_NOALPHALIST },
{ "definitionlist","definition lists", 1, 0, MKD_NODLIST },
{ "1.0", "markdown 1.0 compatability", 0, 0, MKD_1_COMPAT },
{ "footnotes", "markdown extra footnotes", 0, 0, MKD_EXTRA_FOOTNOTE },
{ "footnote", "markdown extra footnotes", 0, 1, MKD_EXTRA_FOOTNOTE },
} ;
#define NR(x) (sizeof x / sizeof x[0])
int
sort_by_name(struct _opt *a, struct _opt *b)
{
return strcmp(a->name,b->name);
}
int
sort_by_flag(struct _opt *a, struct _opt *b)
{
return a->flag - b->flag;
}
void
show_flags(int byname)
{
int i;
if ( byname ) {
qsort(opts, NR(opts), sizeof(opts[0]), sort_by_name);
for (i=0; i < NR(opts); i++)
if ( ! opts[i].skip )
fprintf(stderr, "%16s : %s\n", opts[i].name, opts[i].desc);
}
else {
qsort(opts, NR(opts), sizeof(opts[0]), sort_by_flag);
for (i=0; i < NR(opts); i++)
if ( ! opts[i].skip ) {
fprintf(stderr, "%08lx : ", (long)opts[i].flag);
fprintf(stderr, opts[i].off ? "disable " : "enable ");
fprintf(stderr, "%s\n", opts[i].desc);
}
}
}
void
......@@ -125,6 +165,7 @@ main(int argc, char **argv)
int version = 0;
int with_html5 = 0;
int use_mkd_line = 0;
char *extra_footnote_prefix = 0;
char *urlflags = 0;
char *text = 0;
char *ofile = 0;
......@@ -138,7 +179,7 @@ main(int argc, char **argv)
pgm = basename(argv[0]);
opterr = 1;
while ( (opt=getopt(argc, argv, "5b:df:E:F:o:s:t:TV")) != EOF ) {
while ( (opt=getopt(argc, argv, "5b:C:df:E:F:o:s:t:TV")) != EOF ) {
switch (opt) {
case '5': with_html5 = 1;
break;
......@@ -150,9 +191,19 @@ main(int argc, char **argv)
break;
case 'E': urlflags = optarg;
break;
case 'F': flags = strtol(optarg, 0, 0);
case 'F': if ( strcmp(optarg, "?") == 0 ) {
show_flags(0);
exit(0);
}
else
flags = strtol(optarg, 0, 0);
break;
case 'f': set(&flags, optarg);
case 'f': if ( strcmp(optarg, "?") == 0 ) {
show_flags(1);
exit(0);
}
else
set(&flags, optarg);
break;
case 't': text = optarg;
use_mkd_line = 1;
......@@ -161,6 +212,8 @@ main(int argc, char **argv)
break;
case 's': text = optarg;
break;
case 'C': extra_footnote_prefix = optarg;
break;
case 'o': if ( ofile ) {
fprintf(stderr, "Too many -o options\n");
exit(1);
......@@ -218,6 +271,8 @@ main(int argc, char **argv)
mkd_e_data(doc, urlflags);
mkd_e_flags(doc, e_flags);
}
if ( extra_footnote_prefix )
mkd_ref_prefix(doc, extra_footnote_prefix);
if ( debug )
rc = mkd_dump(doc, stdout, 0, argc ? basename(argv[0]) : "stdin");
......@@ -232,6 +287,7 @@ main(int argc, char **argv)
}
}
}
mkd_deallocate_tags();
adump();
exit( (rc == 0) ? 0 : errno );
}
......@@ -12,6 +12,7 @@
.Op Fl T
.Op Fl V
.Op Fl b Ar url-base
.Op Fl C Ar prefix
.Op Fl F Pa bitmap
.Op Fl f Ar flags
.Op Fl o Pa file
......@@ -31,9 +32,13 @@ to stdout.
The options are as follows:
.Bl -tag -width "-o file"
.It Fl b Ar url-base
Links in source begining with / will be prefixed with
Links in source beginning with / will be prefixed with
.Ar url-base
in the output.
.It Fl C
When processing markdown extra-style footnotes, use the
given prefix instead of the default of
.Ar fn .
.It Fl d
Instead of writing the html file, dump a parse
tree to stdout.
......@@ -100,6 +105,8 @@ blocks.
Allow alphabetic lists.
.It Ar definitionlist
Allow definition lists.
.It Ar footnote
Allow markdown extra-style footnotes.
.El
.Pp
As an example, the option
......
......@@ -104,6 +104,8 @@ blocks.
Forbid alphabetic lists.
.It Ar MKD_NODLIST
Forbid definition lists.
.It Ar MKD_EXTRA_FOOTNOTE
Enable markdown extra-style footnotes.
.El
.Sh RETURN VALUES
.Fn markdown
......@@ -133,4 +135,3 @@ created by
is deleted by the
.Nm
function.
......@@ -270,25 +270,35 @@ static int
istable(Line *t)
{
char *p;
Line *dashes = t->next;
int contains = 0; /* found character bits; 0x01 is |, 0x02 is - */
Line *dashes, *body;
int l;
int dashed = 0;
/* two lines, first must contain | */
if ( !(dashes && memchr(T(t->text), '|', S(t->text))) )
/* three lines, first must contain |,
second must be ---|---,
third must contain |
*/
if ( !(t->flags & PIPECHAR) )
return 0;
dashes = t->next;
if ( !(dashes && (dashes->flags & PIPECHAR)) )
return 0;
body = dashes->next;
if ( !(body && (body->flags & PIPECHAR)) )
return 0;
/* second line must contain - or | and nothing
* else except for whitespace or :
*/
for ( p = T(dashes->text)+S(dashes->text)-1; p >= T(dashes->text); --p)
if ( *p == '|' )
contains |= 0x01;
else if ( *p == '-' )
contains |= 0x02;
else if ( ! ((*p == ':') || isspace(*p)) )
for ( p = T(dashes->text), l = S(dashes->text); l > 0; ++p, --l)
if ( *p == '-' )
dashed = 1;
else if ( ! ((*p == '|') || (*p == ':') || isspace(*p)) )
return 0;
return (contains & 0x03);
return dashed;
}
......@@ -770,7 +780,7 @@ tableblock(Paragraph *p)
Line *t, *q;
for ( t = p->text; t && (q = t->next); t = t->next ) {
if ( !memchr(T(q->text), '|', S(q->text)) ) {
if ( !(t->flags & PIPECHAR) ) {
t->next = 0;
return q;
}
......@@ -957,7 +967,7 @@ addfootnote(Line *p, MMIOT* f)
CREATE(foot->tag);
CREATE(foot->link);
CREATE(foot->title);
foot->height = foot->width = 0;
foot->flags = foot->height = foot->width = 0;
for (j=i=p->dle+1; T(p->text)[j] != ']'; j++)
EXPAND(foot->tag) = T(p->text)[j];
......@@ -1208,6 +1218,7 @@ mkd_compile(Document *doc, DWORD flags)
doc->compiled = 1;
memset(doc->ctx, 0, sizeof(MMIOT) );
doc->ctx->ref_prefix= doc->ref_prefix;
doc->ctx->cb = &(doc->cb);
doc->ctx->flags = flags & USER_FLAGS;
CREATE(doc->ctx->in);
......
......@@ -26,7 +26,9 @@ typedef struct footnote {
typedef struct line {
Cstring text;
struct line *next;
int dle;
int dle; /* leading indent on the line */
int flags; /* special attributes for this line */
#define PIPECHAR 0x01 /* line contains a | */
} Line;
......@@ -80,6 +82,7 @@ typedef struct mmiot {
Qblock Q;
int isp;
int reference;
char *ref_prefix;
STRING(Footnote) *footnotes;
DWORD flags;
#define MKD_NOLINKS 0x00000001
......@@ -130,6 +133,7 @@ typedef struct document {
int compiled; /* set after mkd_compile() */
int html; /* set after (internal) htmlify() */
int tabstop; /* for properly expanding tabs (ick) */
char *ref_prefix;
MMIOT *ctx; /* backend buffers, flags, and structures */
Callback_data cb; /* callback functions & private data */
} Document;
......@@ -154,11 +158,13 @@ typedef int (*mkd_sta_function_t)(const int,const void*);
extern void mkd_string_to_anchor(char*,int, mkd_sta_function_t, void*, int);
extern Document *mkd_in(FILE *, DWORD);
extern Document *mkd_string(char*,int, DWORD);
extern Document *mkd_string(const char*,int, DWORD);
extern void mkd_initialize();
extern void mkd_shlib_destructor();
extern void mkd_ref_prefix(Document*, char*);
/* internal resource handling functions.
*/
extern void ___mkd_freeLine(Line *);
......
......@@ -87,6 +87,15 @@ followed by text, another
.Ar = ,
a newline, 4 spaces of intent, and then more text.)
.Pp
Alternatively, definition list items are defined as
.nf
tag
: description
.fi
(This is the format that
.Ar "PHP Markdown Extra"
uses.)
.Pp
.Ss embedded stylesheets
Stylesheets may be defined and modified in a
.Em <style>
......@@ -174,6 +183,13 @@ Like code sections, you may use as many
.Ar ~
as you want, but there must be as many starting tildes as closing
tildes.
.Ss markdown extra-style footnotes
.Ar "PHP Markdown Extra"
footnotes are supported. If a footnote link begins with a
.Ar ^ ,
the first use of that footnote will generate a link down to the
bottom of the rendered document, which will contain a numbered footnote
with a link back to where the footnote was called.
.Sh AUTHOR
David Parsons
.%T http://www.pell.portland.or.us/~orc/
......@@ -182,8 +198,7 @@ David Parsons
.Xr markdown 3 ,
.Xr mkd-callbacks 3 ,
.Xr mkd-functions 3 ,
.Xr mkd-line 3 ,
.Xr mkd-extensions 7 .
.Xr mkd-line 3 .
.Pp
.%T http://daringfireball.net/projects/markdown
.Pp
......
......@@ -163,12 +163,16 @@ first line of code blocks and disable implicit reference links.
Disable strikethrough support.
.El
.Sh RETURN VALUES
The functions
.Fn mkd_compile ,
.Fn mkd_style ,
and
The function
.Fn mkd_compile
returns 1 in the case of success, or 0 if the document is already compiled.
The function
.Fn mkd_generatecss
returns the number of bytes written in the case of success, or EOF if an error
occurred.
The function
.Fn mkd_generatehtml
return 0 on success, -1 on failure.
returns 0 on success, \-1 on failure.
.Sh SEE ALSO
.Xr markdown 1 ,
.Xr markdown 3 ,
......
......@@ -34,7 +34,8 @@ new_Document()
}
/* add a line to the markdown input chain
/* add a line to the markdown input chain, expanding tabs and
* noting the presence of special characters as we go.
*/
static void
queue(Document* a, Cstring *line)
......@@ -60,6 +61,8 @@ queue(Document* a, Cstring *line)
} while ( ++xp % a->tabstop );
}
else if ( c >= ' ' ) {
if ( c == '|' )
p->flags |= PIPECHAR;
EXPAND(p->text) = c;
++xp;
}
......@@ -148,7 +151,7 @@ mkd_in(FILE *f, DWORD flags)
/* return a single character out of a buffer
*/
struct string_ctx {
char *data; /* the unread data */
const char *data; /* the unread data */
int size; /* and how much is there? */
} ;
......@@ -167,7 +170,7 @@ strget(struct string_ctx *in)
/* convert a block of text into a linked list
*/
Document *
mkd_string(char *buf, int len, DWORD flags)
mkd_string(const char *buf, int len, DWORD flags)
{
struct string_ctx about;
......@@ -233,7 +236,7 @@ mkd_string_to_anchor(char *s, int len, mkd_sta_function_t outchar,
if ( isalnum(c) || (c == '_') || (c == ':') || (c == '-') || (c == '.' ) )
(*outchar)(c, out);
else
(*outchar)('.',out);
(*outchar)('.', out);
}
else
(*outchar)(c,out);
......@@ -342,3 +345,13 @@ mkd_e_data(Document *f, void *data)
if ( f )
f->cb.e_data = data;
}
/* set the href prefix for markdown extra style footnotes
*/
void
mkd_ref_prefix(Document *f, char *data)
{
if ( f )
f->ref_prefix = data;
}
......@@ -10,7 +10,7 @@ typedef @DWORD@ mkd_flag_t;
/* line builder for markdown()
*/
MMIOT *mkd_in(FILE*,mkd_flag_t); /* assemble input from a file */
MMIOT *mkd_string(char*,int,mkd_flag_t); /* assemble input from a buffer */
MMIOT *mkd_string(const char*,int,mkd_flag_t); /* assemble input from a buffer */
void mkd_basename(MMIOT*,char*);
......@@ -71,6 +71,8 @@ extern char markdown_version[];
void mkd_mmiot_flags(FILE *, MMIOT *, int);
void mkd_flags_are(FILE*, mkd_flag_t, int);
void mkd_ref_prefix(MMIOT*, char*);
/* special flags for markdown() and mkd_text()
*/
......
......@@ -18,6 +18,16 @@ try -ffootnote 'footnotes (-ffootnote)' "$FOOTIE" \
</ol>
</div>'
try -ffootnote -Cfoot 'footnotes (-ffootnote -Cfoot)' "$FOOTIE" \
'<p>I haz a footnote<sup id="footref:1"><a href="#foot:1" rel="footnote">1</a></sup></p>
<div class="footnotes">
<hr/>
<ol>
<li id="foot:1">
<p>yes?<a href="#footref:1" rev="footnote">&#8617;</a></p></li>
</ol>
</div>'
try -fnofootnote 'footnotes (-fnofootnote)' "$FOOTIE" \
'<p>I haz a footnote<a href="yes?">^1</a></p>'
......
......@@ -29,10 +29,13 @@ summary() {
try() {
unset FLAGS
case "$1" in
-*) FLAGS=$1
shift ;;
esac
while [ "$1" ]; do
case "$1" in
-*) FLAGS="$FLAGS $1"
shift ;;
*) break ;;
esac
done
testcase=`./echo -n " $1" '........................................................' | ./cols 50`
__tests=`expr $__tests + 1`
......
......@@ -151,17 +151,61 @@ text' \
try 'table headers only' \
'a|b|c
-|-|-' \
'<p>a|b|c
&ndash;|&ndash;|&ndash;</p>'
try 'escaped title line' \
'A\|B
--|-
C |D' \
'<table>
<thead>
<tr>
<th>a</th>
<th>b</th>
<th>c</th>
<th>A|B</th>
</tr>
</thead>
<tbody>
<tr>
<td>C |D</td>
</tr>
</tbody>
</table>'
try 'escaped dashes line' \
'A |B
-\|-
C |D' \
'<p>A |B
&ndash;|&ndash;
C |D</p>'
try 'escaped content line' \
'A |B
--|-
C\|D' \
'<table>
<thead>
<tr>
<th>A </th>
<th>B</th>
</tr>
</thead>
<tbody>
<tr>
<td>C|D</td>
<td></td>
</tr>
</tbody>
</table>'
try 'content line w/o dashes' \
'A |B
--|-
CD' \
'<p>A |B
&mdash;|&ndash;
CD</p>'
summary $0
exit $rc
. tests/functions.sh
title "table-of-contents support"
rc=0
MARKDOWN_FLAGS=
try '-T -ftoc' 'table of contents' \
'#H1
if ./markdown -V | grep ID-ANCHOR >/dev/null; then
# old-style; uses id= tag (and collides
# with #-style css)
title "(old) table-of-contents support"
try '-T -ftoc' 'table of contents' \
'#H1
hi' \
'<ul>
<li><a href="#H1">H1</a></li>
</ul>
<h1 id="H1">H1</h1>
<p>hi</p>'
try '-T -ftoc' 'toc item with link' \
'##[H2](H2) here' \
'<ul>
<li><ul>
<li><a href="#H2.here">H2 here</a></li>
</ul></li>
</ul>
<h2 id="H2.here"><a href="H2">H2</a> here</h2>'
try '-T -ftoc' 'toc item with non-alpha start' \
'#1 header' \
'<ul>
<li><a href="#L1.header">1 header</a></li>