#!/bin/sh
ESC_SEQ='\0'
cat () {
while IFS= read -r line; do printf "%s\n" "$line"; done < "$1"
}
# remove a shebang from the start of the file
_remove_shebang () {
IFS= read -r line
case "$line" in
"#!"*) ;;
*) printf "%s\n" "$line"
esac
while IFS= read -r line; do
printf "%s\n" "$line"
done
}
# remove traling whitespace from empty lines
#
_pre_strip () {
while IFS= read -r line; do
set -- $line
[ "$*" ] && {
l="$line"
line=
while [ "$l" != "${l#?}" ]; do
c="${l%*"${l#?}"}"
case "$c" in
" ") line="$line ";;
*) line="$line$c" ;;
esac
l="${l#?}"
done
printf "%s\n" "$line"
} || printf "\n"
done
}
# replace all * with _ for easier processing
#
_pre_emph () {
while IFS= read -r line; do
case "$line" in "$ESC_SEQ"*) printf "%s\n" "$line" && continue;; esac
while [ "$line" != "${line%%\**}" ]; do
printf "%s_" "${line%%\**}"
line="${line#*\*}"
done
printf "%s\n" "${line}"
done
}
# fix any misaligned and closign tags
#
_post_emph () {
while IFS= read -r line; do
case "$line" in "$ESC_SEQ"*) printf "%s\n" "$line" && continue;; esac
# TODO: avoid this problem entirely?
wrong="" right=""
while [ "$line" != "${line%%${wrong}*}" ]; do
printf "%s${right}" "${line%%${wrong}*}"
line="${line#*${wrong}}"
done
printf "%s\n" "${line}"
done
}
# parse emphasis in a line
#
# emph [bound]
\n%s\n" "$line" || printf "%s\n" "$line" empty=false ;; esac done $empty || { printf "
\n" } } # parse ref-style links # #_ref () { #} # parse links # _a_img () { open="[" mid="](" close=")" while IFS= read -r line; do case "$line" in "$ESC_SEQ"*) printf "%s\n" "$line" && continue; esac next="$line" while [ "$next" != "${next#*$close}" ]; do case "$next" in *"["*"]("*")"*);; *) break; esac before="${next%%$open*}" text=${next#*$open} text=${text%%$mid*} url=${next#*$mid} url=${url%%$close*} title=${url#* } url=${url%% *} [ "$title" != "$url" ] \ && title=" title=$title" \ || title= case "$before" in *!) h="%s\n%s\n" before="${before%!}" ;; *) h="%s\n%s\n%s\n" ;; esac printf "$h" "$before" "$ESC_SEQ" "$url" "$title" "$text" next="${next#*$close}" done printf "%s\n" "$next"; done } # get indentation level of a line # _get_indent () { indent=0 l="$*" while [ "$l" ]; do c="${l%*"${l#?}"}" case "$c" in " ") indent=$((indent+1)) ;; *) l="${l#?}" break ;; esac l="${l#?}" done printf "%s" "$indent" } # print a string x times # # print_x x "string" print_x () { x=$1; shift until [ "$((x=x-1))" -lt "0" ]; do printf "%s" "$*" done } # parse unordered lists # _ul () { indent_level=-1 to_close=0 while IFS= read -r line; do case "$line" in "$ESC_SEQ"*) printf "%s\n" "$line" && continue;; esac set -- $line case "$1" in "-"|"_"|"+") indent=$(_get_indent "$line") [ "$indent_level" -lt "$indent" ] && { printf "" "
"
}
# parse multiline codeblocks
#
_code () {
codeblock=false content=true
while IFS= read -r line; do
case "$line" in
" "*)
# prefix lines with newline to avoid trailing newline
$codeblock &&
printf "\n%s" "$ESC_SEQ${line# }" ||
$content || {
printf "%s%s" "$ESC_SEQ" "${line# }"
codeblock=true
}
;;
"")
$codeblock \
&& printf "\n%s" "$ESC_SEQ" \
|| printf "\n"
;;
*)
$codeblock && {
printf "
\n"
codeblock=false
}
printf "%s\n" "$line"
;;
esac
case "$line" in
"") content=false ;;
*) content=true ;;
esac
done
}
# parse quotes
#
_blockquote () {
indent_level=0
while IFS= read -r line; do
case "$line" in "$ESC_SEQ"*) printf "%s\n" "$line" && continue;; esac
set - $line
case "$1" in
">"*)
indent=0
while [ "$line" ]; do
c="${line%*${line#?}}"
case "$c" in
">") indent=$((indent+1)) ;;
" "*)
line="${line#?}"
break
;;
esac
line="${line#?}"
done
print_x $((indent-indent_level)) "\n" print_x $((indent_level-indent)) "\n" indent_level=$indent ;; esac printf "%s\n" "$line" done print_x $((indent_level)) "\n" } # add html header # _html () { printf "\n" while IFS= read -r line; do printf "%s\n" "$line" done } # remove all unecessary newlines # _squash () { while IFS= read -r line; do case "$line" in "$ESC_SEQ"*) printf "\n%s" "${line#??}" ;; *) printf "%s" "$line" ;; esac done printf "\n" } # convert the markdown from stdin into html # md2html () { _remove_shebang \ | _pre_strip \ | _code \ | _pre_emph \ | _blockquote \ | _ul \ | _ol \ | _p \ | _a_img \ | _inline_code \ | _emph '__' "" "" \ | _emph '_' "" "" \ | _post_emph \ | _h 6 \ | _h 5 \ | _h 4 \ | _h 3 \ | _h 2 \ | _h 1 \ | _squash } [ -z "$*" ] \ && md2html \ || md2html < "$1"