summaryrefslogtreecommitdiff
path: root/web/noweb/src/lib
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /web/noweb/src/lib
Initial commit
Diffstat (limited to 'web/noweb/src/lib')
-rw-r--r--web/noweb/src/lib/Makefile38
-rwxr-xr-xweb/noweb/src/lib/btdefn16
-rwxr-xr-xweb/noweb/src/lib/emptydefn9
-rwxr-xr-xweb/noweb/src/lib/h2a17
-rw-r--r--web/noweb/src/lib/noxref.nw215
-rw-r--r--web/noweb/src/lib/noxref.sh65
-rwxr-xr-xweb/noweb/src/lib/nwmtime32
-rwxr-xr-xweb/noweb/src/lib/pipedocs23
-rwxr-xr-xweb/noweb/src/lib/toascii131
-rw-r--r--web/noweb/src/lib/toascii.nw262
-rwxr-xr-xweb/noweb/src/lib/unmarkup48
11 files changed, 856 insertions, 0 deletions
diff --git a/web/noweb/src/lib/Makefile b/web/noweb/src/lib/Makefile
new file mode 100644
index 0000000000..47cb6f40fe
--- /dev/null
+++ b/web/noweb/src/lib/Makefile
@@ -0,0 +1,38 @@
+# Copyright 1993 by Norman Ramsey. All rights reserved.
+# See file COPYRIGHT for more information.
+
+LIB=/dev/null
+SHELL=/bin/sh
+CINAME=
+CIMSG=
+RCSFILES=emptydefn toascii.nw unmarkup Makefile nwmtime pipedocs h2a btdefn
+
+all: toascii
+ chmod +x unmarkup emptydefn toascii nwmtime pipedocs h2a btdefn
+
+install: all
+ cp unmarkup emptydefn nwmtime btdefn $(LIB)
+ sed 's@|LIBDIR|@$(LIB)@g' pipedocs > $(LIB)/pipedocs
+ sed 's@|LIBDIR|@$(LIB)@g' toascii > $(LIB)/toascii
+ sed 's@|LIBDIR|@$(LIB)@g' h2a > $(LIB)/h2a
+ chmod +x $(LIB)/pipedocs $(LIB)/toascii $(LIB)/h2a
+
+uninstall:
+ for i in unmarkup emptydefn toascii nwmtime h2a btdefn; do rm -f $(LIB)/$$i; done
+ rm -f $(LIB)/pipedocs
+
+checkin:
+ ci -l $(CINAME) $(CIMSG) $(RCSFILES)
+
+source: toascii
+touch: toascii
+ touch toascii
+boot:
+ touch toascii
+
+toascii: toascii.nw
+ notangle -Rtoascii toascii.nw > toascii
+
+clean: ; rm -f *.log *.blg *.dvi *.toc *.aux *.tex *~
+clobber: clean
+ rm -f toascii
diff --git a/web/noweb/src/lib/btdefn b/web/noweb/src/lib/btdefn
new file mode 100755
index 0000000000..a7b2d1678d
--- /dev/null
+++ b/web/noweb/src/lib/btdefn
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+# turn backticks into definitions
+
+nawk '
+/^@begin code / { code = 1 }
+/^@end code / { code = 0 }
+code && /^@text .*".*`.*"/ { print; next }
+code && /^@text .*`/ {
+ while (i = match($0, /`[a-zA-Z_][a-zA-Z0-9_]*/)) {
+ id = substr($0, i+1, RLENGTH-1)
+ sub(/`[a-zA-Z_][a-zA-Z0-9_]*/, id)
+ print "@index defn " id
+ }
+}
+{print}'
diff --git a/web/noweb/src/lib/emptydefn b/web/noweb/src/lib/emptydefn
new file mode 100755
index 0000000000..29499b147b
--- /dev/null
+++ b/web/noweb/src/lib/emptydefn
@@ -0,0 +1,9 @@
+#!/bin/sh
+#
+# notangle filter that makes the definition of an empty chunk <<>>=
+# stand for a continuation of the previous chunk definition.
+
+nawk 'BEGIN { lastdefn = "@defn " }
+/^@defn $/ { print lastdefn; next }
+/^@defn / { lastdefn = $0 }
+{ print }' "$@"
diff --git a/web/noweb/src/lib/h2a b/web/noweb/src/lib/h2a
new file mode 100755
index 0000000000..9aec5dc416
--- /dev/null
+++ b/web/noweb/src/lib/h2a
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+LIB=|LIBDIR|
+opts="-nolist"
+
+case $1 in
+ -[0-9]*) opts="$opts -width=`expr 0 - $1`" ; shift ;;
+esac
+
+html=$($LIB/nwmktemp) || { echo "$0: Cannot create temporary file" >&2; exit 1; }
+trap 'rm -f $html; exit 1' 1 2 15 # clean up files
+
+awk '
+/^ *$/ { if (NR == 1) { print ; next } }
+{ print > "'"$html"'" }'
+if [ -r $html ]; then lynx -dump $opts $html | sed '1d'; fi
+rm -f $html
diff --git a/web/noweb/src/lib/noxref.nw b/web/noweb/src/lib/noxref.nw
new file mode 100644
index 0000000000..3eec706bc7
--- /dev/null
+++ b/web/noweb/src/lib/noxref.nw
@@ -0,0 +1,215 @@
+\section{Cross-referencing tool}
+This filter adds labels and cross-references to chunk definitions and uses,
+and it converts the line [[\nowebchunks]] into an alphabetical list of chunks.
+
+Following the lead of J. G. Krom, I make it possible to generate the
+file [[noxref]] for the Unix environment, and the files [[noxref.bat]]
+and [[noxref.awk]] for the MS-DOS environment.
+
+<<*>>=
+#!/bin/sh
+nawk '<<cross-reference awk program>>'
+<<noxref.awk>>=
+<<cross-reference awk program>>
+<<noxref.bat>>=
+@echo off
+REM The NOWEB environment variable must be set to the directory
+REM where NOXREF.AWK is. It must end in '/' or '\' as required
+REM by the AWK interpreter in use.
+awk -f %NOWEB%noxref.awk
+@
+The function [[modid]] turns a chunk name into a unique key acceptable
+for use as a {\LaTeX} label.
+The first step maps the name into a 6-character key; the second step
+appends an integer (from [[keycounts]]) used to distinguish different
+chunk names that map to the same key.
+[[idtable]] is used to cache the results so the computation is
+performed just once per chunk name.
+<<function definitions>>=
+function modid(name, key) {
+ if (idtable[name] == "") {
+ key = name
+ gsub(/[\[\]\\{} `#%&~_^-]/, "*", key) # ditch special chars
+ if (length(key) > 6) key = substr(key,1,3) substr(key, length(key)-2, 3)
+ keycounts[key] = keycounts[key] + 1
+ if (keycounts[key] > 1)
+ idtable[name] = key "-" keycounts[key]
+ else
+ idtable[name] = key
+ }
+ return idtable[name]
+}
+<<initialization>>=
+idtable[0] = 0 ; keycounts[0] = 0
+@
+The complete program runs in two passes.
+The first pass saves all the input and builds up list of definitions
+and uses.
+The second pass writes out all the lines with suitable
+cross-referencing markup.
+The first pass saves information in the following tables, which are
+indexed by chunk name.
+\begin{itemize}
+\item[\tt defns] Lists labels of all defining instances.
+\item[\tt firstdef] Label of the first defining instance.
+\item[\tt dcounts] Counts the number of defining instances.
+\item[\tt uses] Lists labels of all uses.
+\item[\tt dcounts] Counts the number of uses.
+\end{itemize}
+<<initialization>>=
+defns[0] = 0 ; firstdef[0] = 0 ; dcounts[0] = 0 ; uses[0] = 0 ; ucounts[0] = 0
+@ The first pass logs both definitions ([[which == "DEFN"]]) and uses
+([[which == "USE"]]) by calling [[logname]].
+<<function definitions>>=
+function logname(which, tbl, counts, name, id, label) {
+ counts[name] = counts[name] + 1
+ id = which ":" curfile ":" modid(name) "-" counts[name]
+ tbl[name] = tbl[name] id " "
+ if (which == "DEFN" && counts[name] == 1) label = "sublabel"
+ else label = "label"
+ lines[nextline++] = "@literal \\" label "{" id "}"
+ if (which == "DEFN" && firstdef[name] == "") firstdef[name] = id
+}
+@
+The structure of the full program, showing both passes, is:
+<<cross-reference awk program>>=
+<<function definitions>>
+BEGIN { <<initialization>> }
+{ lines[nextline++] = $0 }
+/^@defn / { logname("DEFN", defns, dcounts, substr($0, 7)) }
+/^@use / { logname("USE", uses, ucounts, substr($0, 6)) }
+/^@file / { curfile = modid(substr($0, 7) substr($0, 10, 3)) }
+END { <<write out the program with cross-reference info>> }
+@
+The second pass just copies lines to its output, except for
+definitions, uses and the [[\nowebchunks]] control sequence.
+It also puts a bunch of cross-reference information at the end of each
+code chunk.
+<<write out the program with cross-reference info>>=
+for (i=0; i < nextline; i++) {
+ name = substr(lines[i], 2)
+ if (index(name, " ")) {
+ name = substr(name, 1, index(name, " ")-1)
+ arg = substr(lines[i], length(name)+3)
+ } else {
+ arg = ""
+ }
+ if (name == "defn") {
+ thischunk = arg
+ <<emit definition>>
+ } else if (name == "use") {
+ <<emit use>>
+ } else if (name == "begin") {
+ chunktype = substr(arg, 1, 4)
+ print lines[i]
+ } else if (name == "quote") {
+ quote = 1
+ print lines[i]
+ } else if (name == "endquote") {
+ quote = 0
+ print lines[i]
+ } else if (name == "end") {
+ if (chunktype == "code") {
+ <<emit cross-reference info for [[thischunk]]>>
+ }
+ print lines[i]
+ } else if (name == "text" && arg == "\\nowebchunks" && chunktype == "docs" && quote == 0) {
+ <<emit sorted list of chunks>>
+ } else {
+ print lines[i]
+ }
+ delete lines[i]
+}
+@
+\maybreak{1in}
+<<emit definition>>=
+printf "@defn %s~{\\footnotesize\\Rm\\subpageref{%s}}\n", arg, firstdef[arg]
+<<emit use>>=
+if (firstdef[arg] != "")
+ printf "@use %s~{\\footnotesize\\Rm\\subpageref{%s}}\n", arg, firstdef[arg]
+else
+ printf "@use %s~{\\footnotesize\\Rm (never defined)}\n", arg
+@
+Cross reference information is emitted only at the first definition of each
+chunk, as tracked by [[firstdefnout]].
+<<initialization>>=
+firstdefnout[0] = 0
+<<emit cross-reference info for [[thischunk]]>>=
+if (firstdefnout[thischunk] == 0) {
+ firstdefnout[thischunk] = 1
+ n = split(defns[thischunk], a)
+ if (n > 1) {
+ printf "@literal \\nwalsodefined{"
+ for (j = 2; j <= n; j++)
+ printf "\\\\{%s}", a[j]
+ printf "}\n"
+ }
+ if (uses[thischunk] != "") {
+ printf "@literal \\nwused{"
+ n = split(uses[thischunk], a)
+ for (j = 1; j <= n; j++)
+ printf "\\\\{%s}", a[j]
+ printf "}\n"
+ } else
+ printf "@literal \\nwnotused{%s}\n", escapeTeXspecials(thischunk)
+}
+@ \subsection{Sorting}
+Each chunk name is mapped to a sorting key.
+Ideally such a key would contain only lower-case letters and spaces,
+and it would discount \TeX{} control sequences, and more.
+Such computations are so excruciating in awk that I content myself
+with eliminating nonletters.
+<<function definitions>>=
+function sortkey(name, s) {
+ s = name
+ gsub(/[^a-zA-Z ]/, "", s)
+ return s
+}
+@ I maintain a two parallel lists, one containing sort keys and the other
+containing chunk names.
+<<function definitions>>=
+function insertchunk(name, i, tmp) {
+ sortcount = sortcount + 1
+ sortnames[sortcount] = name
+ sortkeys[sortcount] = sortkey(name)
+ i = sortcount
+ while (i > 1 && (sortkeys[i] < sortkeys[i-1] ||
+ sortkeys[i] == sortkeys[i-1] && sortnames[i] < sortnames[i-1])) {
+ tmp = sortkeys [i]; sortkeys [i] = sortkeys [i-1]; sortkeys [i-1] = tmp
+ tmp = sortnames[i]; sortnames[i] = sortnames[i-1]; sortnames[i-1] = tmp
+ i = i - 1
+ }
+}
+@
+That's enough machinery to do the job.
+<<emit sorted list of chunks>>=
+if (sortcount == 0) {
+ <<insert all chunk names into [[sortnames]]>>
+}
+for (j = 1; j <= sortcount; j++) {
+ if (firstdef[sortnames[j]] != "")
+ print "@use " sortnames[j] "~{\\footnotesize\\Rm\\subpageref{" firstdef[sortnames[j]] "}}"
+ else
+ print "@use " sortnames[j] "~{\\footnotesize\\Rm (never defined)}"
+ if (j < sortcount)
+ print "@literal \\\\"
+}
+<<insert all chunk names into [[sortnames]]>>=
+delete defns[0]
+for (c in defns) insertchunk(c)
+delete uses[0]
+for (c in uses) if (!(c in defns)) insertchunk(c)
+@
+<<function definitions>>=
+function escapeTeXspecials(name, l, r) {
+ r = name
+ l = ""
+ while (match(r, /[{}$%&#^_~\\]/) > 0) {
+ l = l substr(r, 1, RSTART-1) "\\" substr(r, RSTART, 1)
+ r = substr(r, RSTART+1)
+ }
+ return l r
+}
+@
+\subsection{List of chunk names}
+\nowebchunks
diff --git a/web/noweb/src/lib/noxref.sh b/web/noweb/src/lib/noxref.sh
new file mode 100644
index 0000000000..da09c46a55
--- /dev/null
+++ b/web/noweb/src/lib/noxref.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+nawk 'BEGIN { defns[0] = 0 ; uses[0] = 0 ; dcounts[0] = 0 ; firstdef[0] = 0;
+ ucounts[0] = 0 ; idtable[0] = 0 ; keycounts[0] = 0 ; firstdefnout[0] = 0;
+ filetable[0] = 0 }
+{ lines[nextline++] = $0 }
+/^@defn / { logname("DEFN", defns, dcounts, substr($0, 7)) }
+/^@use / { logname("USE", uses, ucounts, substr($0, 6)) }
+/^@file / { curfile = modid(substr($0, 7)) }
+
+function logname(which, tbl, counts, name, id) {
+ counts[name] = counts[name] + 1
+ id = which curfile "-" modid(name) "-" counts[name]
+ tbl[name] = tbl[name] id " "
+ lines[nextline++] = "@literal \\label{" id "}"
+ if (which == "DEFN" && firstdef[name] == "") firstdef[name] = id
+}
+
+function modid(name, key) {
+ if (idtable[name] == "") {
+ key = name
+ gsub(/[\[\]\\{} -]/, "*", key)
+ if (length(key) > 6) key = substr(key,1,3) substr(key, length(key)-2, 3)
+ keycounts[key] = keycounts[key] + 1
+ idtable[name] = key "-" keycounts[key]
+ }
+ return idtable[name]
+}
+
+END {
+ for (i=0; i < nextline; i++) {
+ name = substr(lines[i], 2)
+ name = substr(name, 1, index(name, " ")-1)
+ arg = substr(lines[i], length(name)+3)
+ if (name == "defn") {
+ thischunk = arg
+ printf "@defn %s~{\\footnotesize\\rm\\pageref{%s}}\n", arg, firstdef[arg]
+ } else if (name == "use") {
+ if (firstdef[arg] != "")
+ printf "@use %s~{\\footnotesize\\rm\\pageref{%s}}\n", arg, firstdef[arg]
+ else
+ printf "@use %s~{\\footnotesize\\rm (never defined)}\n", arg
+ } else if (name == "end") {
+ if (substr(arg, 1, 4) == "code" && firstdefnout[thischunk] == 0) {
+ firstdefnout[thischunk] = 1
+ n = split(defns[thischunk], a)
+ if (n > 1) {
+ printf "@literal \\alsodefined{"
+ for (j = 2; j <= n; j++)
+ printf "\\\\{%s}", a[j]
+ printf "}\n@nl\n"
+ }
+ if (uses[thischunk] != "") {
+ printf "@literal \\used{"
+ n = split(uses[thischunk], a)
+ for (j = 1; j <= n; j++)
+ printf "\\\\{%s}", a[j]
+ printf "}\n@nl\n"
+ } else
+ printf "@literal \\notused\n@nl\n"
+ }
+ print lines[i]
+ } else
+ print lines[i]
+ }
+}'
diff --git a/web/noweb/src/lib/nwmtime b/web/noweb/src/lib/nwmtime
new file mode 100755
index 0000000000..0d65b8a4b6
--- /dev/null
+++ b/web/noweb/src/lib/nwmtime
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# nwmtime -- emit defn of modification time of first file
+#
+
+eval 'exec perl -S $0 ${1+"$@"}'
+ if $running_under_some_shell;
+
+$first = 1;
+while(<>) {
+ print;
+ if ($first && /\@file\s*(\S+)/) {
+ $mtime_file = $1;
+ $first = 0;
+ }
+}
+
+if (!$first) {
+ my $filename = $mtime_file;
+ my $mtime;
+
+ # localtime if you really want local time...
+ $mtime = gmtime((stat $filename)[9]);
+ print <<EOF;
+\@begin code 000
+\@defn modification time of first \@file
+\@nl
+\@text $mtime
+\@nl
+\@end code 000
+EOF
+}
diff --git a/web/noweb/src/lib/pipedocs b/web/noweb/src/lib/pipedocs
new file mode 100755
index 0000000000..4205475a4f
--- /dev/null
+++ b/web/noweb/src/lib/pipedocs
@@ -0,0 +1,23 @@
+#!/bin/sh
+#
+# Copyright 1991 by Norman Ramsey. All rights reserved.
+# See file COPYRIGHT for more information.
+
+nawk '
+BEGIN {
+ rcsid = "$I$"
+ rcsname = "$Name $"
+ cmd = "sed '"'"'/^@begin docs /s/[0-9][0-9]*/0/'"'"' | |LIBDIR|/unmarkup | '"$*"' | |LIBDIR|/markup | grep -v '"'"'^@file $'"'"'"
+}
+/^@begin docs / { piping = 1 }
+{ if (piping)
+ print | cmd
+ else
+ print
+}
+/^@end docs / {
+ piping = 0
+ close(cmd)
+}'
+
+
diff --git a/web/noweb/src/lib/toascii b/web/noweb/src/lib/toascii
new file mode 100755
index 0000000000..7df1ee32fb
--- /dev/null
+++ b/web/noweb/src/lib/toascii
@@ -0,0 +1,131 @@
+#!/bin/sh
+delay=0 noindex=0
+for i do
+ case $i in
+ -delay) delay=1 ;;
+ -noindex) noindex=1 ;;
+ *) echo "This can't happen -- $i passed to toascii" 1>&2 ; exit 1 ;;
+ esac
+done
+awkfile=$(mktemp)
+textfile=$(mktemp)
+tagsfile=$(mktemp)
+export awkfile textfile tagsfile
+trap 'rm -f $awkfile $textfile $tagsfile' 0 1 2 10 14 15
+nawk 'BEGIN { textfile=ENVIRON["textfile"]
+ tagsfile=ENVIRON["tagsfile"] }
+ /^@begin code/ { ++secno }
+ /^@xref label/ { print $3, secno >tagsfile }
+ /^@((begin|end) (docs|code))/ { print >textfile }
+ /^@(text|nl|defn|use)/ { print >textfile }
+ /^@xref (ref|notused)/ { print >textfile }
+ /^@xref (begin|end)(defs|uses)/ { print >textfile }
+ /^@xref (def|use)item/ { print >textfile}
+ /^@xref ((begin|end)chunks)|(chunk(begin|use|defn|end))/ { print >textfile }
+ /^@index (begin|end)(defs|uses)/ { print >textfile }
+ /^@index (is(us|defin)ed)|((def|use)item)/ { print >textfile }
+ /^@index ((begin|end)index)|(entry(begin|use|defn|end))/ { print >textfile }'
+nawk 'BEGIN {
+ textfile = ENVIRON["textfile"]
+ tagsfile = ENVIRON["tagsfile"]
+ tfmt="detex | fmt -79"
+ cfmt="expand -4 | fold -75 | sed \"s/^/ /\""
+ xfmt="fold -75 | sed \"s/^/ /\""
+ zfmt="cat"
+ while (getline <tagsfile > 0)
+ tag[$1] = $2
+ close(tagsfile)
+ }
+ /^@begin docs/ { out = tfmt }
+ /^@end docs/ { close(out) }
+ /^@begin code/ { out = cfmt; code = 1; ++secno }
+ /^@end code/ { endcode(); close(out); printf "\n" }
+ /^@text/ { printf "%s", substr($0, 7) | out }
+ /^@nl/ { # printf "(->%s)", formatname(out) | out ;
+ printf "\n" | out }
+ /^@xref ref/ { lastxrefref = tag[substr($0, 11)] }
+ /^@defn/ { name = convquote(substr($0, 7))
+ printf "\n### %d ### %s%s=",
+ secno, chunkname(name, lastxrefref), defn[name]
+ defn[name] = "+" }
+ /^@use/ { name = convquote(substr($0, 6))
+ printf "%s", chunkname(name, lastxrefref) | out }
+ /^@xref begindefs/ { endcode()
+ printf "This definition continued in" | out }
+ /^@xref beginuses/ { endcode()
+ printf "This code used in" | out }
+ /^@xref notused/ { endcode()
+ print "This code not used in this document." | out }
+ /^@xref (def|use)item/ { addlist(tag[$3]) }
+ /^@xref end(defs|uses)/ { printlist() }
+ $0 ~ /^@index begindefs/ && !noindex {
+ endcode()
+ print "Defines:" | out }
+
+ $0 ~ /^@index isused/ && !noindex {
+ if (tag[$3] != lastxrefref) addlist(tag[$3]) }
+
+ $0 ~ /^@index defitem/ && !noindex {
+ printf " %s,", $3 | out
+ if (nlist == 0) printf " not used in this document.\n" | out
+ else { printf " used in" | out; printlist() } }
+ $0 ~ /^@index beginuses/ && !noindex { endcode(); printf "Uses" | out }
+ $0 ~ /^@index isdefined/ && !noindex { lastuse = tag[$3] }
+ $0 ~ /^@index useitem/ && !noindex { addlist(sprintf("%s %s", $3, lastuse)) }
+ $0 ~ /^@index enduses/ && !noindex { printlist() }
+ /^@xref beginchunks/ { close(out); out = zfmt
+ print "List of code chunks\n" | out }
+ /^@xref chunkbegin/ { name = convquote(substr($0, length($3) + 19))
+ printf "%s\n", chunkname(name, tag[$3]) | out }
+ /^@xref chunkuse/ { addlist(tag[$3]) }
+ /^@xref chunkdefn/ { }
+ /^@xref chunkend/ { if (nlist == 0)
+ print " Not used in this document." | out
+ else { printf " Used in" | out; printlist() } }
+ /^@xref endchunks/ { }
+ $0 ~ /^@index beginindex/ && !noindex { print "\nList of identifiers (defini" \
+ "tion in parentheses)\n" | out }
+ $0 ~ /^@index entrybegin/ && !noindex { name = substr($0, length($3 + 19))
+ lastdefn = tag[$3]
+ printf "%s: ", $4 | out }
+ $0 ~ /^@index entryuse/ && !noindex { addlist(tag[$3]) }
+ $0 ~ /^@index entrydefn/ && !noindex { }
+ $0 ~ /^@index entryend/ && !noindex { for (i = 1; i <= nlist; i++)
+ if (list[i] == lastdefn)
+ sub(/.*/, "(&)", list[i])
+ if (nlist == 0)
+ print "Not used." | out
+ else printlist() }
+ $0 ~ /^@index endindex/ && !noindex { }
+ /^@fatal / { exit 1 }
+ END {
+ close(out)
+ }
+ function endcode() {
+ if (code == 1) {
+ code = 0
+ close(out)
+ out = xfmt
+ printf "\n" | out } }
+ function addlist(s, i) {
+ for (i = 1; i <= nlist; i++)
+ if (s == list[i]) return
+ list[++nlist] = s }
+
+ function printlist( i) {
+ if (nlist == 1) printf " %s.\n", list[1] | out
+ else if (nlist == 2) printf " %s and %s.\n", list[1], list[2] | out
+ else {
+ for (i = 1; i < nlist; i++)
+ printf " %s,", list[i] | out
+ printf " and %s.\n", list[nlist] | out }
+ for (i in list) delete list[i]
+ nlist = 0 }
+ function convquote(s) { gsub(/\[\[|\]\]/, "", s); return s }
+ function chunkname(name, number) {
+ if (number == 0)
+ return sprintf("<%s>", name)
+ else
+ return sprintf("<%s %d>", name, number)
+ }' noindex=$noindex $textfile
+exit $?
diff --git a/web/noweb/src/lib/toascii.nw b/web/noweb/src/lib/toascii.nw
new file mode 100644
index 0000000000..c76a7fd2ff
--- /dev/null
+++ b/web/noweb/src/lib/toascii.nw
@@ -0,0 +1,262 @@
+[[Toascii]] is a [[noweb]] back end for formatting text as a plain ascii file.
+It was written by Phil Bewig (pbewig@netcom.com) on March 31, 1995, and
+contributed to Norman Ramsey's [[noweb]] literate programming system.
+@
+The main program is shown below. Option [[-delay]] is processed, for
+compatibility with other back ends, but ignored; since the initial document
+chunk used with [[-delay]] normally contains only [[TeX]] formatting commands
+in limbo, and since those commands will be deleted before formatting, there is
+no need to handle [[-delay]].
+<<toascii>>=
+#!/bin/sh
+delay=0 noindex=0
+for i do
+ case $i in
+ -delay) delay=1 ;;
+ -noindex) noindex=1 ;;
+ *) echo "This can't happen -- $i passed to toascii" 1>&2 ; exit 1 ;;
+ esac
+done
+<<arrange temporary files>>
+<<invoke first pass using parameter>>
+<<invoke second pass using parameter>>
+exit $?
+@ %def delay noindex
+[[Toascii]] uses two temporary files, one for storing the text between passes
+and one for communicating the conversion of labels to tags. The files are
+named here, and disposal of the file on exit from [[toascii]] is arranged.
+Also arranged here is a temporary file for storage of the awk program on an
+ugly system, as discussed below.
+<<arrange temporary files>>=
+awkfile=$(mktemp)
+textfile=$(mktemp)
+tagsfile=$(mktemp)
+export awkfile textfile tagsfile
+trap 'rm -f $awkfile $textfile $tagsfile' 0 1 2 10 14 15
+@ %def textfile tagsfile awkfile
+The actual formatting of the text, code, and index entries is done by various
+unix text processing commands in pipelines. There are four formatting pipes:
+tfmt, which formats text, cfmt, which formats code, xfmt, which formats index
+entries within the running text, and zfmt, which formats the lists of chunks
+and identifiers at the end of the text. The formatters established below are
+only suggestions, and may be modified to suit local taste (and the presence of
+various text processing commands on the local machine!); in particular, [[c]]
+programmers may want to format code with cb or indent. The sed patterns below
+insert four blank spaces at the beginning of the line.
+<<initialize formatters>>=
+tfmt="detex | fmt -79"
+cfmt="expand -4 | fold -75 | sed \"s/^/ /\""
+xfmt="fold -75 | sed \"s/^/ /\""
+zfmt="cat"
+@ %def tfmt cfmt xfmt zfmt
+Forgiving systems allow the awk program to be specified as a parameter to the
+awk interpreter; ugly systems require that it be placed in a temporary file.
+The chunks below implement both options.
+<<invoke first pass using parameter>>=
+nawk '<<first pass>>'
+<<invoke second pass using parameter>>=
+nawk '<<second pass>>' noindex=$noindex $textfile
+<<invoke first pass using file>>=
+cat > $awkfile << 'EOF'
+<<first pass>>
+EOF
+nawk -f $awkfile
+<<invoke second pass using file>>=
+cat > $awkfile << 'EOF'
+<<second pass>>
+EOF
+nawk -f $awkfile noindex=$noindex $textfile
+@
+The first pass is responsible for extracting [[label]]s and assigning them
+section numbers, which are used for cross-referencing in the second pass. The
+first pass also removes from the input file those lines which are not used by
+the second pass.
+<<first pass>>=
+BEGIN { textfile=ENVIRON["textfile"]
+ tagsfile=ENVIRON["tagsfile"] }
+/^@begin code/ { ++secno }
+/^@xref label/ { print $3, secno >tagsfile }
+/^@((begin|end) (docs|code))/ { print >textfile }
+/^@(text|nl|defn|use)/ { print >textfile }
+/^@xref (ref|notused)/ { print >textfile }
+/^@xref (begin|end)(defs|uses)/ { print >textfile }
+/^@xref (def|use)item/ { print >textfile}
+/^@xref ((begin|end)chunks)|(chunk(begin|use|defn|end))/ { print >textfile }
+/^@index (begin|end)(defs|uses)/ { print >textfile }
+/^@index (is(us|defin)ed)|((def|use)item)/ { print >textfile }
+/^@index ((begin|end)index)|(entry(begin|use|defn|end))/ { print >textfile }
+@
+The second pass performs formatting. After looking up the temp file names and
+formatters in the environment and reading the [[tagsfile]] created in the first
+pass, the second pass processes each input command in the body of the awk
+[[pattern-action]] processing loop.
+<<second pass>>=
+BEGIN {
+ textfile = ENVIRON["textfile"]
+ tagsfile = ENVIRON["tagsfile"]
+ <<initialize formatters>>
+ while (getline <tagsfile > 0)
+ tag[$1] = $2
+ close(tagsfile)
+}
+<<process [[noweb]] commands>>
+/^@fatal / { exit 1 }
+END {
+ close(out)
+}
+<<functions>>
+@ %def tag
+The rest of the program consists of a series of awk [[pattern-action]]
+statements which each process a particular type of [[noweb]] pipeline command.
+They are discussed in related groups, and all collected in a single chunk. We
+begin with the commands that process the text of the document and code chunks.
+The basic strategy is always write text to [[out]] and open and close various
+pipes as needed. Variable [[code]] is true only within code chunks, and
+[[secno]] numbers the sections as they appear. Function [[endcode()]] closes
+the code pipeline at the end of a code section or whenever the first indexing
+command appears.
+<<process [[noweb]] commands>>=
+/^@begin docs/ { out = tfmt }
+/^@end docs/ { close(out) }
+/^@begin code/ { out = cfmt; code = 1; ++secno }
+/^@end code/ { endcode(); close(out); printf "\n" }
+/^@text/ { printf "%s", substr($0, 7) | out }
+/^@nl/ { # printf "(->%s)", formatname(out) | out ;
+ printf "\n" | out }
+@ %def out secno code
+<<functions>>=
+function endcode() {
+ if (code == 1) {
+ code = 0
+ close(out)
+ out = xfmt
+ printf "\n" | out } }
+@ %def endcode
+Definitions and uses of code chunks are handled below. Variable [[defn[name]]]
+is set to a plus sign after a definition is printed, so that continuations of
+the definition are properly identified. Variable [[lastxrefref]] is the tag
+associated with the most-recently-seen cross-reference label, and refers to the
+section number of the original definition of the code chunk. Definition lines
+are printed directly, without passing through any of the formatters defined
+above.
+<<process [[noweb]] commands>>=
+/^@xref ref/ { lastxrefref = tag[substr($0, 11)] }
+/^@defn/ { name = convquote(substr($0, 7))
+ printf "\n### %d ### %s%s=",
+ secno, chunkname(name, lastxrefref), defn[name]
+ defn[name] = "+" }
+/^@use/ { name = convquote(substr($0, 6))
+ printf "%s", chunkname(name, lastxrefref) | out }
+@ %def lastxref name defn
+There are three messages related to the definition and use of code chunks which
+may appear in the output: "This definition continued in ...", "This code used
+in ...", and "This code not used in this document." These messages are printed
+by the following code.
+<<process [[noweb]] commands>>=
+/^@xref begindefs/ { endcode()
+ printf "This definition continued in" | out }
+/^@xref beginuses/ { endcode()
+ printf "This code used in" | out }
+/^@xref notused/ { endcode()
+ print "This code not used in this document." | out }
+/^@xref (def|use)item/ { addlist(tag[$3]) }
+/^@xref end(defs|uses)/ { printlist() }
+@
+Processing of the [[noweb]] commands which produce the identifier definition
+message "Defines: ... used in ..." is performed by the following code. The
+[[if]] in [[@index isused]] prevents index definitions from pointing to
+themselves.
+<<process [[noweb]] commands>>=
+$0 ~ /^@index begindefs/ && !noindex {
+ endcode()
+ print "Defines:" | out }
+
+$0 ~ /^@index isused/ && !noindex {
+ if (tag[$3] != lastxrefref) addlist(tag[$3]) }
+
+$0 ~ /^@index defitem/ && !noindex {
+ printf " %s,", $3 | out
+ if (nlist == 0) printf " not used in this document.\n" | out
+ else { printf " used in" | out; printlist() } }
+@
+Processing of the [[noweb]] commands which produce the identifier usage message
+"Uses ..." is performed by the following code.
+<<process [[noweb]] commands>>=
+$0 ~ /^@index beginuses/ && !noindex { endcode(); printf "Uses" | out }
+$0 ~ /^@index isdefined/ && !noindex { lastuse = tag[$3] }
+$0 ~ /^@index useitem/ && !noindex { addlist(sprintf("%s %s", $3, lastuse)) }
+$0 ~ /^@index enduses/ && !noindex { printlist() }
+@ %def lastuse
+The [[noweb]] commands which print the list of chunks at the end of the
+document are processed by the following code.
+<<process [[noweb]] commands>>=
+/^@xref beginchunks/ { close(out); out = zfmt
+ print "List of code chunks\n" | out }
+/^@xref chunkbegin/ { name = convquote(substr($0, length($3) + 19))
+ printf "%s\n", chunkname(name, tag[$3]) | out }
+/^@xref chunkuse/ { addlist(tag[$3]) }
+/^@xref chunkdefn/ { }
+/^@xref chunkend/ { if (nlist == 0)
+ print " Not used in this document." | out
+ else { printf " Used in" | out; printlist() } }
+/^@xref endchunks/ { }
+@
+The [[noweb]] commands which print the list of identifiers at the end of the
+document are processed by the following code.
+<<process [[noweb]] commands>>=
+$0 ~ /^@index beginindex/ && !noindex { print "\nList of identifiers (defini" \
+ "tion in parentheses)\n" | out }
+$0 ~ /^@index entrybegin/ && !noindex { name = substr($0, length($3 + 19))
+ lastdefn = tag[$3]
+ printf "%s: ", $4 | out }
+$0 ~ /^@index entryuse/ && !noindex { addlist(tag[$3]) }
+$0 ~ /^@index entrydefn/ && !noindex { }
+$0 ~ /^@index entryend/ && !noindex { for (i = 1; i <= nlist; i++)
+ if (list[i] == lastdefn)
+ sub(/.*/, "(&)", list[i])
+ if (nlist == 0)
+ print "Not used." | out
+ else printlist() }
+$0 ~ /^@index endindex/ && !noindex { }
+@
+Several of the cross-reference and indexing commands use the [[addlist(s)]] and
+[[printlist()]] functions to manage the printing of lists of code sections and
+variable names: [[addlist(s)]] adds string [[s]] to a queued [[list]] waiting
+to be printed and [[printlist()]] prints the [[list]], appropriately formatted
+with commas. These two functions are described below.
+<<functions>>=
+function addlist(s, i) {
+ for (i = 1; i <= nlist; i++)
+ if (s == list[i]) return
+ list[++nlist] = s }
+
+function printlist( i) {
+ if (nlist == 1) printf " %s.\n", list[1] | out
+ else if (nlist == 2) printf " %s and %s.\n", list[1], list[2] | out
+ else {
+ for (i = 1; i < nlist; i++)
+ printf " %s,", list[i] | out
+ printf " and %s.\n", list[nlist] | out }
+ for (i in list) delete list[i]
+ nlist = 0 }
+@ %def list nlist addlist printlist
+Chunk names which appear in definitions and uses of chunks consist of text
+which may contain quoted code embedded between double square brackets. Quoted
+code in text chunks are handled by the [[@quote ... @endquote]] mechanism, but
+quoted code in chunk names must be handled explicitly by the back end. The
+function below does what is needed.
+<<functions>>=
+function convquote(s) { gsub(/\[\[|\]\]/, "", s); return s }
+@ %def convquote
+
+<<functions>>=
+function chunkname(name, number) {
+ if (number == 0)
+ return sprintf("<%s>", name)
+ else
+ return sprintf("<%s %d>", name, number)
+}
+@ %def chunkname
+@
+<nowebchunks>
+<nowebindex>
diff --git a/web/noweb/src/lib/unmarkup b/web/noweb/src/lib/unmarkup
new file mode 100755
index 0000000000..761fc14897
--- /dev/null
+++ b/web/noweb/src/lib/unmarkup
@@ -0,0 +1,48 @@
+#!/bin/sh
+#
+# Copyright 1991 by Norman Ramsey. All rights reserved.
+# See file COPYRIGHT for more information.
+
+nawk '
+BEGIN {
+ rcsid = "$Id: unmarkup,v 1.20 2008/10/06 01:03:05 nr Exp $"
+ rcsname = "$Name: $"
+ firstdoc = 1
+}
+/^@begin docs / { if (!firstdoc) printf "@ "; firstdoc = 0 }
+/^@begin code / { code = 1 }
+/^@end [cd]o[dc][es] / {
+ code = 0
+ if (dangling_text) printf "\n"
+ dangling_text = 0
+ printf "%s", deflines
+ if (defline != "") printf "%s\n", defline
+ deflines = "" ; defline = ""
+ }
+/^@defn / { printf "<<%s>>=", substr($0,7) }
+/^@text $/ {next}
+/^@text / {
+ gsub("<<", "@<<");
+ gsub(">>", "@>>");
+ if (!(code || quoting)) {
+ gsub(/\[\[/, "@[[");
+ gsub(/\]\]/, "@]]");
+ }
+ printf "%s", substr($0,7)
+ dangling_text = 1
+}
+/^@quote$/ { printf("[["); dangling_text = 1; quoting = 1 }
+/^@endquote$/ { printf("]]"); dangling_text = 1; quoting = 0 }
+/^@nl$/ { printf "\n"; dangling_text = 0}
+
+/^@index defn / {
+ if (defline == "") defline = "@ %def"
+ defline = defline " " substr($0, 13)
+}
+/^@index nl$/ {
+ deflines = deflines defline "\n"
+ defline = ""
+}
+/^@use / { printf "<<%s>>", substr($0,6)
+ dangling_text = 1
+ }' "$@" | sed 's/^@ $/@/'