\documentstyle[noweb]{article} \pagestyle{noweb} \begin{document} \section{Converting {\tt noweb} markup to {\tt HTML}} This copyright applies both to the {\tt noweb} source and to the generated shell script. Thanks to Bill Trost for getting me started with an early version. <>= # Copyright 1994-2018 by Norman Ramsey. All rights reserved. # See file COPYRIGHT for more information. <<*>>= #!/bin/sh <> # Do not try to understand this file! Look at lib/tohtml.nw in the noweb source! delay=0 raw=0 localindex=0 noindex=0 nocomment=0 for i do case $i in -delay) delay=1 ;; -raw) raw=1 ;; -localindex) if [ $noindex -eq 0 ]; then localindex=1; fi;; -noindex) localindex=0; noindex=1 ;; -no-gen-comment) nocomment=1 ;; esac done nawk '<>' \ delay=$delay raw=$raw localindex=$localindex noindex=$noindex nocomment=$nocomment @ The [[-raw]] option brackets HTML with [[\begin{rawhtml}]] and [[\end{rawhtml}]]; the purpose is to embed HTML in a {\LaTeX} document before converting the document with {\tt latex2html}. [[braw]] and [[eraw]] hold those delimiters (or else empty strings). <>= <> BEGIN { <> } !doneraw { # do not do in BEGIN because not all awks assign variables yet if (raw) { braw = "\\begin{rawhtml}"; eraw = "\\end{rawhtml}" } else braw = eraw = "" doneraw = 1 if (!nocomment) { print braw "" eraw } } <> END { print "" } @ [[ecode]] is the marker used at the end of the current code chunk. If there is no cross-reference stuff at the end, we just use [[]]; otherwise we terminate whatever environment is used for the cross-reference stuff. <>= /^@begin code / { code = 1; printf "%s
", braw; ecode = "
" } /^@end code / { code = 0; previscode = 1; <> printf "%s%s", ecode, eraw } @ We want to try to avoid emitting paragraph elements when the preceding chunk is a code chunk, as tracked by [[previscode]]. Also, if we do slip in a paragraph, we may use the {\LaTeX} style. <>= /^@begin docs / { if (previscode) printf "%s", (raw ? "\\par" : "

") previscode = text = 0 } @ Sometimes it happens that a document-chunk anchor is put in a document chunk that contains no text. In that case, we put in a phony anchor at the end of the chunk so we won't lose the cross-reference. <>= /^@end docs / { if (lastxreflabel != "") printf "%s%s%s\n", braw, linklabel(lastxreflabel, "*"), eraw lastxreflabel = "" } @ Normally, if there's a pending anchor, we put it on the first available text line. <>= /^@text / { line = substr($0, 7); text += length(line) if (code) { if (lastindexref != "" && line ~ /[^ \t]/) { printf "%s", linkto(lastindexref, line) lastindexref = "" } else { printf "%s", escapeSpecials(line) } } else if (quoting) { if (line ~ /[^ \t]/) { printf "%s", linklabelto(lastxreflabel, lastindexref, escapeSpecials(line)) lastindexref = lastxreflabel = "" } else { printf "%s", escapeSpecials(line) } } else { if (lastxreflabel != "" && line ~ /[^ \t]/) { <> lastxreflabel = "" } else { printf "%s", line } } } @ We anchor on the first nonblank character of the line, unless that's a \TeX\ control sequence or an SGML tag. In that case we insert a {\tt*} to anchor to. None of this crap would be necessary if HTML could anchor to empty text. <>= match(line, /^[ \t]*/) blanks = substr(line, RSTART, RLENGTH) line = substr(line, RSTART+RLENGTH) if (line ~ /^[{}\\<&]/) { char = "*" } else { char = substr(line, 1, 1) line = substr(line, 2) } printf "%s%s%s%s%s", braw, blanks, linklabel(lastxreflabel, char), eraw, line if (lastxreflabel != "") defns_above[lastxreflabel] = 1 <>= /^@nl$/ { print "" } /^@defn / { thischunk = name = substr($0, 7) if (lastxreflabel != "") defns_above[lastxreflabel] = 1 writechunk(lastxreflabel, lastxrefref, "dfn", name, defns[name] "=") <> defns[name] = "+" } <>= defns[0] = 0 defns_above[0] = 0 <>= /^@use / { writechunk(lastxreflabel, lastxrefref, "i", substr($0, 6), "") } @ Writing a chunk involves creating an anchor for it. <>= function writechunk(label, ref, tag, name, suffix) { printf "%s", linklabelto(label, ref, sgmlwrap(tag, "<" convquotes(name) ">" suffix)) } @ <>= /^@quote$/ { quoting = 1 ; printf "%s", braw } /^@endquote$/ { quoting = 0 ; printf "%s", eraw } /^@file / { filename = substr($0, 7); <> } /^@literal / { printf "%s", substr($0, 10) } /^@header html / { <> } /^@trailer html$/ { <> } @ <>= printf "%s", substr($0, 14) <>= print "" @ <>= /^@xref label / { lastxreflabel = substr($0, 13) } /^@xref ref / { lastxrefref = substr($0, 11) } /^@xref prevdef/ { pendingprev = substr($0, 15) } /^@xref nextdef/ { pendingnext = substr($0, 15) } /^@xref beginuses/ { useitems = "" } /^@xref useitem / { useitems = useitems " " substr($0, 15) } /^@xref enduses/ { useitemstab[thischunk] = useitems } /^@xref notused / { <> printf "This code is written to a file (or else not used).

" } <>= useitemstab[0] = 0 <>= lastxreflabel = lastxrefref = "" <>= useitemscount = split(useitemstab[thischunk], a) if (pendingprev != "" || pendingnext != "" || useitemscount > 0) { <> <> if (useitemscount > 0 && (pendingprev != "" || pendingnext != "")) printf "; " p = useitemscount > 0 ? "previous" : "Previous" n = useitemscount > 0 ? "next" : "Next" if (pendingprev != "") if (pendingnext != "") printf "%s and %s definitions", linkto(pendingprev, p), linkto(pendingnext, "next") else printf "%s definition", linkto(pendingprev, p) else if (pendingnext != "") printf "%s definition", linkto(pendingnext, n) pendingprev = pendingnext = "" useitems = "" print ".

" } <>= useprefix = "Used " for (j = 1; j <= useitemscount; j++) { if (defns_above[a[j]] > 0) usedir = "above" else usedir = "below" printf "%s%s", useprefix, linkto(a[j], usedir (useitemscount > 1 ? " (" j ")" : "")) useprefix = ", " } @ The hack here is to put the supplementary information in a blockquote area after the code. <>= if (ecode == "") { printf "

" ecode = "
" } @ The HTML back end ignores [[@xref begindefs]], [[@xref defitem]], and [[@xref enddefs]]; it uses the [[nextdef]] and [[prevdef]] links instead. <>= /^@xref (begindefs|defitem|enddefs)/ { } /^@xref beginchunks$/ { printf "%s
    \n", braw } /^@xref chunkbegin / { label = $3; name = substr($0, 19 + length(label)) printf "
  • "; comma = ": "; count = 0 writechunk("", label, "i", name, "") } /^@xref chunkuse / { printf "%s%s", comma, linkto(substr($0, 16), "U" ++count) comma = ", " } /^@xref chunkdefn / { printf "%s%s", comma, linkto(substr($0, 17), "D" ++count) comma = ", " } /^@xref chunkend$/ { print "" } /^@xref endchunks$/ { printf "
%s\n", eraw } <>= /^@index beginindex$/ { if (!noindex) { printf "%s
    \n", braw } } /^@index entrybegin / { if (!noindex) { label = $3; name = substr($0, 20 + length(label)) printf "
  • "; comma = ": "; count = 0 printf "%s", linklabelto("NWI-" escapeSpecials(name), label, name) } } /^@index entryuse / { if (!noindex) { printf "%s%s", comma, linkto(substr($0, 17), "U" ++count) comma = ", " } } /^@index entrydefn / { if (!noindex) { printf "%s%s", comma, linkto(substr($0, 18), "D" ++count) comma = ", " } } /^@index entryend$/ { if (!noindex) { print "" } } /^@index endindex$/ { if (!noindex) { printf "
%s\n", eraw } } @ The local identifier cross-reference doesn't show each use; it just shows the identifiers that are defined, with links to the full index. <>= /^@index use/ { lastindexref = lastxrefref; lastxrefref = "" } /^@index defn/ { <> } /^@index localdefn/ { <> } /^@index nl/ { } # do nothing -- destroys line numbering /^@index begindefs/ { if (localindex) { <>; printf "Defines"; comma = " " } } /^@index isused / { } /^@index defitem / { if (localindex) { arg = substr($0, 16) printf "%s%s", comma, linkto("NWI-" escapeSpecials(arg), sgmlwrap("code", escapeSpecials(arg))) comma = ", " } } /^@index enddefs/ { if (localindex) { printf " (links are to index).

\n" } } /^@index (beginuses|isdefined|useitem|enduses)/ { } # use local links @ \subsection{Support functions} Here's all our anchor support goo. <>= function linklabelto(label, ref, contents, s) { s = label != "" || ref != "" ? "" : "") s = s contents s = s (label != "" || ref != "" ? "" : "") return s } function linkto(ref, contents) { return linklabelto("", ref, contents) } function linklabel(label, contents) { return linklabelto(label, "", contents) } @ Another support function is used for wrapping tags around text: <>= function sgmlwrap(tag, s) { return "<" tag ">" s "" } <>= function image(s) { gsub(/"/, "\\\"", s) return "\"" s "\"" } @ Lucky for us, {\tt HTML} has few special characters. Unlucky for us, we have to deal with each one seperately. Nothing much to whine about, really. <>= function escapeSpecials (l) { gsub(/&/, "\\&", l) gsub(//, "\\>", l) gsub(/"/, "\\"", l) return l } @ A special function is used to implement {\tt noweb}'s quoting convention within chunk names. <>= function convquotes(s, r, i, line) { r = "" while (i = index(s, "[[")) { r = r substr(s, 1, i-1) "" s = substr(s, i+2) if (i = match(s, "\\]\\]+")) { line = substr(s, 1, i-1+RLENGTH-2) # line = escapeSpecials(line) # destroys internal markup --- do not call r = r line "" s = substr(s, i+RLENGTH) } else { r = r s "" s = "" } } return r s } @ \end{document}