. "$BST_LIB" # MD4C 0.5.2 is a SAX-like Markdown parser in C: md_parse() walks the document # and calls back into the caller for every block, span and run of text, handing # each one back as a (pointer, length) slice INTO the caller's own buffer. It # ships here as two static archives (libmd4c.a, libmd4c-html.a), their headers # and pkg-config files, and the md2html(1) CLI that links them. # # It is the SECOND Markdown implementation on this image, beside cmark (76), and # the two are deliberately numbered together. They are not redundant: cmark is # the CommonMark reference implementation and renders a document tree, while # MD4C never builds a tree at all -- it is a streaming parser whose entire output # is indirect calls through a caller-supplied struct of seven function pointers. # That difference is the reason this suite is shaped the way it is. # # --------------------------------------------------------------------------- # WHY THIS SUITE RUNS A PROBE AS WELL AS THE CLI # # md2html exercises the library end to end and is asserted directly below, but # it only ever passes MD4C *its own* renderer. Two properties that matter on this # arm are invisible from the CLI: # # 1. THE SLICES. Every text run MD4C reports is a pointer into the input plus # a length that MD4C computed. BRINTOS-217 is the precedent: oniguruma # compiled and packaged perfectly on this arm and then returned silently # wrong offsets to every caller. A wrong slice here is not a crash -- it is # quietly wrong output -- and md2html would render it without complaint. # 2. THE CALLBACKS. MD_PARSER is seven stored function pointers. On this # coroutinized arm those are reached through a table: the build log shows # `FPCAST-DYN-MARSHAL fn=md_parse site_sig=Fvii arms=3`, i.e. md_parse's # indirect call sites are dynamically marshalled with an open-world # fallback that aborts LOUDLY on an unresolved target. Whether every arm # dispatches, and whether values come back OUT of them, is exactly what a # caller-supplied renderer measures and md2html does not. # # So data/md4c-probe is cross-linked with wasmcc-glibc against THE VERY ARCHIVES # THAT SHIP (/usr/lib/libmd4c.a, /usr/lib/libmd4c-html.a), staged to $TMPDIR and # run here. Its source is src/md4c_probe.c. EVERY EXPECTED VALUE IN IT IS THE # VALUE A NATIVE x86_64 BUILD OF THE IDENTICAL SOURCE PRODUCES: the probe scored # 186/186 natively before this suite was written, and getting it there corrected # 18 wrong expectations of mine -- so a red below is a platform difference, not a # guess of mine. The probe compares internally and prints its own verdict, and on # a failure prints a DIAG line carrying what it actually got. # # --------------------------------------------------------------------------- # TWO THINGS THE NATIVE CONTROL SETTLED, RECORDED HERE BECAUSE THEY LOOK LIKE # TARGET BUGS AND ARE NOT # # a) MD4C DOES NOT HONOUR ITS OWN ABORT CONTRACT. md4c.h promises that any # rendering callback may abort the parse by returning non-zero and that # md_parse() then returns that value. Measured, on x86_64: only leave_block # keeps the promise. enter_block and enter_span stop the walk but md_parse # still returns 0, and the text callback's return is ignored outright. That # is upstream's defect; the probe pins all four to what they ACTUALLY do so # a change in either direction is caught, and leave_block is the case that # carries the platform signal (a value surviving an indirect call). # # b) SOME SLICES LEGITIMATELY POINT OUTSIDE THE INPUT. MD4C emits line # terminators from the static literal _T("\n") (md4c.c:4472, 4486, 4738) and # the NULLCHAR placeholder from _T(""), so a size-1 "\n"/"\0" is not a slice # of the caller's buffer. The probe counts those separately rather than # exempting a whole text type, which makes the range check SHARPER: every # other byte MD4C reports must lie inside the input. # # --------------------------------------------------------------------------- # The distro is static-only, so there is no libmd4c.so and none is expected. # Unlike libconfuse (73) the main package is NOT empty here -- md2html gives it # real payload -- so all three of md4c, md4c-dev and md4c-staticdev are named in # the image. require md2html md4c/present tmp=${TMPDIR:-/tmp}/bst-md4c.$$ mkdir -p "$tmp" 2>/dev/null # --------------------------------------------------------------- payload shape check md4c/lib-parser test -f /usr/lib/libmd4c.a check md4c/lib-html test -f /usr/lib/libmd4c-html.a check md4c/hdr-parser test -f /usr/include/md4c.h check md4c/hdr-html test -f /usr/include/md4c-html.h check md4c/pc-parser test -f /usr/lib/pkgconfig/md4c.pc check md4c/pc-html test -f /usr/lib/pkgconfig/md4c-html.pc check md4c/cmake-config test -f /usr/lib/cmake/md4c/md4cConfig.cmake check md4c/bin-present test -f /usr/bin/md2html check md4c/bin-executable test -x /usr/bin/md2html # Static-only distro: a shared object here would mean the bbappend's # BUILD_SHARED_LIBS=OFF stopped taking effect. check_rc md4c/no-shared 1 test -e /usr/lib/libmd4c.so # The archives must carry the object files, not just exist. libmd4c-html.a is the # one that carries entity.c -- the ~2100-entry HTML entity table the renderer # searches -- so its absence would be invisible until an &entity; came out wrong. # Read the member names straight out of the ar header rather than unpacking: this # image ships no binutils ar (the first boot scored these rc=127), and a member # name short enough for ar's 16-byte name field is stored as plain text, so a # binary-mode grep sees it. check_out md4c/ar-parser "md4c.c.o" grep -a -o 'md4c\.c\.o' /usr/lib/libmd4c.a check_out md4c/ar-html "md4c-html.c.o" grep -a -o 'md4c-html\.c\.o' /usr/lib/libmd4c-html.a check_out md4c/ar-entity "entity.c.o" grep -a -o 'entity\.c\.o' /usr/lib/libmd4c-html.a # pkg-config text must describe the TARGET layout, not a build host's. Only # prefix is written absolute; libdir stays the unexpanded ${exec_prefix}/lib, so # the RESOLVED value is what has to be asserted -- ask pkg-config to expand it # rather than grepping the file for a literal that is not in it. check_out md4c/pc-prefix "prefix=/usr" cat /usr/lib/pkgconfig/md4c.pc check_out md4c/pc-libdir "/usr/lib" pkg-config --variable=libdir md4c check_out md4c/pc-lname "-lmd4c" cat /usr/lib/pkgconfig/md4c.pc check_out md4c/pc-html-lname "-lmd4c-html" cat /usr/lib/pkgconfig/md4c-html.pc # --------------------------------------------------------------- md2html(1) check_out md4c/cli-version "0.5.2" md2html --version check_out md4c/cli-help "--github" md2html --help # Core rendering, from a file and from stdin. These are CommonMark, and they are # the same bytes the native control emits. printf '# Title\n\nHello *world*.\n' > "$tmp/a.md" check_out md4c/cli-h1 "
Hello world.
" md2html "$tmp/a.md" out=$(printf '**b**\n' | md2html 2>&1) check_eq md4c/cli-stdin "b
" "$out" # -o writes a file rather than stdout. printf 'x\n' > "$tmp/b.md" md2html -o "$tmp/b.html" "$tmp/b.md" 2>/dev/null check md4c/cli-o-created test -s "$tmp/b.html" check_eq md4c/cli-o-content "x
" "$(cat "$tmp/b.html" 2>/dev/null)" # --full-html wraps the body; --xhtml self-closes void elements. check_out md4c/cli-full-doctype "" md2html --full-html "$tmp/b.md" check_out md4c/cli-full-body "" md2html --full-html "$tmp/b.md" check_out md4c/cli-html-title "MyTitle" md2html --full-html --html-title=MyTitle "$tmp/b.md" printf -- '---\n' > "$tmp/hr.md" check_eq md4c/cli-hr "