From ce532708e572c8c34bc3cde382424b1b0bf7dd72 Mon Sep 17 00:00:00 2001
From: ram <ram>
Date: Fri, 25 Jan 1991 12:32:32 +0000
Subject: [PATCH] Initial revision

---
 docs/database/dbolio.lib        |  324 +++
 docs/database/hem.lib           |   71 +
 docs/database/outtir.lib        |  329 +++
 docs/database/spice.lib         |   67 +
 docs/database/spicer.fon        |  230 ++
 docs/database/table.lib         |   27 +
 docs/database/uttir.lib         |  329 +++
 docs/doc-diff.lisp              |  384 +++
 docs/hem/cim/aux-sys.mss        |  682 +++++
 docs/hem/cim/cim.mss            | 4003 +++++++++++++++++++++++++++++
 docs/hem/hem-docs.log           |   43 +
 docs/hem/hem.dict               |  446 ++++
 docs/hem/user/commands.mss      |  822 ++++++
 docs/hem/user/intro.mss         | 1053 ++++++++
 docs/hem/user/lisp.mss          |  697 ++++++
 docs/hem/user/mail.mss          | 1346 ++++++++++
 docs/hem/user/special-modes.mss |  725 ++++++
 docs/hem/user/user.mss          | 1958 +++++++++++++++
 docs/rtguts.mss                 | 4150 +++++++++++++++++++++++++++++++
 19 files changed, 17686 insertions(+)
 create mode 100644 docs/database/dbolio.lib
 create mode 100644 docs/database/hem.lib
 create mode 100644 docs/database/outtir.lib
 create mode 100644 docs/database/spice.lib
 create mode 100644 docs/database/spicer.fon
 create mode 100644 docs/database/table.lib
 create mode 100644 docs/database/uttir.lib
 create mode 100644 docs/doc-diff.lisp
 create mode 100644 docs/hem/cim/aux-sys.mss
 create mode 100644 docs/hem/cim/cim.mss
 create mode 100644 docs/hem/hem-docs.log
 create mode 100644 docs/hem/hem.dict
 create mode 100644 docs/hem/user/commands.mss
 create mode 100644 docs/hem/user/intro.mss
 create mode 100644 docs/hem/user/lisp.mss
 create mode 100644 docs/hem/user/mail.mss
 create mode 100644 docs/hem/user/special-modes.mss
 create mode 100644 docs/hem/user/user.mss
 create mode 100644 docs/rtguts.mss

diff --git a/docs/database/dbolio.lib b/docs/database/dbolio.lib
new file mode 100644
index 000000000..2ee721a1c
--- /dev/null
+++ b/docs/database/dbolio.lib
@@ -0,0 +1,324 @@
+@Marker(Library, DBOLIO, Press, Dover, Postscript)
+
+
+@Modify(Chapter,TitleForm 
+{@Begin(Hd1A, Below 0.8 in)@Skip(0.8 in)@*Chapter @Parm(Numbered)@*@Skip(0.3 in)@*@Parm(Title)@End(Hd1A)},
+	ContentsForm
+{@Begin(Tc1)@Rfstr(@Parm(Page))@Parm(Referenced)@.@ @Parm(Title)@End(Tc1)},
+	  Numbered [@1],IncrementedBy Use,Referenced [@1],Announced)
+@Modify(Appendix,TitleEnv HD1,ContentsEnv tc1,Numbered [@A.],
+	 ContentsForm "@Tc1(Appendix @Parm(Referenced)@.@ @Rfstr(@Parm(Page))@parm(Title))",
+	 TitleForm "@Hd1(@=Appendix @Parm(Referenced)@*@=@Parm(Title))",
+	  IncrementedBy,Referenced [@A],Announced) @Comment{Alias Chapter}
+@Define(F, Facecode F)
+@Define(Sail, Facecode U)
+@Define(Arrow, Facecode N)
+@Commandstring(Minussign = "")
+@Commandstring(Centerdot = "@Begin(W, script +0.4 quad).@End(W)")
+@Commandstring(Tilde = "@Begin(W, script +0.4 quad)~@End(W)")
+@Commandstring(Underscore = "_")
+@Commandstring(Bq = "@;`")
+@Form(Complex = "@f[#C(@Parm(R) @Parm(I))]")
+@Textform(Altmode = "<altmode>")
+@Define(DenseDescription = Description, Spread .3)
+@Define(Defenvironment = Text, Need 4, Nofill, Justification Off, Break,
+		Above 2, Below 2, Spread 0.5)
+@Define(Defbody = Text, Leftmargin +.6in, Indent 0, Spread 0.5, Break)
+@Define(Undefbody = Text, Nofill, Justification Off, Leftmargin -.6in,
+		Above 0, Below 0, Group, Break)
+@Define(Lispenvironment = Verbatim, Group, Leftmargin +.3in, Above .5, Below .5)
+@Commandstring(Nopara = "@Begin(Text, Continue Force)@End(Text)")
+@Commandstring(Optional = "@f[&optional]")
+@Commandstring(Rest = "@f[&rest]")
+@Commandstring(Key = "@f[&key]")
+@Commandstring(allowotherkeys = "@f[&allow-other-keys]")
+@Commandstring(Aux = "@f[&aux]")
+@Commandstring(Body = "@f[&body]")
+@Commandstring(Whole = "@f[&whole]")
+@Commandstring(Special = "@f[&special]")
+@Commandstring(Local = "@f[&local]")
+@Textform(Mopt = "@r{[}@Parm(Text)@r{]}")
+@Textform(Mgroup = "@r[{]@Parm(Text)@r[}]")
+@Textform(Mstar = "@r[{]@Parm(Text)@r[}*]")
+@Textform(Mplus = "@r[{]@Parm(Text)@r[}@+[+]]")
+@Commandstring(Mor = "@r[|]")
+@Commandstring(Lisp = "@Begin(Lispenvironment)@~")
+@Commandstring(Endlisp = "@End(Lispenvironment)")
+@Commandstring(Lispx = "@Begin(Text, Indent 0, Above .5)For example:@End(Text)@Lisp")
+@Comment{
+ @Commandstring(EQ = "@Arrow[J]")
+ @Commandstring(EV = "@Arrow[A]")
+ @Commandstring(EX = "@Arrow[G]")
+}
+ @Commandstring(EQ = "@f[<=>]")
+ @Commandstring(EV = "@f[=>]")
+ @Commandstring(EX = "@f[==>]")
+@Commandstring(lbracket = "@f{[}")
+@Commandstring(rbracket = "@f{]}")
+@Commandstring(lbrace = "@f[{]")
+@Commandstring(rbrace = "@f[}]")
+@define(subi = i)
+@define(subr = r)
+@define(superi = i)
+@define(supersail = sail)
+@define(superg = g)
+@commandstring(superminussign = "@minussign@;")
+@commandstring(supercenterdot = "@centerdot@;")
+@Commandstring(false = "@f[nil]")
+@Commandstring(nil = "@f[nil]")
+@Commandstring(empty = "@f[()]")
+@Commandstring(true = "@f[t]")
+@Commandstring(xlisp = "@r[L@c[isp]]")
+@Commandstring(clisp = "@r[C@c[ommon]] @xlisp")
+@Commandstring(lmlisp = "@PossiblyIndexedRef(K <ZetaLisp>,
+		E <@r[Z@c[eta]@xlisp]>, F <@r[Z@c[eta]@xlisp]>)")
+@Commandstring(newlisp = "@PossiblyIndexedRef(K <NIL>,
+		E <@r[N@c[il]]>, F <@r[N@c[il] (New Implementation of @xlisp]>)")
+@Commandstring(slisp = "@PossiblyIndexedRef(K <Spice LISP>,
+		E <@r[S@c[pice]] @xlisp>, F <@r[S@c[pice]] @xlisp>)")
+@Commandstring(lisp15 = "@PossiblyIndexedRef(K <Lisp 1.5>,
+		E <@xlisp @r[1.5]>, F <@xlisp @r[1.5]>)")
+@Commandstring(maclisp = "@PossiblyIndexedRef(K <MacLISP>,
+		E <@r[M@c[ac]]@xlisp>, F <@r[M@c[ac]]@xlisp>)")
+@Commandstring(franzlisp = "@PossiblyIndexedRef(K <Franz LISP>,
+		E <@r[F@c[ranz]] @xlisp>, F <@r[F@c[ranz]] @xlisp>)")
+@Commandstring(interlisp = "@PossiblyIndexedRef(K <InterLISP>,
+		E <@r[I@c[nter]]@xlisp>, F <@r[I@c[nter]]@xlisp>)")
+@Commandstring(stdlisp = "@PossiblyIndexedRef(K <Standard LISP>,
+		E <@r[S@c[tandard]] @xlisp>, F <@r[S@c[tandard]] @xlisp>)")
+@Commandstring(psl = "@PossiblyIndexedRef(K <Portable Standard LISP>,
+		E <@r[P@c[ortable] S@c[tandard]] @xlisp>, F <@r[P@c[ortable] S@c[tandard]] @xlisp>)")
+@Commandstring(s1lisp = "@PossiblyIndexedRef(K <S-1 Lisp>,
+		E <@r[S-1] @xlisp>, F <@r[S-1] @xlisp>)")
+@Commandstring(scheme = "@PossiblyIndexedRef(K <scheme>,
+		E <@r[S@c[cheme]]>, F <@r[S@c[cheme]]>)")
+@Commandstring(fortran = "@PossiblyIndexedRef(K <Fortran>,
+		E <@c[fortran]>, F <@c[fortran]>)")
+@Commandstring(algol = "@PossiblyIndexedRef(K <Algol>,
+		E <@c[algol]>, F <@c[algol]>)")
+@Commandstring(pascal = "@PossiblyIndexedRef(K <Pascal>,
+		E <@c[pascal]>, F <@c[pascal]>)")
+@Commandstring(ada = "@PossiblyIndexedRef(K <ADA>,
+		E <@c[ada]>, F <@c[ada]>)")
+@Commandstring(apl = "@PossiblyIndexedRef(K <APL>,
+		E <@c[apl]>, F <@c[apl]>)")
+@Commandstring(pl1 = "@PossiblyIndexedRef(K <PL/I>,
+		E <@c[pl/i]>, F <@c[pl/i]>)")
+@Commandstring(clanguage = "@PossiblyIndexedRef(K <C>,
+		E <@c[c]>, F <@c[c] language>)")
+@Define(Smallitemize=Itemize, Spread 0.5, Above 0.5, Below 0.5)
+
+@Marker(Library, DBOLIO, File)
+
+
+@Style(Justification Off)
+@Style(Linewidth 7.2 Inches)
+@Style(Indentation 0)
+@Modify(Chapter,TitleForm 
+{@Begin(Hd1A, Below 0.8 in)@Skip(0.8 in)@*Chapter @Parm(Numbered)@*@Skip(0.3 in)@*@Parm(Title)@End(Hd1A)},
+	ContentsForm
+{@Begin(Tc1)@Rfstr(@Parm(Page))@Parm(Referenced)@.@ @Parm(Title)@End(Tc1)},
+	  Numbered [@1],IncrementedBy Use,Referenced [@1],Announced)
+@Modify(Appendix,TitleEnv HD1,ContentsEnv tc1,Numbered [@A.],
+	 ContentsForm "@Tc1(Appendix @Parm(Referenced)@.@ @Rfstr(@Parm(Page))@parm(Title))",
+	 TitleForm "@Hd1(@=Appendix @Parm(Referenced)@*@=@Parm(Title))",
+	  IncrementedBy,Referenced [@A],Announced) @Comment{Alias Chapter}
+@Define(F, Capitalized)
+@Define(A, Initialize "[APL]")
+@Define(Sail = R)
+@Define(B = R)
+@Commandstring(Minussign = "-")
+@Commandstring(Tilde = "~")
+@Commandstring(Centerdot = ".")
+@Commandstring(Underscore = "_")
+@Commandstring(Bq = "@;`")
+@Form(Complex = "@f[#C(@Parm(R) @Parm(I))]")
+@Textform(Altmode = "$")
+@Define(DenseDescription = Description, Spread 0)
+@Define(Defenvironment = Text, Need 4, Nofill, Justification Off, Break,
+		Leftmargin +12, Indent -12, Above 2, Below 2, Spread 0.5)
+@Define(Defbody = Text, Leftmargin -6in, Indent 0, Spread 0.5, Break)
+@Define(Undefbody = Text, Justification Off, Leftmargin +6, Indent -12,
+		Above 0, Below 0, Group, Break)
+@Define(Lispenvironment = Verbatim, Group, Leftmargin +.5in, Above 1, Below 1)
+@Commandstring(Nopara = "@Begin(Text, Continue Force)@End(Text)")
+@Commandstring(Optional = "@f[&optional]")
+@Commandstring(Rest = "@f[&rest]")
+@Commandstring(Key = "@f[&key]")
+@Commandstring(allowotherkeys = "@f[&allow-other-keys]")
+@Commandstring(Aux = "@f[&aux]")
+@Commandstring(Body = "@f[&body]")
+@Commandstring(Whole = "@f[&whole]")
+@Commandstring(Special = "@f[&special]")
+@Commandstring(Local = "@f[&local]")
+@Textform(Mopt = "@r{[}@Parm(Text)@r{]}")
+@Textform(Mgroup = "@r[{]@Parm(Text)@r[}]")
+@Textform(Mstar = "@r[{]@Parm(Text)@r[}*]")
+@Textform(Mplus = "@r[{]@Parm(Text)@r[}@+[+]]")
+@Commandstring(Mor = "@r[|]")
+@Commandstring(Lisp = "@Begin(Lispenvironment)@~")
+@Commandstring(Endlisp = "@End(Lispenvironment)")
+@Commandstring(Lispx = "@Begin(Text, Indent 0, Above 0)For example:@End(Text)@Lisp")
+@Commandstring(EQ = "==")
+@Commandstring(EV = "->")
+@Commandstring(EX = "<=>")
+@Commandstring(lbracket = "@f{[}")
+@Commandstring(rbracket = "@f{]}")
+@Commandstring(lbrace = "@f[{]")
+@Commandstring(rbrace = "@f[}]")
+@define(subi = i)
+@define(subr = r)
+@define(superi = i)
+@define(supersail = sail)
+@define(superg = g)
+@commandstring(superminussign = "@minussign@;")
+@commandstring(supercenterdot = "@centerdot@;")
+@Commandstring(false = "@f[nil]")
+@Commandstring(nil = "@f[nil]")
+@Commandstring(empty = "@f[()]")
+@Commandstring(true = "@f[t]")
+@Commandstring(xlisp = "@r[L@c[isp]]")
+@Commandstring(clisp = "@r[C@c[ommon]] @xlisp")
+@Commandstring(lmlisp = "@PossiblyIndexedRef(K <ZetaLisp>,
+		E <@r[Z@c[eta]@xlisp]>, F <@r[Z@c[eta]@xlisp]>)")
+@Commandstring(newlisp = "@PossiblyIndexedRef(K <NIL>,
+		E <@r[N@c[il]]>, F <@r[N@c[il] (New Implementation of @xlisp]>)")
+@Commandstring(slisp = "@PossiblyIndexedRef(K <Spice LISP>,
+		E <@r[S@c[pice]] @xlisp>, F <@r[S@c[pice]] @xlisp>)")
+@Commandstring(lisp15 = "@PossiblyIndexedRef(K <Lisp 1.5>,
+		E <@xlisp @r[1.5]>, F <@xlisp @r[1.5]>)")
+@Commandstring(maclisp = "@PossiblyIndexedRef(K <MacLISP>,
+		E <@r[M@c[ac]]@xlisp>, F <@r[M@c[ac]]@xlisp>)")
+@Commandstring(franzlisp = "@PossiblyIndexedRef(K <Franz LISP>,
+		E <@r[F@c[ranz]] @xlisp>, F <@r[F@c[ranz]] @xlisp>)")
+@Commandstring(interlisp = "@PossiblyIndexedRef(K <InterLISP>,
+		E <@r[I@c[nter]]@xlisp>, F <@r[I@c[nter]]@xlisp>)")
+@Commandstring(stdlisp = "@PossiblyIndexedRef(K <Standard LISP>,
+		E <@r[S@c[tandard]] @xlisp>, F <@r[S@c[tandard]] @xlisp>)")
+@Commandstring(psl = "@PossiblyIndexedRef(K <Portable Standard LISP>,
+		E <@r[P@c[ortable] S@c[tandard]] @xlisp>, F <@r[P@c[ortable] S@c[tandard]] @xlisp>)")
+@Commandstring(s1lisp = "@PossiblyIndexedRef(K <S-1 Lisp>,
+		E <@r[S-1] @xlisp>, F <@r[S-1] @xlisp>)")
+@Commandstring(scheme = "@PossiblyIndexedRef(K <scheme>,
+		E <@c[scheme]>, F <@c[scheme]>)")
+@Commandstring(fortran = "@PossiblyIndexedRef(K <Fortran>,
+		E <@c[fortran]>, F <@c[fortran]>)")
+@Commandstring(algol = "@PossiblyIndexedRef(K <Algol>,
+		E <@c[algol]>, F <@c[algol]>)")
+@Commandstring(pascal = "@PossiblyIndexedRef(K <Pascal>,
+		E <@c[pascal]>, F <@c[pascal]>)")
+@Commandstring(ada = "@PossiblyIndexedRef(K <ADA>,
+		E <@c[ada]>, F <@c[ada]>)")
+@Commandstring(apl = "@PossiblyIndexedRef(K <APL>,
+		E <@c[apl]>, F <@c[apl]>)")
+@Commandstring(pl1 = "@PossiblyIndexedRef(K <PL/I>,
+		E <@c[pl/i]>, F <@c[pl/i]>)")
+@Commandstring(clanguage = "@PossiblyIndexedRef(K <C>,
+		E <@c[c]>, F <@c[c] language>)")
+@Define(Smallitemize=Itemize, Spread 0, Above 0, Below 0)
+
+@Marker(Library, DBOLIO)
+
+
+@Modify(Chapter,TitleForm 
+{@Begin(Hd1A, Below 0.8 in)@Skip(0.8 in)@*Chapter @Parm(Numbered)@*@Skip(0.3 in)@*@Parm(Title)@End(Hd1A)},
+	ContentsForm
+{@Begin(Tc1)@Rfstr(@Parm(Page))@Parm(Referenced)@.@ @Parm(Title)@End(Tc1)},
+	  Numbered [@1],IncrementedBy Use,Referenced [@1],Announced)
+@Modify(Appendix,TitleEnv HD1,ContentsEnv tc1,Numbered [@A.],
+	 ContentsForm "@Tc1(Appendix @Parm(Referenced)@.@ @Rfstr(@Parm(Page))@parm(Title))",
+	 TitleForm "@Hd1(@=Appendix @Parm(Referenced)@*@=@Parm(Title))",
+	  IncrementedBy,Referenced [@A],Announced) @Comment{Alias Chapter}
+@Define(F, Capitalized)
+@Define(A, Initialize "[APL]")
+@Define(Sail = R)
+@Define(B = R)
+@Commandstring(Minussign = "-")
+@Commandstring(Tilde = "~")
+@Commandstring(Centerdot = ".")
+@Commandstring(Underscore = "_")
+@Commandstring(Bq = "@;`")
+@Form(Complex = "@f[#C(@Parm(R) @Parm(I))]")
+@Textform(Altmode = "<altmode>")
+@Define(DenseDescription = Description, Spread 0)
+@Define(Defenvironment = Text, Need 4, Nofill, Justification Off, Break,
+		Leftmargin +12, Indent -12, Above 2, Below 2, Spread 0.5)
+@Define(Defbody = Text, Leftmargin -6, Indent 0, Spread 0.5, Break)
+@Define(Undefbody = Text, Justification Off, Leftmargin +6, Indent -12,
+		Above 0, Below 0, Group, Break)
+@Define(Lispenvironment = Verbatim, Group, Leftmargin +4, Above 1, Below 1)
+@Commandstring(Nopara = "@Begin(Text, Continue Force)@End(Text)")
+@Commandstring(Optional = "@f[&optional]")
+@Commandstring(Rest = "@f[&rest]")
+@Commandstring(Key = "@f[&key]")
+@Commandstring(allowotherkeys = "@f[&allow-other-keys]")
+@Commandstring(Aux = "@f[&aux]")
+@Commandstring(Body = "@f[&body]")
+@Commandstring(Whole = "@f[&whole]")
+@Commandstring(Special = "@f[&special]")
+@Commandstring(Local = "@f[&local]")
+@Textform(Mopt = "@r{[}@Parm(Text)@r{]}")
+@Textform(Mgroup = "@r[{]@Parm(Text)@r[}]")
+@Textform(Mstar = "@r[{]@Parm(Text)@r[}*]")
+@Textform(Mplus = "@r[{]@Parm(Text)@r[}@+[+]]")
+@Commandstring(Mor = "@r[|]")
+@Commandstring(Lisp = "@Begin(Lispenvironment)@~")
+@Commandstring(Endlisp = "@End(Lispenvironment)")
+@Commandstring(Lispx = "@Begin(Text, Indent 0, Above 0)For example:@End(Text)@Lisp")
+@Commandstring(EQ = "==")
+@Commandstring(EV = "->")
+@Commandstring(EX = "<=>")
+@Commandstring(lbracket = "@f{[}")
+@Commandstring(rbracket = "@f{]}")
+@Commandstring(lbrace = "@f[{]")
+@Commandstring(rbrace = "@f[}]")
+@define(subi = i)
+@define(subr = r)
+@define(superi = i)
+@define(supersail = sail)
+@define(superg = g)
+@commandstring(superminussign = "@minussign@;")
+@commandstring(supercenterdot = "@centerdot@;")
+@Commandstring(false = "@f[nil]")
+@Commandstring(nil = "@f[nil]")
+@Commandstring(empty = "@f[()]")
+@Commandstring(true = "@f[t]")
+@Commandstring(xlisp = "@r[L@c[isp]]")
+@Commandstring(clisp = "@r[C@c[ommon]] @xlisp")
+@Commandstring(lmlisp = "@PossiblyIndexedRef(K <ZetaLisp>,
+		E <@r[Z@c[eta]@xlisp]>, F <@r[Z@c[eta]@xlisp]>)")
+@Commandstring(newlisp = "@PossiblyIndexedRef(K <NIL>,
+		E <@r[N@c[il]]>, F <@r[N@c[il] (New Implementation of @xlisp)]>)")
+@Commandstring(slisp = "@PossiblyIndexedRef(K <Spice LISP>,
+		E <@r[S@c[pice]] @xlisp>, F <@r[S@c[pice]] @xlisp>)")
+@Commandstring(lisp15 = "@PossiblyIndexedRef(K <Lisp 1.5>,
+		E <@xlisp @r[1.5]>, F <@xlisp @r[1.5]>)")
+@Commandstring(maclisp = "@PossiblyIndexedRef(K <MacLISP>,
+		E <@r[M@c[ac]]@xlisp>, F <@r[M@c[ac]]@xlisp>)")
+@Commandstring(franzlisp = "@PossiblyIndexedRef(K <Franz LISP>,
+		E <@r[F@c[ranz]] @xlisp>, F <@r[F@c[ranz]] @xlisp>)")
+@Commandstring(interlisp = "@PossiblyIndexedRef(K <InterLISP>,
+		E <@r[I@c[nter]]@xlisp>, F <@r[I@c[nter]]@xlisp>)")
+@Commandstring(stdlisp = "@PossiblyIndexedRef(K <Standard LISP>,
+		E <@r[S@c[tandard]] @xlisp>, F <@r[S@c[tandard]] @xlisp>)")
+@Commandstring(psl = "@PossiblyIndexedRef(K <Portable Standard LISP>,
+		E <@r[P@c[ortable] S@c[tandard]] @xlisp>, F <@r[P@c[ortable] S@c[tandard]] @xlisp>)")
+@Commandstring(s1lisp = "@PossiblyIndexedRef(K <S-1 Lisp>,
+		E <@r[S-1] @xlisp>, F <@r[S-1] @xlisp>)")
+@Commandstring(scheme = "@PossiblyIndexedRef(K <scheme>,
+		E <@c[scheme]>, F <@c[scheme]>)")
+@Commandstring(fortran = "@PossiblyIndexedRef(K <Fortran>,
+		E <@c[fortran]>, F <@c[fortran]>)")
+@Commandstring(algol = "@PossiblyIndexedRef(K <Algol>,
+		E <@c[algol]>, F <@c[algol]>)")
+@Commandstring(pascal = "@PossiblyIndexedRef(K <Pascal>,
+		E <@c[pascal]>, F <@c[pascal]>)")
+@Commandstring(ada = "@PossiblyIndexedRef(K <ADA>,
+		E <@c[ada]>, F <@c[ada]>)")
+@Commandstring(apl = "@PossiblyIndexedRef(K <APL>,
+		E <@c[apl]>, F <@c[apl]>)")
+@Commandstring(pl1 = "@PossiblyIndexedRef(K <PL/I>,
+		E <@c[pl/i]>, F <@c[pl/i]>)")
+@Commandstring(clanguage = "@PossiblyIndexedRef(K <C>,
+		E <@c[c]>, F <@c[c] language>)")
+@Define(Smallitemize=Itemize, Spread 0, Above 0, Below 0)
diff --git a/docs/database/hem.lib b/docs/database/hem.lib
new file mode 100644
index 000000000..f3b5721e8
--- /dev/null
+++ b/docs/database/hem.lib
@@ -0,0 +1,71 @@
+@marker(library, Hem, Press, Dover, Postscript)
+
+@Form(Defhvar = "@Begin(Defenvironment)@Comment(Tabset?)@~
+   @hid[@Parm(Var)]@imbed(val, def <@ @ (initial value @f[@parm(val)])>)@>[@i[@Hemlock Variable]]@\@~
+   @Send(FunList {@hid[@Parm(Var)] @>[@i[@Hemlock Variable]]@\})@~
+   @HVxindex@Parmquote(Var)@~
+   @Imbed(Nolabel, undef '@Imbed(Varlabel,
+                                  def <@Label{@Parm(Varlabel)-hvar}>,
+                                  undef <@Label{@Parm(Var)-hvar}>)')@~
+   @Begin(Defbody)@Tabclear ")
+
+@Form(Defhvar1 = "@Begin(Undefbody)@Comment(Tabset?)@~
+   @hid[@Parm(Var)]@imbed(val, def <@ @ (initial value @f[@parm(val)])>)@>[@i[@hemlock Variable]]@\@~
+   @Send(FunList {@hid[@Parm(Var)] @>[@i[@hemlock Variable]]@\})@~
+   @HVxindex@Parmquote(Var)@~
+   @Imbed(Nolabel, undef '@Imbed(Varlabel,
+                                  def <@Label{@Parm(Varlabel)-hvar}>,
+                                  undef <@Label{@Parm(Var)-hvar}>)')@~
+   @End(Undefbody)")
+
+@Commandstring(Enddefhvar = "@End(Defbody)@End(Defenvironment)")
+@Textform(HVxindex = "@Xindex(T {Hemlock variable}, X {@Parm(Text)}, P {@hid[@Parm(Text)]})@'")
+@Textform(HVindexref = "@Xindexref(T {Hemlock variable}, X {@Parm(Text)}, P {@hid[@Parm(Text)]})@'")
+@Textform(HVarref = '@hid[@Parm(Text)] @~
+    @r[(page @Pageref(@Parm(Text)-hvar))]@HVindexref@Parmquote(Text)')
+
+
+@Form(Defcom = "@Begin(Defenvironment)@Comment(Tabset?)@~
+   @hid[@Parm(Com)]@imbed(bind, def <@ @ (bound to @bf[@parm(bind)])>)@~
+   @imbed(Stuff, def <@ @ (@Parm(Stuff))>)@>[@i[Command]]@\@~
+   @Send(FunList {@hid[@Parm(Com)] @>[@i[Command]]@\})@~
+   @HCxindex@Parmquote(Com)@~
+   @Imbed(Nolabel, undef '@Imbed(Comlabel,
+                                  def <@Label{@Parm(Comlabel)-com}>,
+                                  undef <@Label{@Parm(Com)-com}>)')@~
+   @Begin(Defbody)@Tabclear ")
+
+
+@Form(Defcom1 = "@Begin(Undefbody)@Comment(Tabset?)@~
+   @hid[@Parm(Com)]@imbed(bind, def <@ @ (bound to @bf[@parm(bind)])>)@~
+   @imbed(Stuff, def <@ @ (@Parm(Stuff))>)@>[@i[Command]]@\@~
+   @Send(FunList {@hid[@Parm(Com)] @>[@i[Command]]@\})@~
+   @HCxindex@Parmquote(Com)@~
+   @Imbed(Nolabel, undef '@Imbed(Comlabel,
+                                  def <@Label{@Parm(Comlabel)-com}>,
+                                  undef <@Label{@Parm(Com)-com}>)')@~
+   @End(Undefbody)")
+
+
+@Commandstring(Enddefcom = "@End(Defbody)@End(Defenvironment)")
+@Textform(HCxindex = "@Xindex(T {Command}, X {@Parm(Text)}, P {@hid[@Parm(Text)]})@'")
+@Textform(HCindexref = "@Xindexref(T {Command}, X {@Parm(Text)}, P {@hid[@Parm(Text)]})@'")
+@Textform(Comref = '@hid[@Parm(Text) ]@~
+    @r[(page @Pageref(@Parm(Text)-com))]@HCindexref@Parmquote(Text)')
+
+
+@String(IndexFuns "Yes")
+@string(supresskeyindex "Yes")
+
+@specialfont(f1 = helvetica)
+@commandstring(Hemlock = "@f1(Hemlock)")
+@textform(hid = '@w{@f1{@parm(Text)}}')
+@commandstring[emacs = "@f1<Emacs>"]
+
+@specialfont(f2 = "BookmanDemi")
+@textform<binding = "@f2[@w(@parm{text})]">
+@textform<bf = "@f2[@w(@parm{text})]">
+
+@commandstring[llisp = "L@c(isp)"]
+
+@commandstring[windows = "X windows"]
diff --git a/docs/database/outtir.lib b/docs/database/outtir.lib
new file mode 100644
index 000000000..428d1a416
--- /dev/null
+++ b/docs/database/outtir.lib
@@ -0,0 +1,329 @@
+@Comment{Version of BOLIO.LIB that provides a single unified index
+instead of separate indexes for functions, variables, constants,
+keywords, and concepts.}
+
+@Marker(Library, Uttir, Press, Dover, Postscript)
+
+@Libraryfile(DBolio)
+
+
+@Comment{Constraints on the definition of IndexEnvironment:
+	Indent = - LeftMargin
+	(Linewidth + Leftmargin + Columnmargin) * Columns - Columnmargin
+		 = global line width
+}
+@Define(IndexEnvironment, Boxed, Columns 2, Columnmargin 0.5in,
+        Linewidth 2.7in, Leftmargin +0.3in, Indent -0.3in)
+
+@Define(KeySpreadEnvironment, Facecode F)
+@Textform(SpreadKeys = "@KeySpreadEnvironment<@SpreadKeysLoop@Parm(Text)[]>")
+@Textform(SpreadKeysLoop =
+	"@String(SpreadKeysTemp = @Parmquote(Text))@Case(SpreadKeysTemp,
+	     null <>, else < :@Parm(Text)@SpreadKeysLoop>)")
+
+@Form(IndexKeys = "@Textform(IndexKeysLoop =
+	'@String(IndexKeysTemp = @Quote{@Parmquote(Text)})@Case(IndexKeysTemp,
+	    null <>, else [@Kindex2(P = @Quote{@Parmquote(Text)},
+				    S = {for@f( @Parm(Fun))})@IndexKeysLoop])')@IndexKeysLoop@Parm(Keys)[]@~")
+
+@Counter(UnNumberedIndex,TitleEnv HD1A,ContentsEnv tc1,Announced,Alias Chapter)
+
+@Textform(IndexHeadings = "@UnnumberedIndex@Parmquote(Text)
+@String(ChapterTitle = @Parmquote(Text))
+@Pageheading(Immediate, Left = <>, Right = <>)
+@Pagefooting(Immediate, Center = <@Value(Page)>)
+@Pageheading(Odd, Left = <@c[@Value(ChapterTitle)]>, Right = <@Value(Page)>)
+@Pageheading(Even, Left = <@Value(Page)>, Right = <@c[@Value(ReportTitle)]>)
+@Pagefooting(Center = <>)
+")
+
+@Textform(Incompatibility = "@Begin(Quotation, Font Smallbodyfont, Indent +0, Spread 0.5, need 4)
+	@b[Compatibility note:] @Index(@b[Compatibility note])
+	@Parm(Text) @End(Quotation)")
+@Textform(Implementation = "@Begin(Quotation, Font Smallbodyfont, Indent +0, Spread 0.5, need 4)
+	@b[Implementation note:] @Index(@b[Implementation note])
+	@Parm(Text) @End(Quotation)")
+@Textform(Rationale = "@Begin(Quotation, Font Smallbodyfont, Indent +0, Spread 0.5, need 4)
+	@b[Rationale:] @Index(@b[Rationale]) @Parm(Text) @End(Quotation)")
+@Comment{
+@Textform(Query = "@Begin(Quotation, Font Smallbodyfont, Indent +0, Spread 0.5, need 4)
+	@f[???] @b[Query:] @Index(@b[Query]) @Parm(Text) @End(Quotation)")
+}
+
+@Textform(Kwd = "@f[:@Parm(Text)]")
+@Textform(KeywordList = "
+	@Begin(Description)
+	@Textform(Keyword = '@Begin(Multiple)@~
+@f[:@Quote<@Parm(Text)>  ]@\@Kindex2(P = @Quote<@Parmquote(Text)>,
+			   S = {for@f[ @Parm(Text)]})@~
+		@Label{@Parm(Text)-@Quote<@Parm(Text)>-kwd}@~')
+	@Textform(FirstKeyword = '@Begin(Multiple)@~
+@f[:@Quote<@Parm(Text)> @r[or] ]@Kindex2(P = @Quote<@Parmquote(Text)>,
+			   S = {for@f[ @Parm(Text)]})@~
+		@Label{@Parm(Text)-@Quote<@Parm(Text)>-kwd}@~')
+	@Textform(NextKeyword = '@~
+@f[:@Quote<@Parm(Text)> @r[or] ]@Kindex2(P = @Quote<@Parmquote(Text)>,
+			   S = {for@f[ @Parm(Text)]})@~
+		@Label{@Parm(Text)-@Quote<@Parm(Text)>-kwd}@~')
+	@Textform(LastKeyword = '@~
+@f[:@Quote<@Parm(Text)>  ]@\@Kindex2(P = @Quote<@Parmquote(Text)>,
+			   S = {for@f[ @Parm(Text)]})@~
+		@Label{@Parm(Text)-@Quote<@Parm(Text)>-kwd}@~')
+	@Textform(SubKeywordList = '
+		@Begin(Description)
+		@Textform(SubKeyword = <@Begin(Multiple)@~
+@f[:@Quote{@Quote[@Parm(Text)]}  ]@\@Kindex2(P = @Quote{@Quote[@Parmquote(Text)]},
+			   S = {for@f[ @Quote[@Parm(Text)] ]option @~
+				to@f[ @Parm(Text)]})@~
+		@Label{@Parm(Text)-@Quote[@Parm(Text)]-@Quote{@Quote[@Parm(Text)]}-kwd}@~>)')
+")
+@Textform(PseudoKeyword = "@Begin(Multiple)@Parm(Text)   @\@~")
+@Commandstring(Endkeyword = "@End(Multiple)")
+@Commandstring(Endkeywordlist = "@End(Description)")
+@Textform(PseudoSubKeyword = "@Begin(Multiple)@Parm(Text)   @\@~")
+@Commandstring(EndSubKeyword = "@End(Multiple)")
+@Commandstring(EndSubKeywordlist = "@End(Description)")
+@Textform(RandomKeywordList = "
+	@Begin(Description)
+	@Index2(P = {Keywords}, S = {for@f[ ]@Parm(Text)})
+	@Textform(RandomKeyword = '@Begin(Multiple)
+@f[:@Quote<@Parm(Text)>  ]@\@Kindex2(P = @Quote<@Parmquote(Text)>,
+				     S = {for@f[ ]@Parm(Text)})@~')
+")
+@Textform(PseudoRandomKeyword = "@Begin(Multiple)@Parm(Text)   @\@~")
+@Commandstring(Endrandomkeyword = "@End(Multiple)")
+@Commandstring(Endrandomkeywordlist = "@End(Description)")
+
+@Form(Defvar = "@Begin(Defenvironment)@Comment(Tabset?)@~
+   @f[@Imbed(Nostar, undef '*')@Parm(Var)@Imbed(Nostar, undef '*')] @>[@i[Variable]]@\@~
+   @Send(FunList {@f[@Imbed(Nostar, undef '*')@Parm(Var)@Imbed(Nostar, undef '*')] @>[@i[Variable]]@\})@~
+   @Imbed(Nostar, undef<@Vindex@Parmquote(Var)>, def<@Vxindex@Parmquote(Var)>)@~
+   @Imbed(Nolabel, undef '@Imbed(Varlabel,
+			          def <@Label{@Parm(Varlabel)-var}>,
+			          undef <@Label{@Parm(Var)-var}>)')@~
+   @Begin(Defbody)@Tabclear ")
+@Form(Defvar1 = "@Begin(Undefbody)@Comment(Tabset?)@~
+   @f[@Imbed(Nostar, undef '*')@Parm(Var)@Imbed(Nostar, undef '*')] @>[@i[Variable]]@\@~
+   @Send(FunList {@f[@Imbed(Nostar, undef '*')@Parm(Var)@Imbed(Nostar, undef '*')] @>[@i[Variable]]@\})@~
+   @Imbed(Nostar, undef<@Vindex@Parmquote(Var)>, def<@Vxindex@Parmquote(Var)>)@~
+   @Imbed(Nolabel, undef '@Imbed(Varlabel,
+			          def <@Label{@Parm(Varlabel)-var}>,
+			          undef <@Label{@Parm(Var)-var}>)')@~
+   @End(Undefbody)")
+@Commandstring(Enddefvar = "@End(Defbody)@End(Defenvironment)")
+
+@Form(Defcon = "@Begin(Defenvironment)@Comment(Tabset?)@~
+   @f[@Parm(Var)] @>[@i[Constant]]@\@~
+   @Send(FunList {@f[@Parm(Var)] @>[@i[Constant]]@\})@~
+   @Conindex@Parmquote(Var)@~
+   @Imbed(Nolabel, undef '@Imbed(Varlabel,
+			          def <@Label{@Parm(Varlabel)-con}>,
+			          undef <@Label{@Parm(Var)-con}>)')@~
+   @Begin(Defbody)@Tabclear ")
+@Form(Defcon1 = "@Begin(Undefbody)@Comment(Tabset?)@~
+   @f[@Parm(Var)] @>[@i[Constant]]@\@~
+   @Send(FunList {@f[@Parm(Var)] @>[@i[Constant]]@\})@~
+   @Conindex@Parmquote(Var)@~
+   @Imbed(Nolabel, undef '@Imbed(Varlabel,
+			          def <@Label{@Parm(Varlabel)-con}>,
+			          undef <@Label{@Parm(Var)-con}>)')@~
+   @End(Undefbody)")
+@Commandstring(Enddefcon = "@End(Defbody)@End(Defenvironment)")
+
+@Form(Defun = "@Begin(Defenvironment)@Comment(Tabset?)@~
+   @f[@Parm(Fun) @Parm(Args, default <>)@Imbed(Keys, def < @key@!@Spreadkeys(@Parm(Keys))>)] @>[@i[Function]]@\
+@Imbed(MoreKeys, def <@/@Spreadkeys(@Parm(MoreKeys))
+>)@~
+@Imbed(YetMoreKeys, def <@/@Spreadkeys(@Parm(YetMoreKeys))
+>)@~
+   @Send(FunList {@f[@Parm(Fun) @Parm(Args, default <>)@Imbed(Keys,
+	def < @key@!@Spreadkeys(@Parm(Keys))>)] @>[@i[Function]]@\@Imbed(MoreKeys,
+	def <
+@/@f[@Spreadkeys(@Parm(MoreKeys))]>)@Imbed(YetMoreKeys,
+	def <
+@/@f[@Spreadkeys(@Parm(YetMoreKeys))]>)})@~
+   @Findex@Parmquote(Fun)@~
+  @Imbed(SuppressKeyIndex, undef <
+   @Imbed(Keys, def '@IndexKeys(Fun = @Parmquote(Fun), Keys = @Parmquote(Keys))')@~
+   @Imbed(MoreKeys, def '@IndexKeys(Fun = @Parmquote(Fun), Keys = @Parmquote(MoreKeys))')@~
+   @Imbed(YetMoreKeys, def '@IndexKeys(Fun = @Parmquote(Fun), Keys = @Parmquote(YetMoreKeys))')>)@~
+   @Imbed(Nolabel, undef '@Imbed(Funlabel,
+			          def <@Label{@Parm(Funlabel)-fun}>,
+			          undef <@Label{@Parm(Fun)-fun}>)')@~
+   @Begin(Defbody)@Tabclear ")
+@Form(Defun1 = "@Begin(Undefbody)@Comment(Tabset?)@~
+   @f[@Parm(Fun) @Parm(Args, default <>)@Imbed(Keys, def < @key@!@Spreadkeys(@Parm(Keys))>)] @>[@i[Function]]@\
+@Imbed(MoreKeys, def <@/@Spreadkeys(@Parm(MoreKeys))
+>)@~
+@Imbed(YetMoreKeys, def <@/@Spreadkeys(@Parm(YetMoreKeys))
+>)@~
+   @Send(FunList {@f[@Parm(Fun) @Parm(Args, default <>)@Imbed(Keys,
+	def < @key@!@Spreadkeys(@Parm(Keys))>)] @>[@i[Function]]@\@Imbed(MoreKeys,
+	def <
+@/@f[@Spreadkeys(@Parm(MoreKeys))]>)@Imbed(YetMoreKeys,
+	def <
+@/@f[@Spreadkeys(@Parm(YetMoreKeys))]>)})@~
+   @Findex@Parmquote(Fun)@~
+  @Imbed(SuppressKeyIndex, undef <
+   @Imbed(Keys, def '@IndexKeys(Fun = @Parmquote(Fun), Keys = @Parmquote(Keys))')@~
+   @Imbed(MoreKeys, def '@IndexKeys(Fun = @Parmquote(Fun), Keys = @Parmquote(MoreKeys))')@~
+   @Imbed(YetMoreKeys, def '@IndexKeys(Fun = @Parmquote(Fun), Keys = @Parmquote(YetMoreKeys))')>)@~
+   @Imbed(Nolabel, undef '@Imbed(Funlabel,
+			          def [@Label{@Parm(Funlabel)-fun}],
+			          undef [@Label{@Parm(Fun)-fun}])')@~
+   @End(Undefbody)")
+@Commandstring(Enddefun = "@End(Defbody)@End(Defenvironment)")
+
+@Form(Defmac = "@Begin(Defenvironment)@Comment(Tabset?)@~
+   @f[@Parm(Fun) @Parm(Args, default <>)] @>[@i[Macro]]@\@~
+   @Send(FunList {@f[@Parm(Fun) @Parm(Args, default <>)] @>[@i[Macro]]@\})@~
+   @Mindex@Parmquote(Fun)@~
+   @Imbed(Nolabel, undef '@Imbed(Funlabel,
+			          def <@Label{@Parm(Funlabel)-mac}>,
+			          undef <@Label{@Parm(Fun)-mac}>)')@~
+   @Begin(Defbody)@Tabclear ")
+@Form(Defmac1 = "@Begin(Undefbody)@Comment(Tabset?)@~
+   @f[@Parm(Fun) @Parm(Args, default <>)] @>[@i[Macro]]@\@~
+   @Send(FunList {@f[@Parm(Fun) @Parm(Args, default <>)] @>[@i[Macro]]@\})@~
+   @Mindex@Parmquote(Fun)@~
+   @Imbed(Nolabel, undef '@Imbed(Funlabel,
+			          def <@Label{@Parm(Funlabel)-mac}>,
+			          undef <@Label{@Parm(Fun)-mac}>)')@~
+   @End(Undefbody)")
+@Commandstring(Enddefmac = "@End(Defbody)@End(Defenvironment)")
+
+@Form(Defspec = "@Begin(Defenvironment)@Comment(Tabset?)@~
+   @f[@Parm(Fun) @Parm(Args, default <>)] @>[@i[Special form]]@\@~
+   @Send(FunList {@f[@Parm(Fun) @Parm(Args, default <>)] @>[@i[Special form]]@\})@~
+   @Sindex@Parmquote(Fun)@~
+   @Imbed(Nolabel, undef '@Imbed(Funlabel,
+			          def <@Label{@Parm(Funlabel)-spec}>,
+			          undef <@Label{@Parm(Fun)-spec}>)')@~
+   @Begin(Defbody)@Tabclear ")
+@Form(Defspec1 = "@Begin(Undefbody)@Comment(Tabset?)@~
+   @f[@Parm(Fun) @Parm(Args, default <>)] @>[@i[Special form]]@\@~
+   @Send(FunList {@f[@Parm(Fun) @Parm(Args, default <>)] @>[@i[Special form]]@\})@~
+   @Sindex@Parmquote(Fun)@~
+   @Imbed(Nolabel, undef '@Imbed(Funlabel,
+			          def <@Label{@Parm(Funlabel)-spec}>,
+			          undef <@Label{@Parm(Fun)-spec}>)')@~
+   @End(Undefbody)")
+@Commandstring(Enddefspec = "@End(Defbody)@End(Defenvironment)")
+
+@Textform(Xindent = "@hsp(2.0em)")
+@Textform(Xsepr = "@hsp(0.5em)")
+@Textform(Def = "@Index@Parmquote(Text)@i@Parmquote(Text)")
+@Textform(Index = "@Indexentry{Key {@Parm(Text) !1},
+             Entry {@r[@Parm(Text)]@Xsepr()}, Number {@r[@Parmvalue(Page)]}}@'")
+@Form(PossiblyIndexedRef = "@Indexentry{Key {@Parm(K) !1},
+             Entry {@r[@Parm(F)]@Xsepr()}, Number {@r[@Parmvalue(Page)]}}@Parm(E)")
+@Textform(Index1 = "@Indexentry{Key {@Parm(Text) !1},
+             Entry {@r[@Parm(Text)]@Xsepr()}}@'")
+@Form(Index2 = "@Index1@Parmquote(P)@Indexentry{Key {@Parm(P) !2 @Parm(S)},
+         Entry {@Xindent()@r[@Parm(S)]@Xsepr()}, Number {@Parmvalue(Page)}}@'")
+@Form(Seealso = "@Index1@Parmquote(P)@Indexentry{Key {@Parm(P) !3 @Parm(S)},
+         Entry {@Xindent()@Xindent()@r[See also:]}, Number @Parmquote(S)}@'")
+@Form(Xindex = "@Indexentry{Key {@Parm(X) @Parm(T) 1},
+         Entry {@Parm(Q, default <>)@Parm(P)@Parm(R, default <>)@f[ ]@r[@Parm(T)]@Xsepr()},
+	 Number {@b[@Parmvalue(Page)]}}@'")
+@Form(Xindexref = "@Indexentry{Key {@Parm(X) @Parm(T) 1},
+         Entry {@Parm(Q, default <>)@Parm(P)@Parm(R, default <>)@f[ ]@r[@Parm(T)]@Xsepr()},
+	 Number {@Parmvalue(Page)}}@'")
+@Form(Xindex1 = "@Indexentry{Key {@Parm(X) @Parm(T) 1},
+         Entry {@Parm(Q, default <>)@Parm(P)@Parm(R, default <>)@f[ ]@r[@Parm(T)]@Xsepr()}}@'")
+@Form(Xindex2 = "@Xindex1(X @Parmquote(X), T @Parmquote(T),
+			  P @Parmquote(P)@Imbed(Q, def <, Q @Parmquote(Q)>)@Imbed(R, def <, R @Parmquote(R)>))@~
+         @Indexentry{Key {@Parm(X) @Parm(T) 2 @Parm(S)},
+		     Entry {@Xindent()@Parm(S)@Xsepr()},
+		     Number {@b[@Parmvalue(Page)]}}@'")
+@Form(Xindexref2 = "@Xindex1(X @Parmquote(X), T @Parmquote(T),
+			     P @Parmquote(P)@Imbed(Q, def <, Q @Parmquote(Q)>)@Imbed(R, def <, R @Parmquote(R)>))@~
+         @Indexentry{Key {@Parm(X) @Parm(T) 2 @Parm(S)},
+		     Entry {@Xindent()@Parm(S)@Xsepr()},
+		     Number {@Parmvalue(Page)}}@'")
+@Form(Xseealso = "@Xindex1(X @Parmquote(X), T @Parmquote(T),
+			   P @Parmquote(P)@Imbed(Q, def <, Q @Parmquote(Q)>)@Imbed(R, def <, R @Parmquote(R)>))@~
+         @Indexentry{Key {@Parm(X) @Parm(T) 3 @Parm(S)},
+		     Entry {@Xindent()@Xindent()@r[See also:]},
+		     Number @Parmquote(S)}}@'")
+
+@Textform(Cindex = "@Index@Parmquote(Text)@'")
+
+@Textform(Findex = "@Case(IndexFuns, Yes '@Xindex(T {function}, X {@Parm(Text)}, P {@f[@Parm(Text)]})')@'")
+@Textform(Findexref = "@Case(IndexFuns, Yes '@Xindexref(T {function}, X {@Parm(Text)}, P {@f[@Parm(Text)]})')@'")
+@Form(Findex2 = "@Case(IndexFuns, Yes '@Xindex2(T {function}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S))')@'")
+@Form(Fseealso = "@Case(IndexFuns, Yes '@Xseealso(T {function}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S))')@'")
+
+@Textform(Mindex = "@Case(IndexFuns, Yes '@Xindex(T {macro}, X {@Parm(Text)}, P {@f[@Parm(Text)]})')@'")
+@Textform(Mindexref = "@Case(IndexFuns, Yes '@Xindexref(T {macro}, X {@Parm(Text)}, P {@f[@Parm(Text)]})')@'")
+@Form(Mindex2 = "@Case(IndexFuns, Yes '@Xindex2(T {macro}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S))')@'")
+@Form(Mseealso = "@Case(IndexFuns, Yes '@Xseealso(T {macro}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S))')@'")
+
+@Textform(Sindex = "@Case(IndexFuns, Yes '@Xindex(T {special form}, X {@Parm(Text)}, P {@f[@Parm(Text)]})')@'")
+@Textform(Sindexref = "@Case(IndexFuns, Yes '@Xindexref(T {special form}, X {@Parm(Text)}, P {@f[@Parm(Text)]})')@'")
+@Form(Sindex2 = "@Case(IndexFuns, Yes '@Xindex2(T {special form}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S))')@'")
+@Form(Sseealso = "@Case(IndexFuns, Yes '@Xseealso(T {special form}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S))')@'")
+
+@Textform(Vindex = "@Xindex(T {variable}, X {@Parm(Text)}, P {@f[@Parm(Text)]}, Q {@f[*]}, R{@f[*]})@'")
+@Textform(Vxindex = "@Xindex(T {variable}, X {@Parm(Text)}, P {@f[@Parm(Text)]})@'")
+@Textform(Vindexref = "@Xindexref(T {variable}, X {@Parm(Text)}, P {@f[@Parm(Text)]}, Q {@f[*]}, R{@f[*]})@'")
+@Form(Vindex2 = "@Xindex2(T {variable}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S), Q {@f[*]}, R{@f[*]})@'")
+@Form(Vseealso = "@Xseealso(T {variable}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S), Q {@f[*]}, R{@f[*]})@'")
+
+@Textform(Conindex = "@Xindex(T {constant}, X {@Parm(Text)}, P {@f[@Parm(Text)]})@'")
+@Textform(Conindexref = "@Xindexref(T {constant}, X {@Parm(Text)}, P {@f[@Parm(Text)]})@'")
+@Form(Conindex2 = "@Xindex2(T {constant}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S))@'")
+@Form(Conseealso = "@Xseealso(T {constant}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S))@'")
+
+@Textform(Kindex = "@Xindex(T {keyword}, X {@Parm(Text)}, P {@f[@Parm(Text)]}, Q {@f[:]})@'")
+@Textform(Kindexref = "@Xindexref(T {keyword}, X {@Parm(Text)}, P {@f[@Parm(Text)]}, Q {@f[:]})@'")
+@Form(Kindex2 = "@Xindex2(T {keyword}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S), Q {@f[:]})@'")
+@Form(Kindexref2 = "@Xindexref2(T {keyword}, X {@Parm(K)}, P {@f[@Parm(K)]}, S @Parmquote(S), Q {@f[:]})@'")
+@Form(Kseealso = "@Xseealso(T {keyword}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S), Q {@f[:]})@'")
+
+@Textform(Declindex = "@Xindex(T {declaration}, X {@Parm(Text)}, P {@f[@Parm(Text)]})@'")
+@Textform(Declindexref = "@Xindexref(T {declaration}, X {@Parm(Text)}, P {@f[@Parm(Text)]})@'")
+@Form(Declindex2 = "@Xindex2(T {declaration}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S))@'")
+@Form(Declseealso = "@Xseealso(T {declaration}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S))@'")
+
+@Textform(Typeindex = "@Xindex(T {type specifier}, X {@Parm(Text)}, P {@f[@Parm(Text)]})@'")
+@Textform(Typeindexref = "@Xindexref(T {type specifier}, X {@Parm(Text)}, P {@f[@Parm(Text)]})@'")
+@Form(Typeindex2 = "@Xindex2(T {type specifier}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S))@'")
+@Form(Typeseealso = "@Xseealso(T {type specifier}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S))@'")
+
+@Textform(Funref = "@f[@Parm(Text) ]@~
+    @r[(page @Pageref(@Parm(Text)-fun))]@Findexref@Parmquote(Text)@;")
+@Textform(Funreftab = "@f[@Parm(Text) ]@\@r[(page @Pageref(@Parm(Text)-fun))]@Findexref@Parmquote(Text)@;")
+@Form(Xfunref = "@f[@Parm(X) ]@~
+    @r[(page @Pageref(@Parm(L)-fun))]@Findexref@Parmquote(X)@;")
+@Textform(Macref = "@f[@Parm(Text) ]@~
+    @r[(page @Pageref(@Parm(Text)-mac))]@Mindexref@Parmquote(Text)@;")
+@Textform(Macreftab = "@f[@Parm(Text) ]@\@r[(page @Pageref(@Parm(Text)-mac))]@Mindexref@Parmquote(Text)@;")
+@Form(Xmacref = "@f[@Parm(X) ]@~
+    @r[(page @Pageref(@Parm(L)-mac))]@Mindexref@Parmquote(X)@;")
+@Textform(Specref = "@f[@Parm(Text) ]@~
+    @r[(page @Pageref(@Parm(Text)-spec))]@Sindexref@Parmquote(Text)@;")
+@Textform(Specreftab = "@f[@Parm(Text) ]@\@r[(page @Pageref(@Parm(Text)-spec))]@Sindexref@Parmquote(Text)@;")
+@Form(XSpecref = "@f[@Parm(X) ]@~
+    @r[(page @Pageref(@Parm(L)-spec))]@Sindexref@Parmquote(X)@;")
+@Textform(Var = "@f[*@Parm(Text)*]")
+@Textform(Varref = "@f[*@Parm(Text)* ]@~
+    @r[(page @Pageref(@Parm(Text)-var))]@Vindexref@Parmquote(Text)@;")
+@Form(Xvarref = "@f[*@Parm(X)* ]@~
+    @r[(page @Pageref(@Parm(L)-var))]@Vindexref@Parmquote(X)@;")
+@Textform(Conref = "@f[@Parm(Text) ]@~
+    @r[(page @Pageref(@Parm(Text)-con))]@Conindexref@Parmquote(Text)@;")
+@Form(Xconref = "@f[@Parm(X) ]@~
+    @r[(page @Pageref(@Parm(L)-con))]@Conindexref@Parmquote(X)@;")
+@Form(Kwdref = "@f[:@Parm(K) ]@~
+    @r[(page @Pageref(@Parm(F)-@Parm(K)-kwd))]@Kindexref2(S {for@f[ @Parm(F)]},
+						      K @Parmquote(K))@;")
+@Form(SubKwdref = "@f[:@Parm(K)] @~
+    @r[(page @Pageref(@Parm(F)-@Parm(O)-@Parm(K)-kwd))]@~
+	@Kindexref2(S {for@f[ :@Parm(O) ]option to@f[ @Parm(F)]},
+		    K @Parmquote(K))")
+
+@Indexentry(Key {  1}, Entry {@IndexHeadings[Index]@Blankspace(1)@Begin(IndexEnvironment)})
+@Indexentry(Key {~~~ }, Entry {@End(IndexEnvironment)})
+
+@Textform(IndexCleanup = " ")
diff --git a/docs/database/spice.lib b/docs/database/spice.lib
new file mode 100644
index 000000000..a6520620e
--- /dev/null
+++ b/docs/database/spice.lib
@@ -0,0 +1,67 @@
+@Marker(Library, Spice, Press, Dover, Postscript)
+
+@libraryfile(table)
+@modify(HD3, above 0.3inch, below 0.15inch)
+@modify(HD2, below 0.25inch)
+@modify[HD4, above .3inch, below 0, break before]
+@modify(paragraph, 
+	ContentsForm=" ", 
+	TitleForm="@HD4[@parm(title)@hsp(1quad)]",
+	numbered [], referenced [])
+@textform(mline="@enter(liner,script +5pts)@tabclear()@&@ @\@leave(liner)")
+
+@define(twocolumn,columns 2,columnmargin 1cm,spacing 12pts,boxed,
+	linewidth 3inch)
+
+@form(SpiceTitlePage={
+@begin(titlepage)
+@begin(titlebox,centered)
+@majorheading(CARNEGIE-MELLON UNIVERSITY)
+@heading(DEPARTMENT@  OF@  COMPUTER@  SCIENCE)
+@heading[SPICE@  PROJECT]
+@begin(format, leftmargin +1.10inch, rightmargin +1.10inch)
+@mline()
+@begin(center, spacing 1)
+@heading[@Parm(Title)]
+
+@Parm(Author)
+
+@Parm(Date,default="@value(date)")
+@end(center)
+@mline()
+@end(format)
+@end(titlebox)
+
+@Parm(cruft, default="")
+
+@begin(center,spacing 1.3, above .5inch)
+Keywords and index categories: @Parm(Index,default="<not specified>")
+Location of machine-readable File: @parm(File,default="@value(Manuscript) @@ @value(site)")
+@end(center)
+
+@Copyrightnotice(@Parm(Copyrightholder, default <Carnegie-Mellon University>))
+@begin(researchcredit)
+@imbed( internal, 
+def "This is an internal working document of the Computer Science 
+	Department, Carnegie-Mellon University, Schenley Park, Pittsburgh, 
+	PA 15213.  Some of the ideas expressed in this document may be   
+	only partially developed or erroneous.  Distribution of this document   
+	outside the immediate working community is discouraged; publication   
+	of this document is forbidden.")
+
+Supported by the Defense Advanced Research Projects Agency, Department   
+of Defense, ARPA Order 3597, monitored by the Air Force Avionics   
+Laboratory under contract F33615-78-C-1551.  The views   
+and conclusions contained in this document are those of the authors   
+and should not be interpreted as representing the official policies,   
+either expressed or implied, of the Defense Advanced Research   
+Projects Agency or the U.S. Government.
+@end(researchcredit)
+@end(titlepage)
+
+@newpage
+
+@comment[ Leave larger blank area at top of first page ]
+@format[ @blankspace( 1inch ) ]
+}) @comment[ End of SpiceTitlePage form ]
+@Marker(Library,Spice)
diff --git a/docs/database/spicer.fon b/docs/database/spicer.fon
new file mode 100644
index 000000000..5244c3d38
--- /dev/null
+++ b/docs/database/spicer.fon
@@ -0,0 +1,230 @@
+@Marker(Font,SpiceRoman10,Press)
+@DefineFont(BodyFont,	
+	R=<Xerox "TimesRoman10R">,
+	I=<Xerox "TimesRoman10I">,
+	B=<Xerox "TimesRoman10B">,
+	P=<Ascii "TimesRoman10BI">,
+	F=<Ascii "SailA10R">,
+	C=<Xerox "TimesRoman8R">,
+	Z=<Xerox "Zfont10R">,
+	G=<Xgreek "Hippo10R">,
+	Y=<Xerox "TimesRoman8R">,
+	X=<Xerox "CMSY10S10R">,
+	U=<Ascii "Sail10">,
+	A=<Ascii "APL10">,
+	T=<Ascii "SailA10R">,
+	K=<Ascii "Operators10R">,
+	L=<Ascii "Operators20R">,
+	M=<Ascii "Relation9R">,
+	N=<Ascii "AllArrows10R">)
+
+@comment(Shrunk: 14-12,10-9,9-8,8-7,6-5 except K and G)
+@DefineFont(SmallBodyFont,
+	R=<Xerox "TimesRoman8R">,
+	B=<Xerox "TimesRoman8B">,
+	I=<Xerox "TimesRoman8I">,
+	P=<Xerox "TimesRoman8BI">,
+	G=<Xgreek "Hippo8R">,
+	F=<Ascii "SailA8R">,
+	Z=<Xerox "Zfont10R">,
+	Y=<Xerox "TimesRoman8R">,
+	X=<Xerox "CMSY8R">,
+	U=<Ascii "Sail8">,
+	A=<Ascii "APL8">,
+	C=<Xerox "TimesRoman6R">,
+	T=<Ascii "SailA8R">,
+	K=<Ascii "Operators8R">,
+	L=<Ascii "Operators12R">,
+	M=<Ascii "Relation8R">,
+	N=<Ascii "AllArrows8R">) @Comment{GLS 5/17/81: AllArrows7R nonexistent}
+
+@DefineFont(LargeBodyFont,
+		R=<Ascii "TimesRoman12">,
+		I=<Ascii "TimesRoman12I">,
+		B=<Ascii "TimesRoman12B">,
+		C=<Ascii "TimesRoman10">)
+@DefineFont(SquareRootFont,
+		R=<Ascii "SquareRoot10">)
+
+@DefineFont(TitleFont1,
+		R=<Xerox "TimesRoman10B">,
+		I=<Xerox "TimesRoman10BI">,
+		F=<Ascii "SailA10R">,
+		C=<Xerox "TimesRoman8B">)
+@DefineFont(TitleFont2,
+		R=<Xerox "TimesRoman12B">,
+		I=<Xerox "TimesRoman12BI">,
+		F=<Ascii "SailA12R">,
+		C=<Xerox "TimesRoman9B">)
+@DefineFont(TitleFont3,
+		R=<Xerox "TimesRoman12B">,
+		I=<Xerox "TimesRoman12BI">,
+		F=<Ascii "SailA12R">,
+		C=<Xerox "TimesRoman9B">)
+@DefineFont(TitleFont4,
+		R=<Xerox "TimesRoman12B">,
+		I=<Xerox "TimesRoman12BI">,
+		F=<Ascii "SailA12R">,
+		C=<Xerox "TimesRoman9B">)
+@DefineFont(TitleFont5,
+		R=<Xerox "TimesRoman18B">,
+		I=<Xerox "TimesRoman18BI">,
+		C=<Xerox "TimesRoman12B">)
+
+@Equate(DisplayFont=BodyFont,TitleFont0=BodyFont,HeadingFont=TitleFont3)
+@Marker(Font,SpiceRoman11,Press)
+@DefineFont(BodyFont,	
+	R=<Xerox "TimesRoman11R">,
+	I=<Xerox "TimesRoman11I">,
+	B=<Xerox "TimesRoman11B">,
+	P=<Ascii "TimesRoman11BI">,
+	F=<Ascii "SailA11R">,
+	C=<Xerox "TimesRoman9R">,
+	Z=<Xerox "Zfont11R">,
+	G=<Xgreek "Hippo11R">,
+	Y=<Xerox "TimesRoman9R">,
+	X=<Xerox "CMSY10S10R">,
+	U=<Ascii "Sail10">,
+	A=<Ascii "APL10">,
+	T=<Ascii "SailA11R">)
+
+@DefineFont(SmallBodyFont,
+	R=<Xerox "TimesRoman9R">,
+	B=<Xerox "TimesRoman9B">,
+	I=<Xerox "TimesRoman9I">,
+	P=<Xerox "TimesRoman9BI">,
+	G=<Xgreek "Hippo9R">,
+	F=<Ascii "SailA9R">,
+	Z=<Xerox "Zfont11R">,
+	Y=<Xerox "TimesRoman9R">,
+	X=<Xerox "CMSY8R">,
+	C=<Xerox "TimesRoman6R">,
+	U=<Ascii "Sail9">,
+	A=<Ascii "APL8">,
+	T=<Ascii "SailA9R">)
+
+@DefineFont(TitleFont1,
+		R=<Xerox "TimesRoman11B">,
+		I=<Xerox "TimesRoman11BI">,
+		C=<Xerox "TimesRoman9B">)
+@DefineFont(TitleFont2,
+		R=<Xerox "TimesRoman12B">,
+		I=<Xerox "TimesRoman12BI">,
+		C=<Xerox "TimesRoman9B">)
+@DefineFont(TitleFont3,
+		R=<Xerox "TimesRoman12B">,
+		I=<Xerox "TimesRoman12BI">,
+		C=<Xerox "TimesRoman9B">)
+@DefineFont(TitleFont4,
+		R=<Xerox "TimesRoman12B">,
+		I=<Xerox "TimesRoman12BI">,
+		C=<Xerox "TimesRoman9B">)
+@DefineFont(TitleFont5,
+		R=<Xerox "TimesRoman18B">,
+		I=<Xerox "TimesRoman18BI">,
+		C=<Xerox "TimesRoman12B">)
+
+@Equate(DisplayFont=BodyFont,TitleFont0=BodyFont,HeadingFont=TitleFont3)
+@Marker(Font,SpiceRoman12,Press)
+@DefineFont(BodyFont,	
+	R=<Xerox "TimesRoman12R">,
+	I=<Xerox "TimesRoman12I">,
+	B=<Xerox "TimesRoman12B">,
+	P=<Ascii "TimesRoman12BI">,
+	F=<Ascii "SailA10R">,
+	C=<Xerox "TimesRoman10R">,
+	Z=<Xerox "Zfont12R">,
+	G=<Xgreek "Hippo12R">,
+	Y=<Xerox "TimesRoman10R">,
+	X=<Xerox "CMSY10S10R">,
+	U=<Ascii "Sail12">,
+	T=<Ascii "SailA10R">)
+
+@DefineFont(SmallBodyFont,
+	R=<Xerox "TimesRoman10R">,
+	B=<Xerox "TimesRoman10B">,
+	I=<Xerox "TimesRoman10I">,
+	P=<Xerox "TimesRoman10BI">,
+	G=<Xgreek "Hippo10R">,
+	F=<Ascii "SailA9R">,
+	Z=<Xerox "Zfont12R">,
+	Y=<Xerox "TimesRoman10R">,
+	X=<Xerox "CMSY8R">,
+	C=<Xerox "TimesRoman6R">,
+	U=<Ascii "Sail10">,
+	A=<Ascii "APL10">,
+	T=<Ascii "SailA9R">)
+
+@DefineFont(TitleFont1,
+		R=<Xerox "TimesRoman12B">,
+		I=<Xerox "TimesRoman12BI">,
+		C=<Xerox "TimesRoman10B">)
+@DefineFont(TitleFont2,
+		R=<Xerox "TimesRoman14B">,
+		I=<Xerox "TimesRoman14BI">,
+		C=<Xerox "TimesRoman9B">)
+@DefineFont(TitleFont3,
+		R=<Xerox "TimesRoman16B">,
+		I=<Xerox "TimesRoman16BI">,
+		C=<Xerox "TimesRoman12B">)
+@DefineFont(TitleFont4,
+		R=<Xerox "TimesRoman16B">,
+		I=<Xerox "TimesRoman16BI">,
+		C=<Xerox "TimesRoman12B">)
+@DefineFont(TitleFont5,
+		R=<Xerox "TimesRoman18B">,
+		I=<Xerox "TimesRoman18BI">,
+		C=<Xerox "TimesRoman14B">)
+
+@Equate(DisplayFont=BodyFont,TitleFont0=BodyFont,HeadingFont=TitleFont3)
+@Marker(Font,SpiceRoman14,Press)
+@DefineFont(BodyFont,	
+	R=<Xerox "TimesRoman14R">,
+	I=<Xerox "TimesRoman14I">,
+	B=<Xerox "TimesRoman14B">,
+	P=<Ascii "TimesRoman14BI">,
+	F=<Ascii "SailA14R">,
+	C=<Xerox "TimesRoman10R">,
+	Z=<Xerox "Zfont14R">,
+	G=<Xgreek "Hippo14R">,
+	Y=<Xerox "TimesRoman10R">,
+	X=<Xerox "CMSY10S10R">,
+	U=<Ascii "Sail14">,
+	T=<Ascii "SailA14R">)
+
+@DefineFont(SmallBodyFont,
+	R=<Xerox "TimesRoman10R">,
+	B=<Xerox "TimesRoman10B">,
+	I=<Xerox "TimesRoman10I">,
+	P=<Xerox "TimesRoman10BI">,
+	G=<Xgreek "Hippo10R">,
+	F=<Ascii "SailA10R">,
+	Z=<Xerox "Zfont10R">,
+	Y=<Xerox "TimesRoman10R">,
+	X=<Xerox "CMSY10S10R">,
+	C=<Xerox "TimesRoman8R">,
+	U=<Ascii "Sail12">,
+	T=<Ascii "SailA10R">)
+
+@DefineFont(TitleFont1,
+		R=<Xerox "TimesRoman14B">,
+		I=<Xerox "TimesRoman14BI">,
+		C=<Xerox "TimesRoman10B">)
+@DefineFont(TitleFont2,
+		R=<Xerox "TimesRoman16B">,
+		I=<Xerox "TimesRoman16BI">,
+		C=<Xerox "TimesRoman12B">)
+@DefineFont(TitleFont3,
+		R=<Xerox "TimesRoman16B">,
+		I=<Xerox "TimesRoman16BI">,
+		C=<Xerox "TimesRoman12B">)
+@DefineFont(TitleFont4,
+		R=<Xerox "TimesRoman18B">,
+		I=<Xerox "TimesRoman18BI">,
+		C=<Xerox "TimesRoman14B">)
+@DefineFont(TitleFont5,
+		R=<Xerox "TimesRoman18B">,
+		I=<Xerox "TimesRoman18BI">,
+		C=<Xerox "TimesRoman14B">)
+
+@Equate(DisplayFont=BodyFont,TitleFont0=BodyFont,HeadingFont=TitleFont3)
diff --git a/docs/database/table.lib b/docs/database/table.lib
new file mode 100644
index 000000000..0d572fe83
--- /dev/null
+++ b/docs/database/table.lib
@@ -0,0 +1,27 @@
+@Marker(Library,Table,Dover,Postscript)
+
+@Comment{New library definitions for tables.}
+
+@Style(StringMax=10000)
+@Modify(Table, Spacing 1)
+
+@Define(Liner, underline all, tabexport off, script -1pt,
+	rightmargin +1pts, leftmargin +2pts)
+@Define(up6, script +6pts)
+
+@textform(VB={@string(NID = "@parm(text)")@case(NID,
+	1 "@hsp(1pt)@ovp[|]@up6[|]",
+	2 "@hsp(1pt)@ovp[|]@up6[|]@>@ovp[|]@up6[|]@\",
+	3 "@hsp(1pt)@ovp[|]@up6[|]@>@ovp[|]@up6[|]@>@ovp[|]@up6[|]@\",
+	4 "@hsp(1pt)@ovp[|]@up6[|]@>@ovp[|]@up6[|]@>@ovp[|]@up6[|]@>@ovp[|]@up6[|]@\",
+	5 "@hsp(1pt)@ovp[|]@up6[|]@>@ovp[|]@up6[|]@>@ovp[|]@up6[|]@>@ovp[|]@up6[|]@>@ovp[|]@up6[|]@\",
+	6 "@hsp(1pt)@ovp[|]@up6[|]@>@ovp[|]@up6[|]@>@ovp[|]@up6[|]@>@ovp[|]@up6[|]@>@ovp[|]@up6[|]@>@ovp[|]@up6[|]@\",
+	7 "@hsp(1pt)@ovp[|]@up6[|]@>@ovp[|]@up6[|]@>@ovp[|]@up6[|]@>@ovp[|]@up6[|]@>@ovp[|]@up6[|]@>@ovp[|]@up6[|]@>@ovp[|]@up6[|]@\",
+	else "@hsp(1pt)@ovp[|]@up6[|]")})
+
+@Form(TLine="@enter(Liner, script @parm<height, default=[+3pts]>)@~
+	@tabclear()@&@ @\@leave(Liner)")
+@TextForm(BLine="@ovp<@Liner(@tabclear()@&@ @\)>@VB(@parm(text))")
+@TextForm(TL="@hsp(1)@parm(text)@>@ovp[|]@up6[|]@\")
+@TextForm(TC="@=@parm(text)@>@ovp[|]@up6[|]@\")
+@TextForm(TR="@>@parm(text)@hsp(1)@ovp[|]@up6[|]@\")
diff --git a/docs/database/uttir.lib b/docs/database/uttir.lib
new file mode 100644
index 000000000..63bdfdca6
--- /dev/null
+++ b/docs/database/uttir.lib
@@ -0,0 +1,329 @@
+@Comment{Version of BOLIO.LIB that provides a single unified index
+instead of separate indexes for functions, variables, constants,
+keywords, and concepts.}
+
+@Marker(Library, Uttir, Press, Dover, Postscript)
+
+@Libraryfile(DBolio)
+
+
+@Comment{Constraints on the definition of IndexEnvironment:
+	Indent = - LeftMargin
+	(Linewidth + Leftmargin + Columnmargin) * Columns - Columnmargin
+		 = global line width
+}
+@Define(IndexEnvironment, Boxed, Columns 2, Columnmargin 0.5in,
+        Linewidth 2.7in, Leftmargin +0.3in, Indent -0.3in)
+
+@Define(KeySpreadEnvironment, Facecode F)
+@Textform(SpreadKeys = "@KeySpreadEnvironment<@SpreadKeysLoop@Parm(Text)[]>")
+@Textform(SpreadKeysLoop =
+	"@String(SpreadKeysTemp = @Parmquote(Text))@Case(SpreadKeysTemp,
+	     null <>, else < :@Parm(Text)@SpreadKeysLoop>)")
+
+@Form(IndexKeys = "@Textform(IndexKeysLoop =
+	'@String(IndexKeysTemp = @Quote{@Parmquote(Text)})@Case(IndexKeysTemp,
+	    null <>, else [@Kindex2(P = @Quote{@Parmquote(Text)},
+				    S = {for@f( @Parm(Fun))})@IndexKeysLoop])')@IndexKeysLoop@Parm(Keys)[]@~")
+
+@Counter(UnNumberedIndex,TitleEnv HD1A,ContentsEnv tc1,Announced,Alias Chapter)
+
+@Textform(IndexHeadings = "@UnnumberedIndex@Parmquote(Text)
+@String(ChapterTitle = @Parmquote(Text))
+@Pageheading(Immediate, Left = <>, Right = <>)
+@Pagefooting(Immediate, Center = <@Value(Page)>)
+@Pageheading(Odd, Left = <@c[@Value(ChapterTitle)]>, Right = <@Value(Page)>)
+@Pageheading(Even, Left = <@Value(Page)>, Right = <@c[@Value(ReportTitle)]>)
+@Pagefooting(Center = <>)
+")
+
+@Textform(Incompatibility = "@Begin(Quotation, Font Smallbodyfont, Indent +0, Spread 0.5, need 4)
+	@b[Compatibility note:] @Index(@b[Compatibility note])
+	@Parm(Text) @End(Quotation)")
+@Textform(Implementation = "@Begin(Quotation, Font Smallbodyfont, Indent +0, Spread 0.5, need 4)
+	@b[Implementation note:] @Index(@b[Implementation note])
+	@Parm(Text) @End(Quotation)")
+@Textform(Rationale = "@Begin(Quotation, Font Smallbodyfont, Indent +0, Spread 0.5, need 4)
+	@b[Rationale:] @Index(@b[Rationale]) @Parm(Text) @End(Quotation)")
+@Comment{
+@Textform(Query = "@Begin(Quotation, Font Smallbodyfont, Indent +0, Spread 0.5, need 4)
+	@f[???] @b[Query:] @Index(@b[Query]) @Parm(Text) @End(Quotation)")
+}
+
+@Textform(Kwd = "@f[:@Parm(Text)]")
+@Textform(KeywordList = "
+	@Begin(Description)
+	@Textform(Keyword = '@Begin(Multiple)@~
+@f[:@Quote<@Parm(Text)>  ]@\@Kindex2(P = @Quote<@Parmquote(Text)>,
+			   S = {for@f[ @Parm(Text)]})@~
+		@Label{@Parm(Text)-@Quote<@Parm(Text)>-kwd}@~')
+	@Textform(FirstKeyword = '@Begin(Multiple)@~
+@f[:@Quote<@Parm(Text)> @r[or] ]@Kindex2(P = @Quote<@Parmquote(Text)>,
+			   S = {for@f[ @Parm(Text)]})@~
+		@Label{@Parm(Text)-@Quote<@Parm(Text)>-kwd}@~')
+	@Textform(NextKeyword = '@~
+@f[:@Quote<@Parm(Text)> @r[or] ]@Kindex2(P = @Quote<@Parmquote(Text)>,
+			   S = {for@f[ @Parm(Text)]})@~
+		@Label{@Parm(Text)-@Quote<@Parm(Text)>-kwd}@~')
+	@Textform(LastKeyword = '@~
+@f[:@Quote<@Parm(Text)>  ]@\@Kindex2(P = @Quote<@Parmquote(Text)>,
+			   S = {for@f[ @Parm(Text)]})@~
+		@Label{@Parm(Text)-@Quote<@Parm(Text)>-kwd}@~')
+	@Textform(SubKeywordList = '
+		@Begin(Description)
+		@Textform(SubKeyword = <@Begin(Multiple)@~
+@f[:@Quote{@Quote[@Parm(Text)]}  ]@\@Kindex2(P = @Quote{@Quote[@Parmquote(Text)]},
+			   S = {for@f[ @Quote[@Parm(Text)] ]option @~
+				to@f[ @Parm(Text)]})@~
+		@Label{@Parm(Text)-@Quote[@Parm(Text)]-@Quote{@Quote[@Parm(Text)]}-kwd}@~>)')
+")
+@Textform(PseudoKeyword = "@Begin(Multiple)@Parm(Text)   @\@~")
+@Commandstring(Endkeyword = "@End(Multiple)")
+@Commandstring(Endkeywordlist = "@End(Description)")
+@Textform(PseudoSubKeyword = "@Begin(Multiple)@Parm(Text)   @\@~")
+@Commandstring(EndSubKeyword = "@End(Multiple)")
+@Commandstring(EndSubKeywordlist = "@End(Description)")
+@Textform(RandomKeywordList = "
+	@Begin(Description)
+	@Index2(P = {Keywords}, S = {for@f[ ]@Parm(Text)})
+	@Textform(RandomKeyword = '@Begin(Multiple)
+@f[:@Quote<@Parm(Text)>  ]@\@Kindex2(P = @Quote<@Parmquote(Text)>,
+				     S = {for@f[ ]@Parm(Text)})@~')
+")
+@Textform(PseudoRandomKeyword = "@Begin(Multiple)@Parm(Text)   @\@~")
+@Commandstring(Endrandomkeyword = "@End(Multiple)")
+@Commandstring(Endrandomkeywordlist = "@End(Description)")
+
+@Form(Defvar = "@Begin(Defenvironment)@Comment(Tabset?)@~
+   @f[@Imbed(Package, def '@Parm(Package):')@Imbed(Nostar, undef '*')@Parm(Var)@Imbed(Nostar, undef '*')] @>[@i[Variable]]@\@~
+   @Send(FunList {@f[@Imbed(Nostar, undef '*')@Parm(Var)@Imbed(Nostar, undef '*')] @>[@i[Variable]]@\})@~
+   @Imbed(Nostar, undef<@Vindex@Parmquote(Var)>, def<@Vxindex@Parmquote(Var)>)@~
+   @Imbed(Nolabel, undef '@Imbed(Varlabel,
+			          def <@Label{@Parm(Varlabel)-var}>,
+			          undef <@Label{@Parm(Var)-var}>)')@~
+   @Begin(Defbody)@Tabclear ")
+@Form(Defvar1 = "@Begin(Undefbody)@Comment(Tabset?)@~
+   @f[@Imbed(Package, def '@Parm(Package):')@Imbed(Nostar, undef '*')@Parm(Var)@Imbed(Nostar, undef '*')] @>[@i[Variable]]@\@~
+   @Send(FunList {@f[@Imbed(Nostar, undef '*')@Parm(Var)@Imbed(Nostar, undef '*')] @>[@i[Variable]]@\})@~
+   @Imbed(Nostar, undef<@Vindex@Parmquote(Var)>, def<@Vxindex@Parmquote(Var)>)@~
+   @Imbed(Nolabel, undef '@Imbed(Varlabel,
+			          def <@Label{@Parm(Varlabel)-var}>,
+			          undef <@Label{@Parm(Var)-var}>)')@~
+   @End(Undefbody)")
+@Commandstring(Enddefvar = "@End(Defbody)@End(Defenvironment)")
+
+@Form(Defcon = "@Begin(Defenvironment)@Comment(Tabset?)@~
+   @f[@Imbed(Package, def '@Parm(Package):')@Parm(Var)] @>[@i[Constant]]@\@~
+   @Send(FunList {@f[@Parm(Var)] @>[@i[Constant]]@\})@~
+   @Conindex@Parmquote(Var)@~
+   @Imbed(Nolabel, undef '@Imbed(Varlabel,
+			          def <@Label{@Parm(Varlabel)-con}>,
+			          undef <@Label{@Parm(Var)-con}>)')@~
+   @Begin(Defbody)@Tabclear ")
+@Form(Defcon1 = "@Begin(Undefbody)@Comment(Tabset?)@~
+   @f[@Imbed(Package, def '@Parm(Package):')@Parm(Var)] @>[@i[Constant]]@\@~
+   @Send(FunList {@f[@Parm(Var)] @>[@i[Constant]]@\})@~
+   @Conindex@Parmquote(Var)@~
+   @Imbed(Nolabel, undef '@Imbed(Varlabel,
+			          def <@Label{@Parm(Varlabel)-con}>,
+			          undef <@Label{@Parm(Var)-con}>)')@~
+   @End(Undefbody)")
+@Commandstring(Enddefcon = "@End(Defbody)@End(Defenvironment)")
+
+@Form(Defun = "@Begin(Defenvironment)@Comment(Tabset?)@~
+   @f[@Imbed(Package, def '@Parm(Package):')@Parm(Fun) @Parm(Args, default <>)@Imbed(Keys, def < @key@!@Spreadkeys(@Parm(Keys))>)] @>[@i[Function]]@\
+@Imbed(MoreKeys, def <@/@Spreadkeys(@Parm(MoreKeys))
+>)@~
+@Imbed(YetMoreKeys, def <@/@Spreadkeys(@Parm(YetMoreKeys))
+>)@~
+   @Send(FunList {@f[@Parm(Fun) @Parm(Args, default <>)@Imbed(Keys,
+	def < @key@!@Spreadkeys(@Parm(Keys))>)] @>[@i[Function]]@\@Imbed(MoreKeys,
+	def <
+@/@f[@Spreadkeys(@Parm(MoreKeys))]>)@Imbed(YetMoreKeys,
+	def <
+@/@f[@Spreadkeys(@Parm(YetMoreKeys))]>)})@~
+   @Findex@Parmquote(Fun)@~
+  @Imbed(SuppressKeyIndex, undef <
+   @Imbed(Keys, def '@IndexKeys(Fun = @Parmquote(Fun), Keys = @Parmquote(Keys))')@~
+   @Imbed(MoreKeys, def '@IndexKeys(Fun = @Parmquote(Fun), Keys = @Parmquote(MoreKeys))')@~
+   @Imbed(YetMoreKeys, def '@IndexKeys(Fun = @Parmquote(Fun), Keys = @Parmquote(YetMoreKeys))')>)@~
+   @Imbed(Nolabel, undef '@Imbed(Funlabel,
+			          def <@Label{@Parm(Funlabel)-fun}>,
+			          undef <@Label{@Parm(Fun)-fun}>)')@~
+   @Begin(Defbody)@Tabclear ")
+@Form(Defun1 = "@Begin(Undefbody)@Comment(Tabset?)@~
+   @f[@Imbed(Package, def '@Parm(Package):')@Parm(Fun) @Parm(Args, default <>)@Imbed(Keys, def < @key@!@Spreadkeys(@Parm(Keys))>)] @>[@i[Function]]@\
+@Imbed(MoreKeys, def <@/@Spreadkeys(@Parm(MoreKeys))
+>)@~
+@Imbed(YetMoreKeys, def <@/@Spreadkeys(@Parm(YetMoreKeys))
+>)@~
+   @Send(FunList {@f[@Parm(Fun) @Parm(Args, default <>)@Imbed(Keys,
+	def < @key@!@Spreadkeys(@Parm(Keys))>)] @>[@i[Function]]@\@Imbed(MoreKeys,
+	def <
+@/@f[@Spreadkeys(@Parm(MoreKeys))]>)@Imbed(YetMoreKeys,
+	def <
+@/@f[@Spreadkeys(@Parm(YetMoreKeys))]>)})@~
+   @Findex@Parmquote(Fun)@~
+  @Imbed(SuppressKeyIndex, undef <
+   @Imbed(Keys, def '@IndexKeys(Fun = @Parmquote(Fun), Keys = @Parmquote(Keys))')@~
+   @Imbed(MoreKeys, def '@IndexKeys(Fun = @Parmquote(Fun), Keys = @Parmquote(MoreKeys))')@~
+   @Imbed(YetMoreKeys, def '@IndexKeys(Fun = @Parmquote(Fun), Keys = @Parmquote(YetMoreKeys))')>)@~
+   @Imbed(Nolabel, undef '@Imbed(Funlabel,
+			          def [@Label{@Parm(Funlabel)-fun}],
+			          undef [@Label{@Parm(Fun)-fun}])')@~
+   @End(Undefbody)")
+@Commandstring(Enddefun = "@End(Defbody)@End(Defenvironment)")
+
+@Form(Defmac = "@Begin(Defenvironment)@Comment(Tabset?)@~
+   @f[@Imbed(Package, def '@Parm(Package):')@Parm(Fun) @Parm(Args, default <>)] @>[@i[Macro]]@\@~
+   @Send(FunList {@f[@Parm(Fun) @Parm(Args, default <>)] @>[@i[Macro]]@\})@~
+   @Mindex@Parmquote(Fun)@~
+   @Imbed(Nolabel, undef '@Imbed(Funlabel,
+			          def <@Label{@Parm(Funlabel)-mac}>,
+			          undef <@Label{@Parm(Fun)-mac}>)')@~
+   @Begin(Defbody)@Tabclear ")
+@Form(Defmac1 = "@Begin(Undefbody)@Comment(Tabset?)@~
+   @f[@Imbed(Package, def '@Parm(Package):')@Parm(Fun) @Parm(Args, default <>)] @>[@i[Macro]]@\@~
+   @Send(FunList {@f[@Parm(Fun) @Parm(Args, default <>)] @>[@i[Macro]]@\})@~
+   @Mindex@Parmquote(Fun)@~
+   @Imbed(Nolabel, undef '@Imbed(Funlabel,
+			          def <@Label{@Parm(Funlabel)-mac}>,
+			          undef <@Label{@Parm(Fun)-mac}>)')@~
+   @End(Undefbody)")
+@Commandstring(Enddefmac = "@End(Defbody)@End(Defenvironment)")
+
+@Form(Defspec = "@Begin(Defenvironment)@Comment(Tabset?)@~
+   @f[@Imbed(Package, def '@Parm(Package):')@Parm(Fun) @Parm(Args, default <>)] @>[@i[Special form]]@\@~
+   @Send(FunList {@f[@Parm(Fun) @Parm(Args, default <>)] @>[@i[Special form]]@\})@~
+   @Sindex@Parmquote(Fun)@~
+   @Imbed(Nolabel, undef '@Imbed(Funlabel,
+			          def <@Label{@Parm(Funlabel)-spec}>,
+			          undef <@Label{@Parm(Fun)-spec}>)')@~
+   @Begin(Defbody)@Tabclear ")
+@Form(Defspec1 = "@Begin(Undefbody)@Comment(Tabset?)@~
+   @f[@Imbed(Package, def '@Parm(Package):')@Parm(Fun) @Parm(Args, default <>)] @>[@i[Special form]]@\@~
+   @Send(FunList {@f[@Parm(Fun) @Parm(Args, default <>)] @>[@i[Special form]]@\})@~
+   @Sindex@Parmquote(Fun)@~
+   @Imbed(Nolabel, undef '@Imbed(Funlabel,
+			          def <@Label{@Parm(Funlabel)-spec}>,
+			          undef <@Label{@Parm(Fun)-spec}>)')@~
+   @End(Undefbody)")
+@Commandstring(Enddefspec = "@End(Defbody)@End(Defenvironment)")
+
+@Textform(Xindent = "@hsp(2.0em)")
+@Textform(Xsepr = "@hsp(0.5em)")
+@Textform(Def = "@Index@Parmquote(Text)@i@Parmquote(Text)")
+@Textform(Index = "@Indexentry{Key {@Parm(Text) !1},
+             Entry {@r[@Parm(Text)]@Xsepr()}, Number {@r[@Parmvalue(Page)]}}@'")
+@Form(PossiblyIndexedRef = "@Indexentry{Key {@Parm(K) !1},
+             Entry {@r[@Parm(F)]@Xsepr()}, Number {@r[@Parmvalue(Page)]}}@Parm(E)")
+@Textform(Index1 = "@Indexentry{Key {@Parm(Text) !1},
+             Entry {@r[@Parm(Text)]@Xsepr()}}@'")
+@Form(Index2 = "@Index1@Parmquote(P)@Indexentry{Key {@Parm(P) !2 @Parm(S)},
+         Entry {@Xindent()@r[@Parm(S)]@Xsepr()}, Number {@Parmvalue(Page)}}@'")
+@Form(Seealso = "@Index1@Parmquote(P)@Indexentry{Key {@Parm(P) !3 @Parm(S)},
+         Entry {@Xindent()@Xindent()@r[See also:]}, Number @Parmquote(S)}@'")
+@Form(Xindex = "@Indexentry{Key {@Parm(X) @Parm(T) 1},
+         Entry {@Parm(Q, default <>)@Parm(P)@Parm(R, default <>)@f[ ]@r[@Parm(T)]@Xsepr()},
+	 Number {@b[@Parmvalue(Page)]}}@'")
+@Form(Xindexref = "@Indexentry{Key {@Parm(X) @Parm(T) 1},
+         Entry {@Parm(Q, default <>)@Parm(P)@Parm(R, default <>)@f[ ]@r[@Parm(T)]@Xsepr()},
+	 Number {@Parmvalue(Page)}}@'")
+@Form(Xindex1 = "@Indexentry{Key {@Parm(X) @Parm(T) 1},
+         Entry {@Parm(Q, default <>)@Parm(P)@Parm(R, default <>)@f[ ]@r[@Parm(T)]@Xsepr()}}@'")
+@Form(Xindex2 = "@Xindex1(X @Parmquote(X), T @Parmquote(T),
+			  P @Parmquote(P)@Imbed(Q, def <, Q @Parmquote(Q)>)@Imbed(R, def <, R @Parmquote(R)>))@~
+         @Indexentry{Key {@Parm(X) @Parm(T) 2 @Parm(S)},
+		     Entry {@Xindent()@Parm(S)@Xsepr()},
+		     Number {@b[@Parmvalue(Page)]}}@'")
+@Form(Xindexref2 = "@Xindex1(X @Parmquote(X), T @Parmquote(T),
+			     P @Parmquote(P)@Imbed(Q, def <, Q @Parmquote(Q)>)@Imbed(R, def <, R @Parmquote(R)>))@~
+         @Indexentry{Key {@Parm(X) @Parm(T) 2 @Parm(S)},
+		     Entry {@Xindent()@Parm(S)@Xsepr()},
+		     Number {@Parmvalue(Page)}}@'")
+@Form(Xseealso = "@Xindex1(X @Parmquote(X), T @Parmquote(T),
+			   P @Parmquote(P)@Imbed(Q, def <, Q @Parmquote(Q)>)@Imbed(R, def <, R @Parmquote(R)>))@~
+         @Indexentry{Key {@Parm(X) @Parm(T) 3 @Parm(S)},
+		     Entry {@Xindent()@Xindent()@r[See also:]},
+		     Number @Parmquote(S)}}@'")
+
+@Textform(Cindex = "@Index@Parmquote(Text)@'")
+
+@Textform(Findex = "@Case(IndexFuns, Yes '@Xindex(T {function}, X {@Parm(Text)}, P {@f[@Parm(Text)]})')@'")
+@Textform(Findexref = "@Case(IndexFuns, Yes '@Xindexref(T {function}, X {@Parm(Text)}, P {@f[@Parm(Text)]})')@'")
+@Form(Findex2 = "@Case(IndexFuns, Yes '@Xindex2(T {function}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S))')@'")
+@Form(Fseealso = "@Case(IndexFuns, Yes '@Xseealso(T {function}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S))')@'")
+
+@Textform(Mindex = "@Case(IndexFuns, Yes '@Xindex(T {macro}, X {@Parm(Text)}, P {@f[@Parm(Text)]})')@'")
+@Textform(Mindexref = "@Case(IndexFuns, Yes '@Xindexref(T {macro}, X {@Parm(Text)}, P {@f[@Parm(Text)]})')@'")
+@Form(Mindex2 = "@Case(IndexFuns, Yes '@Xindex2(T {macro}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S))')@'")
+@Form(Mseealso = "@Case(IndexFuns, Yes '@Xseealso(T {macro}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S))')@'")
+
+@Textform(Sindex = "@Case(IndexFuns, Yes '@Xindex(T {special form}, X {@Parm(Text)}, P {@f[@Parm(Text)]})')@'")
+@Textform(Sindexref = "@Case(IndexFuns, Yes '@Xindexref(T {special form}, X {@Parm(Text)}, P {@f[@Parm(Text)]})')@'")
+@Form(Sindex2 = "@Case(IndexFuns, Yes '@Xindex2(T {special form}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S))')@'")
+@Form(Sseealso = "@Case(IndexFuns, Yes '@Xseealso(T {special form}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S))')@'")
+
+@Textform(Vindex = "@Xindex(T {variable}, X {@Parm(Text)}, P {@f[@Parm(Text)]}, Q {@f[*]}, R{@f[*]})@'")
+@Textform(Vxindex = "@Xindex(T {variable}, X {@Parm(Text)}, P {@f[@Parm(Text)]})@'")
+@Textform(Vindexref = "@Xindexref(T {variable}, X {@Parm(Text)}, P {@f[@Parm(Text)]}, Q {@f[*]}, R{@f[*]})@'")
+@Form(Vindex2 = "@Xindex2(T {variable}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S), Q {@f[*]}, R{@f[*]})@'")
+@Form(Vseealso = "@Xseealso(T {variable}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S), Q {@f[*]}, R{@f[*]})@'")
+
+@Textform(Conindex = "@Xindex(T {constant}, X {@Parm(Text)}, P {@f[@Parm(Text)]})@'")
+@Textform(Conindexref = "@Xindexref(T {constant}, X {@Parm(Text)}, P {@f[@Parm(Text)]})@'")
+@Form(Conindex2 = "@Xindex2(T {constant}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S))@'")
+@Form(Conseealso = "@Xseealso(T {constant}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S))@'")
+
+@Textform(Kindex = "@Xindex(T {keyword}, X {@Parm(Text)}, P {@f[@Parm(Text)]}, Q {@f[:]})@'")
+@Textform(Kindexref = "@Xindexref(T {keyword}, X {@Parm(Text)}, P {@f[@Parm(Text)]}, Q {@f[:]})@'")
+@Form(Kindex2 = "@Xindex2(T {keyword}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S), Q {@f[:]})@'")
+@Form(Kindexref2 = "@Xindexref2(T {keyword}, X {@Parm(K)}, P {@f[@Parm(K)]}, S @Parmquote(S), Q {@f[:]})@'")
+@Form(Kseealso = "@Xseealso(T {keyword}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S), Q {@f[:]})@'")
+
+@Textform(Declindex = "@Xindex(T {declaration}, X {@Parm(Text)}, P {@f[@Parm(Text)]})@'")
+@Textform(Declindexref = "@Xindexref(T {declaration}, X {@Parm(Text)}, P {@f[@Parm(Text)]})@'")
+@Form(Declindex2 = "@Xindex2(T {declaration}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S))@'")
+@Form(Declseealso = "@Xseealso(T {declaration}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S))@'")
+
+@Textform(Typeindex = "@Xindex(T {type specifier}, X {@Parm(Text)}, P {@f[@Parm(Text)]})@'")
+@Textform(Typeindexref = "@Xindexref(T {type specifier}, X {@Parm(Text)}, P {@f[@Parm(Text)]})@'")
+@Form(Typeindex2 = "@Xindex2(T {type specifier}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S))@'")
+@Form(Typeseealso = "@Xseealso(T {type specifier}, X {@Parm(P)}, P {@f[@Parm(P)]}, S @Parmquote(S))@'")
+
+@Textform(Funref = "@f[@Parm(Text) ]@~
+    @r[(page @Pageref(@Parm(Text)-fun))]@Findexref@Parmquote(Text)@;")
+@Textform(Funreftab = "@f[@Parm(Text) ]@\@r[(page @Pageref(@Parm(Text)-fun))]@Findexref@Parmquote(Text)@;")
+@Form(Xfunref = "@f[@Parm(X) ]@~
+    @r[(page @Pageref(@Parm(L)-fun))]@Findexref@Parmquote(X)@;")
+@Textform(Macref = "@f[@Parm(Text) ]@~
+    @r[(page @Pageref(@Parm(Text)-mac))]@Mindexref@Parmquote(Text)@;")
+@Textform(Macreftab = "@f[@Parm(Text) ]@\@r[(page @Pageref(@Parm(Text)-mac))]@Mindexref@Parmquote(Text)@;")
+@Form(Xmacref = "@f[@Parm(X) ]@~
+    @r[(page @Pageref(@Parm(L)-mac))]@Mindexref@Parmquote(X)@;")
+@Textform(Specref = "@f[@Parm(Text) ]@~
+    @r[(page @Pageref(@Parm(Text)-spec))]@Sindexref@Parmquote(Text)@;")
+@Textform(Specreftab = "@f[@Parm(Text) ]@\@r[(page @Pageref(@Parm(Text)-spec))]@Sindexref@Parmquote(Text)@;")
+@Form(XSpecref = "@f[@Parm(X) ]@~
+    @r[(page @Pageref(@Parm(L)-spec))]@Sindexref@Parmquote(X)@;")
+@Textform(Var = "@f[*@Parm(Text)*]")
+@Textform(Varref = "@f[*@Parm(Text)* ]@~
+    @r[(page @Pageref(@Parm(Text)-var))]@Vindexref@Parmquote(Text)@;")
+@Form(Xvarref = "@f[*@Parm(X)* ]@~
+    @r[(page @Pageref(@Parm(L)-var))]@Vindexref@Parmquote(X)@;")
+@Textform(Conref = "@f[@Parm(Text) ]@~
+    @r[(page @Pageref(@Parm(Text)-con))]@Conindexref@Parmquote(Text)@;")
+@Form(Xconref = "@f[@Parm(X) ]@~
+    @r[(page @Pageref(@Parm(L)-con))]@Conindexref@Parmquote(X)@;")
+@Form(Kwdref = "@f[:@Parm(K) ]@~
+    @r[(page @Pageref(@Parm(F)-@Parm(K)-kwd))]@Kindexref2(S {for@f[ @Parm(F)]},
+						      K @Parmquote(K))@;")
+@Form(SubKwdref = "@f[:@Parm(K)] @~
+    @r[(page @Pageref(@Parm(F)-@Parm(O)-@Parm(K)-kwd))]@~
+	@Kindexref2(S {for@f[ :@Parm(O) ]option to@f[ @Parm(F)]},
+		    K @Parmquote(K))")
+
+@Indexentry(Key {  1}, Entry {@IndexHeadings[Index]@Blankspace(1)@Begin(IndexEnvironment)})
+@Indexentry(Key {~~~ }, Entry {@End(IndexEnvironment)})
+
+@Textform(IndexCleanup = " ")
diff --git a/docs/doc-diff.lisp b/docs/doc-diff.lisp
new file mode 100644
index 000000000..7f232bb68
--- /dev/null
+++ b/docs/doc-diff.lisp
@@ -0,0 +1,384 @@
+;;; -*- Package: Hemlock -*-
+;;;
+;;;    A hack to compare the functions and variables defined by the hemlock
+;;; documents with the ones defined in the core.
+;;;
+;;; Use GROVEL-LABELS.
+;;;
+
+(in-package "HEMLOCK")
+
+
+(defvar *defined-labels* (make-hash-table :test #'equal))
+
+;;; Ignore these because they would be internal (not for the user) if Hemlock
+;;; had that kind of definition power.
+;;;
+(defvar *hvars-to-ignore*
+  '(auto-save-state current-package draft-information headers-buffer
+    headers-information message-buffer message-information spell-information
+    default-message-modeline-fields current-compile-server current-eval-server))
+
+(defvar *cmds-to-ignore*
+  '("Beginning Of Parse" "Echo Area Backward Character"
+    "Echo Area Backward Word" "Echo Area Delete Previous Character"
+    "Echo Area Kill Previous Word" "Do Nothing" "Illegal" "Insert Parse Default"
+    "Italic Comment Mode" "Kill Parse" "Lisp Insert )" "Next Parse"
+    "Previous Parse" "Start Italic Comment" "Insert ()" "Move over )"
+    "Current Compile Server" "Current Eval Server" "Defhvar" "Defindent"))
+
+;;; These do not get removed from *defined-labels* because they are not
+;;; command names, variable names, or "HI" function names.  These are now
+;;; documented in the Command Implementor's Manual, but we don't want to call
+;;; FIND-UNDOCUMENTED-SYMBOLS on these packages due to all the uninteresting
+;;; symbols they hold.  In the case of routines defined in the "ED" package,
+;;; they aren't exported anyway.
+;;;
+;;; Do not add names to this list that occur in the ED package and have
+;;; asterisks (e.g., specials like *kill-ring* and *last-search-string*).  Use
+;;; the variable below, *unimplemented-strings-to-ignore*.
+;;;
+(defvar *unimplemented-to-ignore*
+  '(spell:spell-try-word spell:maybe-read-spell-dictionary spell:spell-root-word
+    spell:max-entry-length spell:spell-read-dictionary
+    spell:spell-collect-close-words spell:correct-spelling
+    spell:spell-add-entry spell:spell-remove-entry spell:spell-root-flags
+
+    ext:translate-character ext:define-keyboard-modifier
+    ext:define-mouse-code ext:translate-mouse-character ext:define-keysym
+
+    dired:find-file dired:make-directory dired:delete-file
+    dired:pathnames-from-pattern dired:copy-file dired:rename-file
+
+    get-search-pattern current-mark file-compile kill-characters
+    indent-region-for-commands display-page-directory previous-buffer
+    sentence-offset interactive buffer-default-pathname
+    add-definition-dir-translation push-buffer-mark do-active-group
+    paragraph-offset word-offset create-slave make-region-undo
+    process-file-options pre-command-parse-check top-level-offset fill-region
+    pop-buffer-mark region-eval get-current-compile-server mark-top-level-form
+    ed page-directory find-file-buffer deactivate-region valid-spot
+    buffer-history kill-region string-eval backward-up-list
+    define-file-type-hook buffer-history check-region-query-size
+    change-to-buffer region-compile current-region mark-paragraph form-offset
+    check-region-active read-buffer-file fill-region-by-paragraphs
+    forward-up-list define-file-option buffer-mark region-active-p
+    inside-defun-p activate-region start-defun-p delete-buffer-if-possible
+    get-current-eval-server goto-page write-buffer-file save-for-undo
+    eval-form-in-server indent-region in-lisp pathname-to-buffer-name
+    page-offset defun-region delete-definition-dir-translation
+    delete-horizontal-space supply-generic-pointer-up-function))
+
+;;; This is just like *unimplemented-to-ignore*, but these names are hard to
+;;; deal with in *unimplemented-to-ignore* due to one of the following reasons:
+;;;    Scribe,
+;;;    The name is an example and truly unimplemented, or
+;;;    The name has asterisks in core but not in the Scribe label name.
+;;;
+(defvar *unimplemented-strings-to-ignore*
+  '("SAMPLECOMMAND" "SAMPLEVARIABLE"
+
+    "MARK-GTR" "MARK-NEQ" "MARK-LSS" "MARK-LEQ" "MARK-GEQ" "MARK-EQL"
+    "LINE-GEQ" "LINE-LSS" "LINE-GTR" "LINE-LEQ"
+
+    "KILL-RING" "LAST-SEARCH-STRING" "EPHEMERALLY-ACTIVE-COMMAND-TYPES"
+    "HEMLOCK-BEEP" "LAST-SEARCH-PATTERN" "ACTIVE-FILE-GROUP"
+
+    "ERROR-FUNCTION" "REPORT-FUNCTION" "UPDATE-DEFAULT" "YESP-FUNCTION"
+    "CLOBBER-DEFAULT" "RECURSIVE-DEFAULT"))
+
+
+(defun grovel-labels (aux-files output-file)
+  "Read each of the files in the list Aux-Files to find what commands are
+  documented, then compare it with the commands defined in core.  We write
+  documentation forms to the output-file for things defined but not documented,
+  and we put a list of things documented but not implemented in a comment."
+  (clrhash *defined-labels*)
+  (dolist (labels-file aux-files)
+    (with-open-file (s labels-file :direction :input)
+      (loop
+	(let ((l (read-line s nil nil)))
+	  (unless l (return))
+	  (multiple-value-bind (kind label)
+			       (parse-label l)
+	    (when kind
+	      (let ((old (gethash label *defined-labels*)))
+		(when (and old
+			   (not (eq old :hemlock-variable))
+			   (not (eq kind :hemlock-variable)))
+		  (format t "~S multiply defined as ~S and ~S.~%"
+			  label old kind))
+		(setf (gethash label *defined-labels*) kind))))))))
+  (with-open-file (s output-file :direction :output
+		     :if-exists :new-version)
+    (map-undocumented-hemlock-things *command-names* :command s
+				     #'document-command *cmds-to-ignore*)
+    (terpri s)
+    (map-undocumented-hemlock-things *global-variable-names* :hemlock-variable s
+				     #'document-variable *hvars-to-ignore*)
+    (terpri s)
+    (find-undocumented-symbols "HEMLOCK-INTERNALS" s)
+    (terpri s)
+    (write-line "@begin[comment]" s)
+    (let ((ignored-symbols (copy-list *unimplemented-to-ignore*))
+	  (ignored-strings (copy-list *unimplemented-strings-to-ignore*)))
+      (maphash #'(lambda (name type)
+		   (cond ((member name ignored-symbols
+				  :test #'string= :key #'symbol-name)
+			  (setf ignored-symbols
+				(delete name ignored-symbols
+					:test #'string= :key #'symbol-name)))
+			 ((member name ignored-strings :test #'string=)
+			  (setf ignored-strings
+				(delete name ignored-strings :test #'string=)))
+			 (t
+			  (format s "~A ~S is not implemented.~%" type name))))
+	       *defined-labels*)
+      (when ignored-symbols
+	(format s
+		"~&*******************  These ignored \"unimplemented\" symbols ~
+		 were not used.~%~S~%********************~2%"
+		ignored-symbols))
+      (when ignored-strings
+	(format s
+		"~&*******************  These ignored \"unimplemented\" strings ~
+		 were not used.~%~S~%********************~2%"
+		ignored-strings)))
+    (write-line "@end[comment]" s)
+    (values)))
+
+
+;;; Iterate over a string table, checking that each thing has a corresponding
+;;; label of the specified kind.  If there is no label, then call the function
+;;; with the value and stream.  If the label is the wrong kind, print a comment
+;;; on Stream before calling the function.  We also blast the label so we will
+;;; know that it was defined.
+;;;
+(defun map-undocumented-hemlock-things (table kind stream function ignore-stuff)
+  (do-strings (string value table)
+    (let* ((lab (nstring-upcase (remove #\space string)))
+	   (lkind (gethash lab *defined-labels*)))
+      (cond ((and (eq kind :command)
+		  (member (command-name value) ignore-stuff
+			  :test #'string-equal))
+	     (setf ignore-stuff
+		   (remove (command-name value) ignore-stuff
+			   :test #'string-equal)))
+	    ((member value ignore-stuff)
+	     (setf ignore-stuff (remove value ignore-stuff)))
+	    (t
+	     (unless (eq lkind kind)
+	       (when lkind
+		 (format stream
+			 "@comment{~S documented as a ~A, ~
+			  but defined as a ~A.}~2%"
+			 string lkind kind))
+	       (funcall function value stream))))
+      (remhash lab *defined-labels*)))
+  (when ignore-stuff
+    (format stream
+	    "~&********************  These ignored ~Ss were not used.~%~
+	     ~S~%********************~2%"
+	    kind ignore-stuff)))
+
+
+
+(defvar *undocumented-symbols-to-ignore*
+  '(make-xwindow-like-hwindow mark/= default-font input-waiting mark=
+    modify-kbdmac-stream delete-line-font-marks font-mark hemlock-output-stream
+    command reprompt store-cut-string make-kbdmac-stream window window-font
+    delete-font-mark fetch-cut-string fun-defined-from-pathname
+    hemlock-region-stream line< buffer mark< move-font-mark
+    editor-describe-function enter-window-autoraise ring mark<= search-pattern
+    *print-region* mark>= string-table line mark> line> line>= line<=
+    after-editor-initializations *invoke-hook* defhvar))
+
+(defun find-undocumented-symbols (package stream)
+  (let ((ignore-symbols *undocumented-symbols-to-ignore*))
+    (do-external-symbols (sym package)
+      (let* ((name (string-trim "*" (symbol-name sym)))
+	     (kind (gethash name *defined-labels*)))
+	(ecase kind
+	  ((nil)
+	   (if (member sym ignore-symbols)
+	       (setf ignore-symbols (remove sym ignore-symbols))
+	       (let ((*standard-output* stream))
+		 ;; Bind this to squelch CLOS/DESCRIBE bad interaction.
+		 (describe sym)
+		 (terpri)
+		 (terpri))))
+	  ((:function :macro :special-form)
+	   (let ((def (cond ((macro-function sym) :macro)
+				((special-form-p sym) :special-form)
+				((fboundp sym) :function))))
+		 (unless (eq kind def)
+		   (format stream
+			   "@comment{~S is ~:[not defined~;~:*defined as a ~A~]~
+			    , but is documented as a ~A}~%" sym def kind))))
+	  (:constant
+	   (unless (constantp sym)
+	     (format stream
+		     "@comment{~S is documented as a constant, but isn't ~
+		      defined.}~%"
+		     sym)))
+	  (:variable
+	   (unless (or (get sym 'lisp::globally-special)
+		       (string= name (symbol-name sym)))
+	       (format stream
+		       "@comment{~S is documented as a special, but isn't ~
+			declared.}~%"
+		       sym))))
+	(remhash name *defined-labels*)))
+    (when ignore-symbols
+      (format stream
+	      "~&********************  These ignored symbols were not used.~%~
+	       ~S~%********************~2%"
+	      ignore-symbols))))
+
+  
+(defvar *suffix-codes* (make-hash-table :test #'equal))
+(setf (gethash "COM" *suffix-codes*) :command)
+(setf (gethash "HVAR" *suffix-codes*) :hemlock-variable)
+(setf (gethash "FUN" *suffix-codes*) :function)
+(setf (gethash "MAC" *suffix-codes*) :macro)
+(setf (gethash "SPEC" *suffix-codes*) :special-form)
+(setf (gethash "VAR" *suffix-codes*) :variable)
+(setf (gethash "CON" *suffix-codes*) :constant)
+
+
+;;; Parse a line from a Scribe .Aux file, returning the kind of the thing
+;;; documented and its name.
+;;;
+(defun parse-label (entry)
+  (let* ((end (search "), Value" entry :start2 28))
+	 (hpos (position #\- entry :start 28 :end end :from-end t)))
+    (if hpos
+	(let* ((suffix (subseq entry (1+ hpos) end))
+	       (found (gethash suffix *suffix-codes*)))
+	  (if found
+	      (values found (subseq entry 28 hpos))
+	      (values nil nil)))
+	(values nil nil))))
+
+
+(defun document-command (command stream)
+  (format stream "@defcom[com ~S" (command-name command))
+  (let ((binds (command-bindings command)))
+    (when binds
+      (format stream ", bind (")
+      (print-command-bindings binds stream)
+      (format stream ")"))
+    (format stream "]~%~A~%@enddefcom~2%"
+	    (command-documentation command))))
+
+
+(defun document-variable (var stream)
+  (let* ((name (variable-name var :global))
+	 (len (length name)))
+    (unless (string= name "Mode Hook" :start1 (- len 9))
+      (format stream "@defhvar[var ~S~@[, val {~(~S~)}~]]~%~A~%@enddefhvar~2%"
+	      name (variable-value var :global)
+	      (variable-documentation var :global)))))
+
+
+(defvar *definition-pattern*
+  (new-search-pattern :string-insensitive :forward "
+@def"))
+
+(defvar *insert-pattern*
+  (new-search-pattern :string-insensitive :backward "
+
+"))
+
+(defvar *definition-macros* (make-hash-table :test #'equal))
+(setf (gethash "COM" *definition-macros*) :command)
+(setf (gethash "HVAR" *definition-macros*) :hemlock-variable)
+(setf (gethash "UN" *definition-macros*) :function)
+(setf (gethash "MAC" *definition-macros*) :macro)
+(setf (gethash "SPEC" *definition-macros*) :special-form)
+(setf (gethash "VAR" *definition-macros*) :variable)
+(setf (gethash "CON" *definition-macros*) :constant)
+(setf (gethash "COM1" *definition-macros*) :command)
+(setf (gethash "HVAR1" *definition-macros*) :hemlock-variable)
+(setf (gethash "UN1" *definition-macros*) :function)
+(setf (gethash "MAC1" *definition-macros*) :macro)
+(setf (gethash "SPEC1" *definition-macros*) :special-form)
+(setf (gethash "VAR1" *definition-macros*) :variable)
+(setf (gethash "CON1" *definition-macros*) :constant)
+
+(defun parse-doc-macro (line)
+  (let* ((bracket (or (position #\[ line)
+		      (error "No opening #\[ ???")))
+	 (name (nstring-upcase (subseq line 4 bracket)))
+	 (kind (gethash name *definition-macros*))
+	 (nend (case (char line (+ bracket 5))
+		 (#\"
+		  (position #\" line :start (+ bracket 6)))
+		 (#\{
+		  (position #\} line :start (+ bracket 6)))
+		 (t nil))))
+    (cond ((not kind)
+	   (format t "Unknown definition macro:~%~A~%" line)
+	   (values nil nil))
+	  ((not nend)
+	   (format t "Can't parse name:~%~A~%" line)
+	   (values nil nil))
+	  (t
+	   (values kind (subseq line (+ bracket 6) nend))))))
+
+
+(defun annotate-with-online-documentation (input-file output-file)
+  "Take a Scribe input file and produce a Scribe output file with the online
+  documentation for each thing inserted before the offline documentation."
+  (let* ((temp-buffer (make-buffer "Annotate Temporary"))
+	 (point (buffer-point temp-buffer)))
+    (unwind-protect
+	(progn
+	  (read-file input-file point)
+	  (buffer-start point)
+	  (loop
+	    (unless (find-pattern point *definition-pattern*)
+	      (return))
+	    (line-offset point 1)
+	    (multiple-value-bind
+		(kind name)
+		(parse-doc-macro (line-string (mark-line point)))
+	      (when kind
+		(with-mark ((insert point :left-inserting))
+		  (unless (find-pattern insert *insert-pattern*)
+		    (buffer-start insert))
+		  (line-offset insert 2 0)
+		  (with-output-to-mark (stream insert :full)
+		    (ecase kind
+		      ((:function :macro :special-form :constant)
+		       (format stream "@begin[format]~%")
+		       (let ((*standard-output* stream))
+			 (describe (intern (string-upcase name))))
+		       (format stream "~&@end[format]~2%"))
+		      (:variable
+		       (format stream "@begin[format]~%")
+		       (let ((*standard-output* stream))
+			 (describe (intern (concatenate 'string "*"
+							(string-upcase name)
+							"*"))))
+		       (format stream "~&@end[format]~2%"))
+		      (:command
+		       (let ((command (getstring name *command-names*)))
+			 (when command
+			   (format stream "@begin[verse]~%Command @hid[~A]:  ("
+				   (command-name command))
+			   (print-command-bindings (command-bindings command)
+						   stream)
+			   (format stream ")~%@end[verse]~%~A~2&"
+				   (command-documentation command)))))
+		      (:hemlock-variable
+		       (let ((var (getstring name *global-variable-names*)))
+			 (when var
+			   (format stream "@begin[verse]~%Variable @hid[~A]: ~
+			   (~(~S~))~%@end[verse]~%~A~2&"
+				   (variable-name var :global)
+				   (variable-value var :global)
+				   (variable-documentation var :global))))))
+		    )))))
+	  (write-file (buffer-region temp-buffer) output-file))
+      (delete-buffer temp-buffer))))
diff --git a/docs/hem/cim/aux-sys.mss b/docs/hem/cim/aux-sys.mss
new file mode 100644
index 000000000..15e215eaf
--- /dev/null
+++ b/docs/hem/cim/aux-sys.mss
@@ -0,0 +1,682 @@
+@comment{-*- Dictionary: /usr/lisp/scribe/hem/hem; Mode: spell; Package: Hemlock; Log: /usr/lisp/scribe/hem/hem-docs.log -*-}
+@chapter (Auxiliary Systems)
+This chapter describes utilities that some implementations of @hemlock may
+leave unprovided or unsupported.
+
+
+@section[Key-events]
+@index(I/O)
+@index[keyboard input]
+@index[input, keyboard]
+@index[mouse input]
+@index[input, mouse]
+@label[key-events]
+
+These routines are defined in the @f["EXTENSIONS"] package since other projects
+have often used @hemlock's input translations for interfacing to CLX.
+
+
+@subsection[Introduction]
+
+The canonical representation of editor input is a key-event structure.  Users
+can bind commands to keys (see section @ref[key-bindings]), which are non-zero
+length sequences of key-events.  A key-event consists of an identifying token
+known as a @i[keysym] and a field of bits representing modifiers.  Users define
+keysyms, integers between 0 and 65535 inclusively, by supplying names that
+reflect the legends on their keyboard's keys.  Users define modifier names
+similarly, but the system chooses the bit and mask for recognizing the
+modifier.  You can use keysym and modifier names to textually specify
+key-events and Hemlock keys in a @f[#k] syntax.  The following are some
+examples:
+@begin[programexample]
+   #k"C-u"
+   #k"Control-u"
+   #k"c-m-z"
+   #k"control-x meta-d"
+   #k"a"
+   #k"A"
+   #k"Linefeed"
+@end[programexample]
+This is convenient for use within code and in init files containing
+@f[bind-key] calls.
+
+The @f[#k] syntax is delimited by double quotes, but the system parses the
+contents rather than reading it as a Common Lisp string.  Within the double
+quotes, spaces separate multiple key-events.  A single key-event optionally
+starts with modifier names terminated by hyphens.  Modifier names are
+alphabetic sequences of characters which the system uses case-insensitively.
+Following modifiers is a keysym name, which is case-insensitive if it consists
+of multiple characters, but if the name consists of only a single character,
+then it is case-sensitive.
+
+You can escape special characters @dash hyphen, double quote, open angle
+bracket, close angle bracket, and space @dash with a backslash, and you can
+specify a backslash by using two contiguously.  You can use angle brackets to
+enclose a keysym name with many special characters in it.  Between angle
+brackets appearing in a keysym name position, there are only two special
+characters, the closing angle bracket and backslash.
+
+
+
+@subsection[Interface]
+
+All of the following routines and variables are exported from the "EXTENSIONS"
+("EXT") package.
+
+
+@defun[fun {define-keysym}, args {@i[keysym] @i[preferred-name] @rest @i[other-names]}]
+This function establishes a mapping from @i[preferred-name] to @i[keysym] for
+purposes of @f[#k] syntax.  @i[Other-names] also map to @i[keysym], but the
+system uses @i[preferred-name] when printing key-events.  The names are
+case-insensitive simple-strings; however, if the string contains a single
+character, then it is used case-sensitively.  Redefining a keysym or re-using
+names has undefined effects.
+
+You can use this to define unused keysyms, but primarily this defines keysyms
+defined in the @i[X Window System Protocol, MIT X Consortium Standard, X
+Version 11, Release 4].  @f[translate-key-event] uses this knowledge to
+determine what keysyms are modifier keysyms and what keysym stand for
+alphabetic key-events.
+@enddefun
+
+
+@defun[fun {define-mouse-keysym}, args {@i[button] @i[keysym] @i[name] @i[shifted-bit] @i[event-key]}]
+This function defines @i[keysym] named @i[name] for key-events representing the
+X @i[button] cross the X @i[event-key] (@kwd[button-press] or
+@kwd[button-release]).  @i[Shifted-bit] is a defined modifier name that
+@f[translate-mouse-key-event] sets in the key-event it returns whenever the X
+shift bit is set in an incoming event.
+
+Note, by default, there are distinct keysyms for each button distinguishing
+whether the user pressed or released the button.
+
+@i[Keysym] should be an one unspecified in @i[X Window System Protocol, MIT X
+Consortium Standard, X Version 11, Release 4].
+@enddefun
+
+
+@defun[fun {name-keysym}, args {@i[name]}]
+This function returns the keysym named @i[name].  If @i[name] is unknown, this
+returns @nil.
+@enddefun
+
+@defun[fun {keysym-names}, args {@i[keysym]}]
+This function returns the list of all names for @i[keysym].  If @i[keysym] is
+undefined, this returns @nil.
+@enddefun
+
+@defun[fun {keysym-preferred-name}, args {@i[keysym]}]
+This returns the preferred name for @i[keysym], how it is typically printed.
+If @i[keysym] is undefined, this returns @nil.
+@enddefun
+
+@defun[fun {define-key-event-modifier}, args {@i[long-name] @i[short-name]}]
+This establishes @i[long-name] and @i[short-name] as modifier names for
+purposes of specifying key-events in @f[#k] syntax.  The names are
+case-insensitive simple-strings.  If either name is already defined, this
+signals an error.
+
+The system defines the following default modifiers (first the long name,
+then the short name):
+@begin[Itemize]
+@f["Hyper"], @f["H"]
+
+@f["Super"], @f["S"]
+
+@f["Meta"], @f["M"]
+
+@f["Control"], @f["C"]
+
+@f["Shift"], @f["Shift"]
+
+@f["Lock"], @f["Lock"]
+@end[Itemize]
+@enddefun
+
+
+@defvar[var {all-modifier-names}]
+This variable holds all the defined modifier names.
+@enddefvar
+
+
+@defun[fun {define-clx-modifier}, args {@i[clx-mask] @i[modifier-name]}]
+This function establishes a mapping from @i[clx-mask] to a defined key-event
+@i[modifier-name].  @f[translate-key-event] and @f[translate-mouse-key-event]
+can only return key-events with bits defined by this routine.
+
+The system defines the following default mappings between CLX modifiers and
+key-event modifiers:
+@begin[Itemize]
+@f[(xlib:make-state-mask :mod-1)    -->  "Meta"]
+
+@f[(xlib:make-state-mask :control)  -->  "Control"]
+
+@f[(xlib:make-state-mask :lock)     -->  "Lock"]
+
+@f[(xlib:make-state-mask :shift)    -->  "Shift"]
+@end[Itemize]
+@enddefun
+
+
+@defun[fun {make-key-event-bits}, args {@rest @i[modifier-names]}]
+This function returns bits suitable for @f[make-key-event] from the supplied
+@i[modifier-names].  If any name is undefined, this signals an error.
+@enddefun
+
+@defun[fun {key-event-modifier-mask}, args {@i[modifier-name]}]
+This function returns a mask for @i[modifier-name].  This mask is suitable for
+use with @f[key-event-bits].  If @i[modifier-name] is undefined, this signals
+an error.
+@enddefun
+
+@defun[fun {key-event-bits-modifiers}, args {@i[bits]}]
+This returns a list of key-event modifier names, one for each modifier
+set in @i[bits].
+@enddefun
+
+
+@defun[fun {translate-key-event}, args {@i[display] @i[scan-code] @i[bits]}]
+This function translates the X @i[scan-code] and X @i[bits] to a key-event.
+First this maps @i[scan-code] to an X keysym using @f[xlib:keycode->keysym]
+looking at @i[bits] and supplying index as @f[1] if the X shift bit is on,
+@f[0] otherwise.
+
+If the resulting keysym is undefined, and it is not a modifier keysym,
+then this signals an error.  If the keysym is a modifier key, then this
+returns @nil.
+
+If these conditions are satisfied
+@begin[Itemize]
+The keysym is defined.
+
+The X shift bit is off.
+
+The X lock bit is on.
+
+The X keysym represents a lowercase letter.
+@end[Itemize]
+then this maps the @i[scan-code] again supplying index as @f[1] this time,
+treating the X lock bit as a caps-lock bit.  If this results in an undefined
+keysym, this signals an error.  Otherwise, this makes a key-event with the
+keysym and bits formed by mapping the X bits to key-event bits.
+
+Otherwise, this makes a key-event with the keysym and bits formed by
+mapping the X bits to key-event bits.
+@enddefun
+
+
+@defun[fun {translate-mouse-key-event}, args {@i[scan-code] @i[bits] @i[event-key]}]
+This function translates the X button code, @i[scan-code], and modifier bits,
+@i[bits], for the X @i[event-key] into a key-event.  See
+@f[define-mouse-keysym].
+@enddefun
+
+@defun[fun {make-key-event}, args {@i[object] @i[bits]}]
+This function returns a key-event described by @i[object] with @i[bits].
+@i[Object] is one of keysym, string, or key-event.  When @i[object] is a
+key-event, this uses @f[key-event-keysym].  You can form @i[bits] with
+@f[make-key-event-bits] or @f[key-event-modifier-mask].
+@enddefun
+
+@defun[fun {key-event-p}, args {@i[object]}]
+This function returns whether @i[object] is a key-event.
+@enddefun
+
+@defun[fun {key-event-bits}, args {@i[key-event]}]
+This function returns the bits field of a @i[key-event].
+@enddefun
+
+@defun[fun {key-event-keysym}, args {@i[key-event]}]
+This function returns the keysym field of a @i[key-event].
+@enddefun
+
+@defun[fun {char-key-event}, args {@i[character]}]
+This function returns the key-event associated with @i[character].  You can
+associate a key-event with a character by @f[setf]'ing this form.
+@enddefun
+
+@defun[fun {key-event-char}, args {@i[key-event]}]
+This function returns the character associated with @i[key-event].  You can
+associate a character with a key-event by @f[setf]'ing this form.  The system
+defaultly translates key-events in some implementation dependent way for text
+insertion; for example, under an ASCII system, the key-event @f[#k"C-h"], as
+well as @f[#k"backspace"] would map to the Common Lisp character that causes a
+backspace.
+@enddefun
+
+@defun[fun {key-event-bit-p}, args {@i[key-event] @i[bit-name]}]
+This function returns whether @i[key-event] has the bit set named by
+@i[bit-name].  This signals an error if @i[bit-name] is undefined.
+@enddefun
+
+@defmac[fun {do-alpha-key-events}, args
+{(@i[var] @i[kind] @optional @i[result]) @mstar<@i[form]>}]
+ This macro evaluates each @i[form] with @i[var] bound to a key-event
+representing an alphabetic character.  @i[Kind] is one of @kwd[lower],
+@kwd[upper], or @kwd[both], and this binds @i[var] to each key-event in order
+as specified in @i[X Window System Protocol, MIT X Consortium Standard, X
+Version 11, Release 4].  When @kwd[both] is specified, this processes lowercase
+letters first.
+@enddefmac
+
+@defun[fun {print-pretty-key}, args {@i[key] @optional @i[stream] @i[long-names-p]}]
+This prints @i[key], a key-event or vector of key-events, in a user-expected
+fashion to @i[stream].  @i[Long-names-p] indicates whether modifiers should
+print with their long or short name.  @i[Stream] defaults to
+@var[standard-output].
+@enddefun
+
+@defun[fun {print-pretty-key-event}, args {@i[key-event] @optional @i[stream] @i[long-names-p]}]
+This prints @i[key-event] to @i[stream] in a user-expected fashion.
+@i[Long-names-p] indicates whether modifier names should appear using the long
+name or short name.  @i[Stream] defaults to @var[standard-output].
+@enddefun
+
+
+
+@section (CLX Interface)
+
+@subsection (Graphics Window Hooks)
+This section describes a few hooks used by Hemlock's internals to handle
+graphics windows that manifest Hemlock windows.  Some heavy users of Hemlock as
+a tool have needed these in the past, but typically functions that replace the
+default values of these hooks must be written in the "@f[HEMLOCK-INTERNALS]"
+package.  All of these symbols are internal to this package.
+
+If you need this level of control for your application, consult the current
+implementation for code fragments that will be useful in correctly writing your
+own window hook functions.
+
+@defvar[var {create-window-hook}]
+This holds a function that @Hemlock calls when @f[make-window] executes under
+CLX.  @Hemlock passes the CLX display and the following arguments from
+@f[make-window]: starting mark, ask-user, x, y, width, height, and modelinep.
+The function returns a CLX window or nil indicating one could not be made.
+@enddefvar
+
+@defvar[var {delete-window-hook}]
+This holds a function that @hemlock calls when @f[delete-window] executes under
+CLX.  @hemlock passes the CLX window and the @hemlock window to this function.
+@enddefvar
+
+@defvar[var {random-typeout-hook}]
+This holds a function that @hemlock calls when random typeout occurs under CLX.
+@hemlock passes it a @hemlock device, a pre-existing CLX window or @nil, and
+the number of pixels needed to display the number of lines requested in the
+@f[with-pop-up-display] form.  It should return a window, and if a new window
+is created, then a CLX gcontext must be the second value.
+@enddefvar
+
+@defvar[var {create-initial-windows-hook}]
+This holds a function that @hemlock calls when it initializes the screen
+manager and makes the first windows, typically windows for the @hid[Main] and
+@hid[Echo Area] buffers.  @hemlock passes the function a @hemlock device.
+@enddefvar
+
+
+@subsection (Entering and Leaving Windows)
+
+@defhvar[var "Enter Window Hook"]
+When the mouse enters an editor window, @hemlock invokes the functions in this
+hook.  These functions take a @Hemlock window as an argument.
+@enddefhvar
+
+@defhvar[var "Exit Window Hook"]
+When the mouse exits an editor window, @hemlock invokes the functions in this
+hook.  These functions take a @Hemlock window as an argument.
+@enddefhvar
+
+
+@subsection (How to Lose Up-Events)
+Often the only useful activity user's design for the mouse is to click on
+something.  @Hemlock sees a character representing the down event, but what do
+you do with the up event character that you know must follow?  Having the
+command eat it would be tasteless, and would inhibit later customizations that
+make use of it, possibly adding on to the down click command's functionality.
+Bind the corresponding up character to the command described here.
+
+@defcom[com "Do Nothing"]
+This does nothing as many times as you tell it.
+@enddefcom
+
+
+@section (Slave Lisps)
+@index (Slave lisp interface functions)
+Some implementations of @hemlock feature the ability to manage multiple slave
+Lisps, each connected to one editor Lisp.  The routines discussed here spawn
+slaves, send evaluation and compilation requests, return the current server,
+etc.  This is very powerful because without it you can lose your editing state
+when code you are developing causes a fatal error in Lisp.
+
+The routines described in this section are best suited for creating editor
+commands that interact with slave Lisps, but in the past users implemented
+several independent Lisps as nodes communicating via these functions.  There is
+a better level on which to write such code that avoids the extra effort these
+routines take for the editor's sake.  See the @i[CMU Common Lisp User's Manual]
+for the @f[remote] and @f[wire] packages.
+
+
+@subsection (The Current Slave)
+There is a slave-information structure that these return which is suitable for
+passing to the routines described in the following subsections.
+
+@defun[fun {create-slave}, args {@optional @i[name]}]
+This creates a slave that tries to connect to the editor.  When the slave
+connects to the editor, this returns a slave-information structure, and the
+interactive buffer is the buffer named @i[name].  This generates a name if
+@i[name] is @nil.  In case the slave never connects, this will eventually
+timeout and signal an editor-error.
+@enddefun
+
+@defun[fun {get-current-eval-server}, args {@optional @i[errorp]}]
+@defhvar1[var {Current Eval Server}]
+This returns the server-information for the @hid[Current Eval Server] after
+making sure it is valid.  Of course, a slave Lisp can die at anytime.  If this
+variable is @nil, and @i[errorp] is non-@nil, then this signals an
+editor-error; otherwise, it tries to make a new slave.  If there is no current
+eval server, then this tries to make a new slave, prompting the user based on a
+few variables (see the @i[Hemlock User's Manual]).
+@enddefun
+
+@defun[fun {get-current-compile-server}]
+@defhvar1[var {Current Compile Server}]
+This returns the server-information for the @hid[Current Compile Server] after
+making sure it is valid.  This may return nil.  Since multiple slaves may
+exist, it is convenient to use one for developing code and one for compiling
+files.  The compilation commands that use slave Lisps prefer to use the current
+compile server but will fall back on the current eval server when necessary.
+Typically, users only have separate compile servers when the slave Lisp can
+live on a separate workstation to save cycles on the editor machine, and the
+@hemlock commands only use this for compiling files.
+@enddefun
+
+
+@subsection (Asynchronous Operation Queuing)
+The routines in this section queue requests with an eval server.  Requests are
+always satisfied in order, but these do not wait for notification that the
+operation actually happened.  Because of this, the user can continue editing
+while his evaluation or compilation occurs.  Note, these usually execute in the
+slave immediately, but if the interactive buffer connected to the slave is
+waiting for a form to return a value, the operation requested must wait until
+the slave is free again.
+
+@defun[fun {string-eval}, args {@i[string]}, keys {[server][package][context]}]
+@defun1[fun {region-eval}, args {@i[region]}, keys {[server][package][context]}]
+@defun1[fun {region-compile}, args {@i[region]}, keys {[server][package]}]
+@f[string-eval] queues the evaluation of the form read from @i[string] on eval
+server @i[server].  @i[Server] defaults to the result of
+@f[get-current-server], and @i[string] is a simple-string.  The evaluation
+occurs with @var[package] bound in the slave to the package named by
+@i[package], which defaults to @hid[Current Package] or the empty string; the
+empty string indicates that the slave should evaluate the form in its current
+package.  The slave reads the form in @i[string] within this context as well.
+@i[Context] is a string to use when reporting start and end notifications in
+the @hid[Echo Area] buffer; it defaults to the concatenation of @f["evaluation
+of "] and @i[string].
+
+@f[region-eval] is the same as @f[string-eval], but @i[context] defaults
+differently.  If the user leaves this unsupplied, then it becomes a string
+involving part of the first line of region.
+
+@f[region-compile] is the same as the above.  @i[Server] defaults the same; it
+does not default to @f[get-current-compile-server] since this compiles the
+region into the slave Lisp's environment, to affect what you are currently
+working on.
+@enddefun
+
+@defun[fun {file-compile}, args {@i[file]},
+			   keys {[output-file][error-file][load][server]},
+			   morekeys {[package]}]
+@defhvar1[var {Remote Compile File}, val {nil}]
+This compiles @i[file] in a slave Lisp.  When @i[output-file] is @true (the
+default), this uses a temporary output file that is publicly writable in case
+the client is on another machine, which allows for file systems that do not
+permit remote write access.  This renames the temporary file to the appropriate
+binary name or deletes it after compilation.  Setting @hid[Remote Compile File]
+to @nil, inhibits this.  If @i[output-file] is non-@nil and not @true, then it
+is the name of the binary file to write.  The compilation occurs with
+@var[package] bound in the slave to the package named by @i[package], which
+defaults to @hid[Current Package] or the empty string; the empty string
+indicates that the slave should evaluate the form in its current package.
+@i[Error-file] is the file in which to record compiler output, and a @nil value
+inhibits this file's creation.  @i[Load] indicates whether to load the
+resulting binary file, defaults to @nil.  @i[Server] defaults to
+@f[get-current-compile-server], but if this returns nil, then @i[server]
+defaults to @f[get-current-server].
+@enddefun
+
+@subsection (Synchronous Operation Queuing)
+The routines in this section queue requests with an eval server and wait for
+confirmation that the evaluation actually occurred.  Because of this, the user
+cannot continue editing while the slave executes the request.  Note, these
+usually execute in the slave immediately, but if the interactive buffer
+connected to the slave is waiting for a form to return a value, the operation
+requested must wait until the slave is free again.
+
+@defun[fun {eval-form-in-server},
+       args {@i[server-info] @i[string] @optional @i[package]}]
+ This function queues the evaluation of a form in the server associated with
+@i[server-info] and waits for the results.  The server @f[read]'s the form from
+@i[string] with @var[package] bound to the package named by @i[package].  This
+returns the results from the slave Lisp in a list of string values.  You can
+@f[read] from the strings or simply display them depending on the @f[print]'ing
+of the evaluation results.
+
+@i[Package] defaults to @hid[Current Package].  If this is @nil, the server
+uses the value of @var[package] in the server.
+
+While the slave executes the form, it binds @var[terminal-io] to a stream that
+signals errors when read from and dumps output to a bit-bucket.  This prevents
+the editor and slave from dead locking by waiting for each other to reply.
+@enddefun
+
+@defun[fun {eval-form-in-server-1},
+       args {@i[server-info] @i[string] @optional @i[package]}]
+ This function calls @f[eval-form-in-server] and @f[read]'s the result in the
+first string it returns.  This result must be @f[read]'able in the editor's
+Lisp.
+@enddefun
+
+
+@section (Spelling)
+@index (Spelling checking)
+@hemlock supports spelling checking and correcting commands based on the ITS
+Ispell dictionary.  These commands use the following routines which include
+adding and deleting entries, reading the Ispell dictionary in a compiled binary
+format, reading user dictionary files in a text format, and checking and
+correcting possible spellings.
+
+@defun[fun {maybe-read-spell-dictionary}, package {spell}]
+This reads the default binary Ispell dictionary.  Users must call this before
+the following routines will work.
+@enddefun
+
+@defun[fun {spell-read-dictionary}, package {spell}, args {@i[filename]}]
+This adds entries to the dictionary from the lines in the file @i[filename].
+Dictionary files contain line oriented records like the following:
+@begin[programexample]
+entry1/flag1/flag2
+entry2
+entry3/flag1
+@end[programexample]
+The flags are the Ispell flags indicating which endings are appropriate for the
+given entry root, but these are unnecessary for user dictionary files.  You can
+consult Ispell documentation if you want to know more about them.
+@enddefun
+
+@defun[fun {spell-add-entry}, package {spell},
+       args {@i[line] @optional @i[word-end]}]
+This takes a line from a dictionary file, and adds the entry described by
+@i[line] to the dictionary.  @i[Word-end] defaults to the position of the first
+slash character or the length of the line.  @i[Line] is destructively modified.
+@enddefun
+
+@defun[fun {spell-remove-entry}, package {spell}, args {@i[entry]}]
+This removes entry, a simple-string, from the dictionary, so it will be an
+unknown word.  This destructively modifies @i[entry].  If it is a root word,
+then all words derived with @i[entry] and its flags will also be deleted.  If
+@i[entry] is a word derived from some root word, then the root and any words
+derived from it remain known words.
+@enddefun
+
+@defun[fun {correct-spelling}, package {spell}, args {@i[word]}]
+This checks the spelling of @i[word] and outputs the results.  If this finds
+@i[word] is correctly spelled due to some appropriate suffix on a root, it
+generates output indicating this.  If this finds @i[word] as a root entry, it
+simply outputs that it found @i[word].  If this cannot find @i[word] at all,
+then it outputs possibly correct close spellings.  This writes to
+@var[standard-output], and it calls @f[maybe-read-spell-dictionary] before
+attempting any lookups.
+@enddefun
+
+@defun[fun {spell-try-word}, package {spell}, args {@i[word] @i[word-len]}]
+@defcon1[var {max-entry-length}, val {31}]
+This returns an index into the dictionary if it finds @i[word] or an
+appropriate root.  @i[Word-len] must be inclusively in the range 2 through
+@f[max-entry-length], and it is the length of @i[word].  @i[Word] must be
+uppercase.  This returns a second value indicating whether it found @i[word]
+due to a suffix flag, @nil if @i[word] is a root entry.
+@enddefun
+
+@defun[fun {spell-root-word}, package {spell}, args {@i[index]}]
+This returns a copy of the root word at dictionary entry @i[index].  This index
+is the same as returned by @f[spell-try-word].
+@enddefun
+
+@defun[fun {spell-collect-close-words}, package {spell}, args {@i[word]}]
+This returns a list of words correctly spelled that are @i[close] to @i[word].
+@i[Word] must be uppercase, and its length must be inclusively in the range 2
+through @f[max-entry-length].  Close words are determined by the Ispell rules:
+@begin[enumerate]
+Two adjacent letters can be transposed to form a correct spelling.
+
+One letter can be changed to form a correct spelling.
+
+One letter can be added to form a correct spelling.
+
+One letter can be removed to form a correct spelling.
+@end[enumerate]
+@enddefun
+
+@defun[fun {spell-root-flags}, package {spell}, args {@i[index]}]
+This returns a list of suffix flags as capital letters that apply to the
+dictionary root entry at @i[index].  This index is the same as returned by
+@f[spell-try-word].
+@enddefun
+
+
+@section (File Utilities)
+Some implementations of @hemlock provide extensive directory editing commands,
+@hid[Dired], including a single wildcard feature.  An asterisk denotes a
+wildcard.
+
+@defun[fun {copy-file}, package {dired},
+       args {@i[spec1] @i[spec2]}, keys {[update][clobber][directory]}]
+ This function copies @i[spec1] to @i[spec2].  It accepts a single wildcard in
+the filename portion of the specification, and it accepts directories.  This
+copies files maintaining the source's write date.
+
+If @i[spec1] and @i[spec2] are both directories, this recursively copies the
+files and subdirectory structure of @i[spec1]; if @i[spec2] is in the
+subdirectory structure of @i[spec1], the recursion will not descend into it.
+Use @f["/spec1/*"] to copy only the files from @i[spec1] to directory
+@i[spec2].
+
+If @i[spec2] is a directory, and @i[spec1] is a file, then this copies
+@i[spec1] into @i[spec2] with the same @f[pathname-name].
+
+When @kwd[update] is non-@nil, then the copying process only copies files if the
+source is newer than the destination.
+
+When @kwd[update] and @kwd[clobber] are @nil, and the destination exists, the
+copying process stops and asks the user whether the destination should be
+overwritten.
+
+When the user supplies @kwd[directory], it is a list of pathnames, directories
+excluded, and @i[spec1] is a pattern containing one wildcard.  This then copies
+each of the pathnames whose @f[pathname-name] matches the pattern.  @i[Spec2]
+is either a directory or a pathname whose @f[pathname-name] contains a
+wildcard.
+@enddefun
+
+@defun[fun {rename-file}, package {dired},
+       args {@i[spec1] @i[spec2]}, keys {[clobber][directory]}]
+ This function renames @i[spec1] to @i[spec2].  It accepts a single wildcard in
+the filename portion of the specification, and @i[spec2] may be a directory
+with the destination specification resulting in the merging of @i[spec2] with
+@i[spec1].  If @kwd[clobber] is @nil, and @i[spec2] exists, then this asks the
+user to confirm the renaming.  When renaming a directory, end the specification
+without the trailing slash.
+
+When the user supplies @kwd[directory], it is a list of pathnames, directories
+excluded, and @i[spec1] is a pattern containing one wildcard.  This then copies
+each of the pathnames whose @f[pathname-name] matches the pattern.  @i[Spec2]
+is either a directory or a pathname whose @f[pathname-name] contains a
+wildcard.
+@enddefun
+
+@defun[fun {delete-file}, package {dired},
+       args {@i[spec]}, keys {[recursive][clobber]}]
+ This function deletes @i[spec].  It accepts a single wildcard in the filename
+portion of the specification, and it asks for confirmation on each file if
+@kwd[clobber] is @nil.  If @kwd[recursive] is non-@nil, then @i[spec] may be a
+directory to recursively delete the entirety of the directory and its
+subdirectory structure.  An empty directory may be specified without
+@kwd[recursive] being non-@nil.  Specify directories with the trailing
+slash.
+@enddefun
+
+@defun[fun {find-file}, package {dired},
+       args {@i[name] @optional @i[directory] @i[find-all]}]
+ This function finds the file with @f[file-namestring] @i[name], recursively
+looking in @i[directory].  If @i[find-all] is non-@nil (defaults to @nil), then
+this continues searching even after finding a first occurrence of file.
+@i[Name] may contain a single wildcard, which causes @i[find-all] to default to
+@true instead of @nil.
+@enddefun
+
+@defun[fun {make-directory}, package {dired}, args {@i[name]}]
+This function creates the directory with @i[name].  If it already exists, this
+signals an error.
+@enddefun
+
+@defun[fun {pathnames-from-pattern}, package {dired},
+       args {@i[pattern] @i[files]}]
+This function returns a list of pathnames from the list @i[files] whose
+@f[file-namestring]'s match @i[pattern].  @i[Pattern] must be a non-empty
+string and contain only one asterisk.  @i[Files] contains no directories.
+@enddefun
+
+@defvar[var {update-default}, package {dired}]
+@defvar1[var {clobber-default}, package {dired}]
+@defvar1[var {recursive-default}, package {dired}]
+These are the default values for the keyword arguments above with corresponding
+names.  These default to @nil, @true, and @nil respectively.
+@enddefvar
+
+@defvar[var {report-function}, package {dired}]
+@defvar1[var {error-function}, package {dired}]
+@defvar1[var {yesp-function}, package {dired}]
+These are the function the above routines call to report progress, signal
+errors, and prompt for @i[yes] or @i[no].  These all take format strings and
+arguments.
+@enddefvar
+
+
+@section (Beeping)
+
+@defun[fun {hemlock-beep}]
+@Hemlock binds @f[system:*beep-function*] to this function to beep the device.
+It is different for different devices.
+@enddefvar
+
+@defhvar[var "Bell Style", val {:border-flash}]
+@defhvar1[var "Beep Border Width", val {20}]
+@hid[Bell Style] determines what @var[hemlock-beep] does in @hemlock under CLX.
+Acceptable values are @kwd[border-flash], @kwd[feep],
+@kwd[border-flash-and-feep], @kwd[flash], @kwd[flash-and-feep], and @nil (do
+nothing).
+
+@hid[Beep Border Width] is the width in pixels of the border flashed by border
+flash beep styles.
+@enddefhvar
diff --git a/docs/hem/cim/cim.mss b/docs/hem/cim/cim.mss
new file mode 100644
index 000000000..0fc5c0ced
--- /dev/null
+++ b/docs/hem/cim/cim.mss
@@ -0,0 +1,4003 @@
+@make[Manual] @comment{-*- Dictionary: /usr/lisp/scribe/hem/hem; Mode: spell; Package: Hemlock; Log: /usr/lisp/scribe/hem/hem-docs.log -*-}
+@Device[postscript]
+@style(FontFamily = TimesRoman)
+@Style(Spacing = 1.2 lines)
+@Style(StringMax = 5000)
+@style(Hyphenation = On)
+@style(Date="March 1952")
+@use(database "/usr/lisp/scribe/database/")
+@Style [DoubleSided]
+@Libraryfile[ArpaCredit]
+@Libraryfile[Hem]
+@Libraryfile[Spice]
+@Libraryfile[Uttir]
+
+@String(ReportTitle "Hemlock Command Implementor's Manual")
+
+@comment<
+@begin[TitlePage]
+@begin[TitleBox]
+>
+@blankspace(1.3inches)
+@heading[Hemlock Command Implementor's Manual]
+
+@center[
+@b<Bill Chiles>
+@b<Rob MacLachlan>
+
+@b<@value[date]>
+
+@b<CMU-CS-89-134-R1>
+]
+@comment<@end[TitleBox]>
+@blankspace(2lines)
+@begin[Center]
+School of Computer Science
+Carnegie Mellon University
+Pittsburgh, PA 15213
+@end[Center]
+
+@blankspace(2lines)
+@begin[Center]
+This is a revised version of Technical Report CMU-CS-87-159.
+@end[Center]
+@heading[Abstract]
+@begin(Text, indent 0)
+This document describes how to write commands for the @Hemlock text editor, as
+of version M3.2.  @Hemlock is a customizable, extensible text editor whose
+initial command set closely resembles that of ITS/TOPS-20 @Emacs.  @Hemlock is
+written in the CMU Common Lisp and has been ported to other implementations.
+@end(Text)
+
+@blankspace(0.5in)
+@begin[ResearchCredit]
+@arpacredit[Contract=Basic87-90]
+@end[ResearchCredit]
+@comment<@end[TitlePage]>
+
+
+@commandstring(dash = "@Y[M]")
+
+
+@Tabclear
+
+@chapter(Introduction)
+
+ @hemlock is a text editor which follows in the tradition of editors
+such as EMACS and the Lisp Machine editor ZWEI.  In its basic form,
+@hemlock has almost the same command set as EMACS, and similar
+features such as multiple buffers and windows, extended commands,
+and built in documentation.
+
+Both user extensions and the original commands are written in Lisp,
+therefore a command implementor will have a working knowledge of this
+language.  Users not familiar with Lisp need not despair however.  Many
+users of Multics EMACS, another text editor written in Lisp, came to learn
+Lisp simply for the purpose of writing their own editor extensions, and
+found, to their surprise, that it was really pretty easy to write simple
+commands.
+
+This document describes the Common Lisp functions, macros and data structures
+that are used to implement new commands.  The basic editor consists of a set of
+Lisp utility functions for manipulating buffers and the other data structures
+of the editor as well as handling the display.  All user level commands are
+written in terms of these functions.  To find out how to define commands see
+chapter @ref[commands].
+
+@chapter(Representation of Text)
+@index (Lines)
+@section(Lines)
+In @hemlock all text is in some @i[line].  Text is broken into lines wherever
+it contains a newline character; newline characters are never stored, but are
+assumed to exist between every pair of lines.  The implicit newline character
+is treated as a single character by the text primitives.
+
+@defun[fun {linep}, args {@i[line]}]
+This function returns @true if @i[line] is a @f[line] object, otherwise @nil.
+@enddefun
+
+@defun[fun {line-string}, args {@i[line]}]
+Given a @i(line), this function returns as a simple string the characters in
+the line.  This is @f[setf]'able to set the @f[line-string] to any string that
+does not contain newline characters.  It is an error to destructively modify
+the result of @f[line-string] or to destructively modify any string after the
+@f[line-string] of some line has been set to that string.
+@enddefun
+
+@defun[fun {line-previous}, args {@i[line]}]
+@defun1[fun {line-next}, args {@i[line]}]
+Given a @i(line), @f[line-previous] returns the previous line or @nil if there
+is no previous line.  Similarly, @f[line-next] returns the line following
+@i[line] or @nil.
+@enddefun
+
+@defun[fun {line-buffer}, args {@i[line]}]
+This function returns the buffer which contains this @i(line).  Since a
+line may not be associated with any buffer, in which case @f[line-buffer]
+returns @nil.
+@enddefun
+
+@defun[fun {line-length}, args {@i[line]}]
+This function returns the number of characters in the @i(line).  This excludes
+the newline character at the end.
+@enddefun
+
+@defun[fun {line-character}, args {@i[line] @i[index]}]
+This function returns the character at position @i[index] within @i[line].  It
+is an error for @i[index] to be greater than the length of the line or less
+than zero.  If @i[index] is equal to the length of the line, this returns a
+@f[#\newline] character.
+@enddefun
+
+@defun[fun {line-plist}, args {@i[line]}]
+This function returns the property-list for @i[line].  @f[setf], @f[getf],
+@f[putf] and @f[remf] can be used to change properties.  This is typically used
+in conjunction with @f[line-signature] to cache information about the line's
+contents.
+@enddefun
+
+@defun[fun {line-signature}, args {@i[line]}]
+This function returns an object that serves as a signature for a @i[line]'s
+contents.  It is guaranteed that any modification of text on the line will
+result in the signature changing so that it is not @f[eql] to any previous
+value.  The signature may change even when the text remains unmodified, but
+this does not happen often.
+@enddefun
+
+
+@section(Marks)
+@label[marks]
+@index (Marks)
+A mark indicates a specific position within the text represented by a line and
+a character position within that line.  Although a mark is sometimes loosely
+referred to as pointing to some character, it in fact points between
+characters.  If the @f[charpos] is zero, the previous character is the newline
+character separating the previous line from the mark's @f[line].  If the
+charpos is equal to the number of characters in the line, the next character is
+the newline character separating the current line from the next.  If the mark's
+line has no previous line, a mark with @f[charpos] of zero has no previous
+character; if the mark's line has no next line, a mark with @f[charpos] equal
+to the length of the line has no next character.
+
+This section discusses the very basic operations involving marks, but a lot of
+@hemlock programming is built on altering some text at a mark.  For more
+extended uses of marks see chapter @ref[doing-stuff].
+
+
+@subsection(Kinds of Marks)
+@index (Permanent marks)
+@index (Temporary marks)
+A mark may have one of two lifetimes: @i[temporary] or @i[permanent].
+Permanent marks remain valid after arbitrary operations on the text; temporary
+marks do not.  Temporary marks are used because less bookkeeping overhead is
+involved in their creation and use.  If a temporary mark is used after the text
+it points to has been modified results will be unpredictable.  Permanent marks
+continue to point between the same two characters regardless of insertions and
+deletions made before or after them.
+
+There are two different kinds of permanent marks which differ only in their
+behavior when text is inserted @i(at the position of the mark); text is
+inserted to the left of a @i[left-inserting] mark and to the right of
+@i[right-inserting] mark.
+
+
+@subsection(Mark Functions)
+@defun[fun {markp}, args {@i[mark]}]
+This function returns @true if @i[mark] is a @f[mark] object, otherwise @nil.
+@enddefun
+
+@defun[fun {mark-line}, args {@i[mark]}]
+This function returns the line to which @i(mark) points.
+@enddefun
+
+@defun[fun {mark-charpos}, args {@i[mark]}]
+This function returns the character position of the character after @i(mark).
+If @i[mark]'s line has no next line, this returns the length of the line as
+usual; however, there is actually is no character after the mark.
+@enddefun
+
+@defun[fun {mark-kind}, args {@i[mark]}]
+This function returns one of @kwd[right-inserting], @kwd[left-inserting] or
+@kwd[temporary] depending on the mark's kind.  A corresponding @f[setf] form
+changes the mark's kind.
+@enddefun
+
+@defun[fun {previous-character}, args {@i[mark]}]
+@defun1[fun {next-character}, args {@i[mark]}]
+This function returns the character immediately before (after) the position of
+the @i[mark], or @nil if there is no previous (next) character.  These
+characters may be set with @f[setf] when they exist; the @f[setf] methods for
+these forms signal errors when there is no previous or next character.
+@enddefun
+
+
+@subsection(Making Marks)
+@defun[fun {mark}, args {@i[line] @i[charpos] @optional @i[kind]}]
+This function returns a mark object that points to the @i(charpos)'th character
+of the @i(line).  @i(Kind) is the kind of mark to create, one of
+@kwd[temporary], @kwd[left-inserting], or @kwd[right-inserting].  The default
+is @kwd[temporary].
+@enddefun
+
+@defun[fun {copy-mark}, args {@i[mark] @optional @i[kind]}]
+This function returns a new mark pointing to the same position and of the same
+kind, or of kind @i[kind] if it is supplied.
+@enddefun
+
+@defun[fun {delete-mark}, args {@i[mark]}]
+This function deletes @i(mark).  Delete any permanent marks when you are
+finished using it.
+@enddefun
+
+@Defmac[Fun {with-mark}, Args 
+        {(@Mstar<(@i[mark] @i[pos] @mopt[@i(kind)])>) @Mstar<@i[form]>}]
+ This macro binds to each variable @i[mark] a mark of kind @i[kind], which
+defaults to @kwd[temporary], pointing to the same position as the mark @i[pos].
+On exit from the scope the mark is deleted.  The value of the last @i[form] is
+the value returned.
+@enddefmac
+
+
+@subsection(Moving Marks)
+@index(Moving marks)
+These functions destructively modify marks to point to new positions.  Other
+sections of this document describe mark moving routines specific to higher
+level text forms than characters and lines, such as words, sentences,
+paragraphs, Lisp forms, etc.
+
+@defun[fun {move-to-position}, args {@i[mark] @i[charpos] @optional @i[line]}]
+This function changes the @i(mark) to point to the given character position on
+the line @i(line).  @i(Line) defaults to @i[mark]'s line.
+@enddefun
+
+@defun[fun {move-mark}, args {@i[mark] @i[new-position]}]
+This function moves @i[mark] to the same position as the mark @i[new-position]
+and returns it.
+@enddefun
+
+@defun[fun {line-start}, args {@i[mark] @optional @i[line]}]
+@defun1[fun {line-end}, args {@i[mark] @optional @i[line]}]
+This function changes @i[mark] to point to the beginning or the end of @i(line)
+and returns it.  @i[Line] defaults to @i[mark]'s line.
+@enddefun
+
+@defun[fun {buffer-start}, args {@i[mark] @optional @i[buffer]}]
+@defun1[fun {buffer-end}, args {@i[mark] @optional @i[buffer]}]
+These functions change @i[mark] to point to the beginning or end of @i[buffer],
+which defaults to the buffer @i[mark] currently points into.  If @i[buffer] is
+unsupplied, then it is an error for @i[mark] to be disassociated from any
+buffer.
+@enddefun
+
+@defun[fun {mark-before}, args {@i[mark]}]
+@defun1[fun {mark-after}, args {@i[mark]}]
+These functions change @i[mark] to point one character before or after the
+current position.  If there is no character before/after the current position,
+then they return @nil and leave @i[mark] unmodified.
+@enddefun
+
+@defun[fun {character-offset}, args {@i[mark] @i[n]}]
+This function changes @i[mark] to point @i[n] characters after (@i[n] before if
+@i[n] is negative) the current position.  If there are less than @i[n]
+characters after (before) the @i[mark], then this returns @nil and @i[mark] is
+unmodified.
+@enddefun
+
+@defun[fun {line-offset}, args {@i[mark] @i[n] @optional @i[charpos]}]
+This function changes @i[mark] to point @i[n] lines after (@i[n] before if
+@i[n] is negative) the current position.  The character position of the
+resulting mark is
+@lisp
+(min (line-length @i(resulting-line)) (mark-charpos @i(mark)))
+@endlisp
+if @i[charpos] is unspecified, or
+@lisp
+(min (line-length @i(resulting-line)) @i(charpos))
+@endlisp
+if it is.  As with @t(character-offset), if there are not @i[n] lines then
+@nil is returned and @i[mark] is not modified.
+@enddefun
+
+
+@section(Regions)
+@index (Regions)
+A region is simply a pair of marks: a starting mark and an ending mark.
+The text in a region consists of the characters following the starting
+mark and preceding the ending mark (keep in mind that a mark points between
+characters on a line, not at them).
+
+By modifying the starting or ending mark in a region it is possible to
+produce regions with a start and end which are out of order or even in
+different buffers.  The use of such regions is undefined and may
+result in arbitrarily bad behavior.
+
+
+@subsection(Region Functions)
+@defun[fun {region}, args {@i[start] @i[end]}]
+This function returns a region constructed from the marks @i[start] and
+@i[end].  It is an error for the marks to point to non-contiguous lines or for
+@i(start) to come after @i(end).
+@enddefun
+
+@defun[fun {regionp}, args {@i[region]}]
+This function returns @true if @i[region] is a @f[region] object, otherwise
+@nil.
+@enddefun
+
+@defun[fun {make-empty-region}]
+This function returns a region with start and end marks pointing to the start
+of one empty line.  The start mark is a @kwd[right-inserting] mark, and the end
+is a @kwd[left-inserting] mark.
+@enddefun
+
+@defun[fun {copy-region}, args {@i[region]}]
+This function returns a region containing a copy of the text in the specified
+@i[region].  The resulting region is completely disjoint from @i[region] with
+respect to data references @dash marks, lines, text, etc.
+@enddefun
+
+@defun[fun {region-to-string}, args {@i[region]}]
+@defun1[fun {string-to-region}, args {@i[string]}]
+These functions coerce regions to Lisp strings and vice versa.  Within the
+string, lines are delimited by newline characters.
+@enddefun
+
+@defun[fun {line-to-region}, args {@i[line]}]
+This function returns a region containing all the characters on @i[line].  The
+first mark is @kwd[right-inserting] and the last is @kwd[left-inserting].
+@enddefun
+
+@defun[fun {region-start}, args {@i[region]}]
+@defun1[fun {region-end}, args {@i[region]}]
+This function returns the start or end mark of @i(region).
+@enddefun
+
+@defun[fun {region-bounds}, args {@i[region]}]
+This function returns as multiple-values the starting and ending marks of
+@i[region].
+@enddefun
+
+@defun[fun {set-region-bounds}, args {@i[region] @i[start] @i[end]}]
+This function sets the start and end of region to @i[start] and @i[end].  It is
+an error for @i[start] to be after or in a different buffer from @i[end].
+@enddefun
+
+@index(Counting lines and characters)
+@defun[fun {count-lines}, args {@i[region]}]
+This function returns the number of lines in the @i(region), first and last
+lines inclusive.  A newline is associated with the line it follows, thus a
+region containing some number of non-newline characters followed by one newline
+is one line, but if a newline were added at the beginning, it would be two
+lines.
+@enddefun
+
+@defun[fun {count-characters}, args {@i[region]}]
+This function returns the number of characters in a given @i(region).  This
+counts line breaks as one character.
+@enddefun
+
+@defun[fun {check-region-query-size}, args {@i[region]}]
+@defhvar1[var {Region Query Size}, val {30}]
+@f[check-region-query-size] counts the lines in @i[region], and if their number
+exceeds the @hid[Region Query Size] threshold, it prompts the user for
+confirmation.  This should be used in commands that perform destructive
+operations and are not undoable.  If the user responds negatively, then this
+signals an editor-error, aborting whatever command was in progress.
+@enddefun
+
+
+
+@chapter(Buffers)
+@index (Buffers)
+@label[buffers]
+A buffer is an environment within @hemlock consisting of:
+@begin(enumerate)
+A name.
+
+A piece of text.
+
+A current focus of attention, the point.
+
+An associated file (optional).
+
+A write protect flag.
+
+Some variables (page @pageref[variables]).
+
+Some key bindings (page @pageref[key-bindings]).
+
+Some collection of modes (page @pageref[modes]).
+
+Some windows in which it is displayed (page @pageref[windows]).
+
+A list of modeline fields (optional).
+@end(enumerate)
+
+
+@section (The Current Buffer)
+@index (Current buffer)
+@defun[fun {current-buffer}]
+@defhvar1[var {Set Buffer Hook}]
+@defhvar1[var {After Set Buffer Hook}]
+@f[current-buffer] returns the current buffer object.  Usually this is the
+buffer that @funref[current-window] is displaying.  This value may be changed
+with @f[setf], and the @f[setf] method invokes @hid[Set Buffer Hook] before the
+change occurs with the new value.  After the change occurs, the method invokes
+@hid[After Set Buffer Hook] with the old value.
+@enddefun
+
+@defun[fun {current-point}]
+This function returns the @f[buffer-point] of the current buffer.
+This is such a common idiom in commands that it is defined despite
+its trivial implementation.
+@enddefun
+
+@defun[fun {current-mark}]
+@defun1[fun {pop-buffer-mark}]
+@defun1[fun {push-buffer-mark}, args {@i[mark] @optional @i[activate-region]}]
+@index(Buffer mark stack)
+@index(Mark stack)
+@label(mark-stack)
+@f[current-mark] returns the top of the current buffer's mark stack.  There
+always is at least one mark at the beginning of the buffer's region, and all
+marks returned are right-inserting.
+
+@f[pop-buffer-mark] pops the current buffer's mark stack, returning the mark.
+If the stack becomes empty, this pushes a new mark on the stack pointing to the
+buffer's start.  This always deactivates the current region (see section
+@ref[active-regions]).
+
+@f[push-buffer-mark] pushes @i[mark] into the current buffer's mark stack,
+ensuring that the mark is right-inserting.  If @i[mark] does not point into the
+current buffer, this signals an error.  Optionally, the current region is made
+active, but this never deactivates the current region (see section
+@ref[active-regions]).  @i[Mark] is returned.
+@enddefun
+
+@defvar[var {buffer-list}]
+This variable holds a list of all the buffer objects made with @f[make-buffer].
+@enddefvar
+
+@defvar[var {buffer-names}]
+This variable holds a @f[string-table] (page @pageref(string-tables)) of all the
+names of the buffers in @var[buffer-list].  The values of the entries are the
+corresponding buffer objects.
+@enddefvar
+
+@defvar[var {buffer-history}]
+This is a list of buffer objects ordered from those most recently selected to
+those selected farthest in the past.  When someone makes a buffer, an element
+of @hid[Make Buffer Hook] adds this buffer to the end of this list.  When
+someone deletes a buffer, an element of @hid[Delete Buffer Hook] removes the
+buffer from this list.  Each buffer occurs in this list exactly once, but it
+never contains the @var[echo-area-buffer].
+@enddefvar
+
+@defun[fun {change-to-buffer}, args {@i[buffer]}]
+This switches to @i[buffer] in the @f[current-window] maintaining
+@f[buffer-history].
+@enddefun
+
+@defun[fun {previous-buffer}]
+This returns the first buffer from @var[buffer-history] that is not the
+@f[current-buffer].  If none can be found, then this returns @nil.
+@enddefun
+
+
+@section(Buffer Functions)
+@defun[fun {make-buffer}, args {@i[name]}, keys {[modes][modeline-fields][delete-hook]}]
+@defhvar1[var {Make Buffer Hook}]
+@defhvar1[var {Default Modeline Fields}]
+@f[make-buffer] creates and returns a buffer with the given @i(name).  If a
+buffer named @i[name] already exists, @nil is returned.  @i[Modes] is a list of
+modes which should be in effect in the buffer, major mode first, followed by
+any minor modes.  If this is omitted then the buffer is created with the list
+of modes contained in @hvarref[Default Modes].  @i[Modeline-fields] is a list
+of modeline-field objects (see section @ref[modelines]) which may be @nil.
+@f[delete-hook] is a list of delete hooks specific to this buffer, and
+@f[delete-buffer] invokes these along with @hid[Delete Buffer Hook].
+
+Buffers created with @f[make-buffer] are entered into the list
+@var[buffer-list], and their names are inserted into the
+string-table @var[buffer-names].  When a buffer is created the hook
+@hid[Make Buffer Hook] is invoked with the new buffer.
+@enddefun
+
+@defun[fun {bufferp}, args {@i[buffer]}]
+Returns @true if @i[buffer] is a @f[buffer] object, otherwise @nil.
+@enddefun
+
+@defun[fun {buffer-name}, args {@i[buffer]}]
+@defhvar1[var {Buffer Name Hook}]
+@f[buffer-name] returns the name, which is a string, of the given @i(buffer).
+The corresponding @f[setf] method invokes @hid[Buffer Name Hook] with
+@i[buffer] and the new name and then sets the buffer's name.  When the user
+supplies a name for which a buffer already exists, the @f[setf] method signals
+an error.
+@enddefun
+
+@defun[fun {buffer-region}, args {@i[buffer]}]
+Returns the @i[buffer]'s region.  This can be set with @f[setf].  Note, this
+returns the region that contains all the text in a buffer, not the
+@funref[current-region].
+@enddefun
+
+@defun[fun {buffer-pathname}, args {@i[buffer]}]
+@defhvar1[var {Buffer Pathname Hook}]
+@f[buffer-pathname] returns the pathname of the file associated with
+the given @i(buffer), or nil if it has no associated file.  This is
+the truename of the file as of the most recent time it was read or
+written.  There is a @f[setf] form to change the pathname.  When the
+pathname is changed the hook @hid[Buffer Pathname Hook] is invoked
+with the buffer and new value.
+@enddefun
+
+@defun[fun {buffer-write-date}, args {@i[buffer]}]
+Returns the write date for the file associated with the buffer in universal
+time format.  When this the @f[buffer-pathname] is set, use @f[setf] to set
+this to the corresponding write date, or to @nil if the date is unknown or
+there is no file.
+@enddefun
+
+@defun[fun {buffer-point}, args {@i[buffer]}]
+Returns the mark which is the current location within @i[buffer].  To
+move the point, use @f[move-mark] or @funref[move-to-position] rather
+than setting @f[buffer-point] with @f[setf].
+@enddefun
+
+@defun[fun {buffer-mark}, args {@i[buffer]}]
+@index(Buffer mark stack)
+@index(Mark stack)
+This function returns the top of @i[buffer]'s mark stack.  There always
+is at least one mark at the beginning of @i[buffer]'s region, and all marks
+returned are right-inserting.
+@enddefun
+
+@defun[fun {buffer-start-mark}, args {@i[buffer]}]
+@defun1[fun {buffer-end-mark}, args {@i[buffer]}]
+These functions return the start and end marks of @i[buffer]'s region:
+@Begin[ProgramExample]
+(buffer-start-mark buffer)  <==>
+  (region-start (buffer-region buffer))
+and
+(buffer-end-mark buffer)  <==>
+  (region-end (buffer-region buffer))
+@End[ProgramExample]
+@enddefun
+
+@defun[fun {buffer-writable}, args {@i[buffer]}]
+@defhvar1[var "Buffer Writable Hook"]
+This function returns @true if you can modify the @i(buffer), @nil if you
+cannot.  If a buffer is not writable, then any attempt to alter text in the
+buffer results in an error.  There is a @f[setf] method to change this value.
+
+The @f[setf] method invokes the functions in @hid[Buffer Writable Hook] on the
+buffer and new value before storing the new value.
+@enddefun
+
+@defun[fun {buffer-modified}, args {@i[buffer]}]
+@defhvar1[var "Buffer Modified Hook"]
+@f[buffer-modified] returns @true if the @i[buffer] has been modified, @nil if
+it hasn't.  This attribute is set whenever a text-altering operation is
+performed on a buffer.  There is a @f[setf] method to change this value.
+
+The @f[setf] method invokes the functions in @hid[Buffer Modified Hook] with
+the buffer whenever the value of the modified flag changes.
+@enddefun
+
+@defmac[fun {with-writable-buffer}, args {(@i[buffer]) @rest @i[forms]}]
+This macro executes @i[forms] with @i[buffer]'s writable status set.  After
+@i[forms] execute, this resets the @i[buffer]'s writable and modified status.
+@enddefmac
+
+@defun[fun {buffer-signature}, args {@i[buffer]}]
+This function returns an arbitrary number which reflects the buffer's current
+@i[signature].  The result is @f[eql] to a previous result if and only if the
+buffer has not been modified between the calls.
+@enddefun
+
+@defun[fun {buffer-variables}, args {@i[buffer]}]
+This function returns a string-table (page @pageref[string-tables]) containing
+the names of the buffer's local variables.  See chapter @ref[variables].
+@enddefun
+
+@defun[fun {buffer-modes}, args {@i[buffer]}]
+This function returns the list of the names of the modes active in @i[buffer].
+The major mode is first, followed by any minor modes.  See chapter @ref[modes].
+@enddefun
+
+@defun[fun {buffer-windows}, args {@i[buffer]}]
+This function returns the list of all the windows in which the buffer may be
+displayed.  This list may include windows which are not currently visible.  See
+page @pageref[windows] for a discussion of windows.
+@enddefun
+
+@defun[fun {buffer-delete-hook}, args {@i[buffer]}]
+This function returns the list of buffer specific functions @f[delete-buffer]
+invokes when deleting a buffer.  This is @f[setf]'able.
+@enddefun
+
+@defun[fun {delete-buffer}, args {@i[buffer]}]
+@defhvar1[var {Delete Buffer Hook}]
+@f[delete-buffer] removes @i[buffer] from @varref[buffer-list] and its name
+from @varref[buffer-names].  Before @i[buffer] is deleted, this invokes the
+functions on @i[buffer] returned by @f[buffer-delete-hook] and those found in
+@hid[Delete Buffer Hook].  If @i[buffer] is the @f[current-buffer], or if it is
+displayed in any windows, then this function signals an error.
+@enddefun
+
+@defun[fun {delete-buffer-if-possible}, args {@i[buffer]}]
+This uses @f[delete-buffer] to delete @i[buffer] if at all possible.  If
+@i[buffer] is the @f[current-buffer], then this sets the @f[current-buffer] to
+the first distinct buffer in @f[buffer-history].  If @i[buffer] is displayed in
+any windows, then this makes each window display the same distinct buffer.
+@enddefun
+
+
+@section(Modelines)
+@index(Modelines)
+@label(modelines)
+
+A Buffer may specify a modeline, a line of text which is displayed across the
+bottom of a window to indicate status information.  Modelines are described as
+a list of @f[modeline-field] objects which have individual update functions and
+are optionally fixed-width.  These have an @f[eql] name for convenience in
+referencing and updating, but the name must be unique for all created
+modeline-field objects.  When creating a modeline-field with a specified width,
+the result of the update function is either truncated or padded on the right to
+meet the constraint.  All modeline-field functions must return simple strings
+with standard characters, and these take a buffer and a window as arguments.
+Modeline-field objects are typically shared amongst, or aliased by, different
+buffers' modeline fields lists.  These lists are unique allowing fields to
+behave the same wherever they occur, but different buffers may display these
+fields in different arrangements.
+
+Whenever one of the following changes occurs, all of a buffer's modeline fields
+are updated:
+@Begin[Itemize]
+A buffer's major mode is set.
+
+One of a buffer's minor modes is turned on or off.
+
+A buffer is renamed.
+
+A buffer's pathname changes.
+
+A buffer's modified status changes.
+
+A window's buffer is changed.
+@End[Itemize]
+
+The policy is that whenever one of these changes occurs, it is guaranteed that
+the modeline will be updated before the next trip through redisplay.
+Furthermore, since the system cannot know what modeline-field objects the
+user has added whose update functions rely on these values, or how he has
+changed @hid[Default Modeline Fields], we must update all the fields.  When any
+but the last occurs, the modeline-field update function is invoked once for
+each window into the buffer.  When a window's buffer changes, each
+modeline-field update function is invoked once; other windows' modeline
+fields should not be affected due to a given window's buffer changing.
+
+The user should note that modelines can be updated at any time, so update
+functions should be careful to avoid needless delays (for example, waiting for
+a local area network to determine information).
+
+@defun[fun {make-modeline-field}, keys {[name][width][function]}]
+@defun1[fun {modeline-field-p}, args @i(modeline-field)]
+@defun1[fun {modeline-field-name}, args @i(modeline-field)]
+@f[make-modeline-field] returns a modeline-field object with @i[name],
+@i[width], and @i[function].  @i[Width] defaults to @nil meaning that the field
+is variable width; otherwise, the programmer must supply this as a positive
+integer.  @i[Function] must take a buffer and window as arguments and return a
+@f[simple-string] containing only standard characters.  If @i[name] already
+names a modeline-field object, then this signals an error.
+
+@f[modeline-field-name] returns the name field of a modeline-field object.  If
+this is set with @f[setf], and the new name already names a modeline-field,
+then the @f[setf] method signals an error.
+
+@f[modeline-field-p] returns @true or @nil, depending on whether its argument
+is a @f[modeline-field] object.
+@enddefun
+
+@defun[fun {modeline-field}, args {@i[name]}]
+This returns the modeline-field object named @i[name].  If none exists, this
+returns nil.
+@enddefun
+
+@defun[fun {modeline-field-function}, args {@i[modeline-field]}]
+Returns the function called when updating the @i[modeline-field].  When this is
+set with @f[setf], the @f[setf] method updates @i[modeline-field] for all
+windows on all buffers that contain the given field, so the next trip through
+redisplay will reflect the change.  All modeline-field functions must return
+simple strings with standard characters, and they take a buffer and a window
+as arguments.
+@enddefun
+
+@defun[fun {modeline-field-width}, args {@i[modeline-field]}]
+Returns the width to which @i[modeline-field] is constrained, or @nil
+indicating that it is variable width.  When this is set with @f[setf], the
+@f[setf] method updates all modeline-fields for all windows on all buffers that
+contain the given field, so the next trip through redisplay will reflect the
+change.  All the fields for any such modeline display must be updated, which is
+not the case when setting a modeline-field's function.
+@enddefun
+
+@defun[fun {buffer-modeline-fields}, args {@i[buffer]}]
+Returns a copy of the list of @i[buffer]'s modeline-field objects.  This list
+can be destructively modified without affecting display of @i[buffer]'s
+modeline, but modifying any particular field's components (for example, width
+or function) causes the changes to be reflected the next trip through redisplay
+in every modeline display that uses the modified modeline-field.  When this is
+set with @f[setf], @f[update-modeline-fields] is called for each window into
+@i[buffer].
+@enddefun
+
+@defun[fun {buffer-modeline-field-p}, args {@i[buffer] @i[field]}]
+If @i[field], a modeline-field or the name of one, is in buffer's list of
+modeline-field objects, it is returned; otherwise, this returns nil.
+@enddefun
+
+@defun[fun {update-modeline-fields}, args {@i[buffer] @i[window]}]
+This invokes each modeline-field object's function from @i[buffer]'s list,
+passing @i[buffer] and @i[window].  The results are collected regarding each
+modeline-field object's width as appropriate, and the window is marked so
+the next trip through redisplay will reflect the changes.  If window does not
+display modelines, then no computation occurs.
+@enddefun
+
+@defun[fun {update-modeline-field}, args {@i[buffer] @i[window] @i[field-or-name}]
+This invokes the modeline-field object's function for @i[field-or-name], which
+is a modeline-field object or the name of one for @i[buffer].  This passes
+@i[buffer] and @i[window] to the update function.  The result is applied to the
+@i[window]'s modeline display using the modeline-field object's width, and the
+window is marked so the next trip through redisplay will reflect the changes.
+If the window does not display modelines, then no computation occurs.  If
+@i[field-or-name] is not found in @i[buffer]'s list of modeline-field objects,
+then this signals an error.  See @f[buffer-modeline-field-p] above.
+@enddefun
+
+
+
+@chapter(Altering and Searching Text)
+@label[doing-stuff]
+
+@section(Altering Text)
+@index(Altering text)
+@index(Inserting)
+@index(Deleting)
+A note on marks and text alteration: @kwd[temporary] marks are invalid
+after any change has been made to the text the mark points to; it is an
+error to use a temporary mark after such a change has been made.  If
+text is deleted which has permanent marks pointing into it then they
+are left pointing to the position where the text was.
+
+@defun[fun {insert-character}, args {@i[mark] @i[character]}]
+@defun1[fun {insert-string}, args {@i[mark] @i[string]}]
+@defun1[fun {insert-region}, args {@i[mark] @i[region]}]
+Inserts @i[character], @i[string] or @i[region] at @i[mark].
+@f[insert-character] signals an error if @i[character] is not
+@f[string-char-p].  If @i[string] or @i[region] is empty, and @i[mark] is in
+some buffer, then @hemlock leaves @f[buffer-modified] of @i[mark]'s buffer
+unaffected.
+@enddefun
+
+@defun[fun {ninsert-region}, args {@i[mark] @i[region]}]
+Like @f[insert-region], inserts the @i[region] at the @i[mark]'s position,
+destroying the source region.  This must be used with caution, since if anyone
+else can refer to the source region bad things will happen.  In particular, one
+should make sure the region is not linked into any existing buffer.  If
+@i[region] is empty, and @i[mark] is in some buffer, then @hemlock leaves
+@f[buffer-modified] of @i[mark]'s buffer unaffected.
+@enddefun
+
+@defun[fun {delete-characters}, args {@i[mark] @i[n]}]
+This deletes @i[n] characters after the @i[mark] (or -@i[n] before if @i[n] is
+negative).  If @i[n] characters after (or -@i[n] before) the @i[mark] do not
+exist, then this returns @nil; otherwise, it returns @true.  If @i[n] is zero,
+and @i[mark] is in some buffer, then @hemlock leaves @f[buffer-modified] of
+@i[mark]'s buffer unaffected.
+@enddefun
+
+@defun[fun {delete-region}, args {@i[region]}]
+This deletes @i[region].  This is faster than @f[delete-and-save-region]
+(below) because no lines are copied.  If @i[region] is empty and contained in
+some buffer's @f[buffer-region], then @hemlock leaves @f[buffer-modified] of
+the buffer unaffected.
+@enddefun
+
+@defun[fun {delete-and-save-region}, args {@i[region]}]
+This deletes @i[region] and returns a region containing the original
+@i[region]'s text.  If @i[region] is empty and contained in some buffer's
+@f[buffer-region], then @hemlock leaves @f[buffer-modified] of the buffer
+unaffected.  In this case, this returns a distinct empty region.
+@enddefun
+
+@defun[fun {filter-region}, args {@i[function] @i[region]}]
+Destructively modifies @i[region] by replacing the text
+of each line with the result of the application of @i[function] to a
+string containing that text.  @i[Function] must obey the following
+restrictions:
+@begin[enumerate]
+The argument may not be destructively modified.
+
+The return value may not contain newline characters.
+
+The return value may not be destructively modified after it is
+returned from @i[function].
+@end[enumerate]
+The strings are passed in order, and are always simple strings.
+
+Using this function, a region could be uppercased by doing:
+@lisp
+(filter-region #'string-upcase region)
+@endlisp
+@enddefun
+
+
+@section(Text Predicates)
+@defun[fun {start-line-p}, args {@i[mark]}]
+Returns @true if the @i(mark) points before the first character in a line,
+@nil otherwise.
+@enddefun
+
+@defun[fun {end-line-p}, args {@i[mark]}]
+Returns @true if the @i(mark) points after the last character in a line and
+before the newline, @nil otherwise.
+@enddefun
+
+@defun[fun {empty-line-p}, args {@i[mark]}]
+Return @true of the line which @i[mark] points to contains no characters.
+@enddefun
+
+@defun[fun {blank-line-p}, args {@i[line]}]
+Returns @true if @i[line] contains only characters with a
+@hid[Whitespace] attribute of 1.  See chapter @ref[character-attributes] for
+discussion of character attributes.
+@enddefun
+
+@defun[fun {blank-before-p}, args {@i[mark]}]
+@defun1[fun {blank-after-p}, args {@i[mark]}]
+These functions test if all the characters preceding or following
+@i[mark] on the line it is on have a @hid[Whitespace] attribute of @f[1].
+@enddefun
+
+@defun[fun {same-line-p}, args {@i[mark1] @i[mark2]}]
+Returns @true if @i(mark1) and @i(mark2) point to the same line, or @nil
+otherwise;  That is,
+@example[(same-line-p a b) <==> (eq (mark-line a) (mark-line b))]
+@enddefun
+
+@defun[fun {mark<}, funlabel {mark-LSS}, args {@i[mark1] @i[mark2]}]
+@defun1[fun {mark<=}, funlabel {mark-LEQ}, args {@i[mark1] @i[mark2]}]
+@defun1[fun {mark=}, funlabel {mark-EQL}, args {@i[mark1] @i[mark2]}]
+@defun1[fun {mark/=}, funlabel {mark-NEQ}, args {@i[mark1] @i[mark2]}]
+@defun1[fun {mark>=}, funlabel {mark-GEQ}, args {@i[mark1] @i[mark2]}]
+@defun1[fun {mark>}, funlabel {mark-GTR}, args {@i[mark1] @i[mark2]}]
+These predicates test the relative ordering of two marks in a piece of
+text, that is a mark is @f[mark>] another if it points to a position
+after it.  If the marks point into different, non-connected pieces of
+text, such as different buffers, then it is an error to test their
+ordering; for such marks @f[mark=] is always false and @f[mark/=] is
+always true.
+@enddefun
+
+@defun[fun {line<}, funlabel {line-LSS}, args {@i[line1] @i[line2]}]
+@defun1[fun {line<=}, funlabel {line-LEQ}, args {@i[line1] @i[line2]}]
+@defun1[fun {line>=}, funlabel {line-GEQ}, args {@i[line1] @i[line2]}]
+@defun1[fun {line>}, funlabel {line-GTR}, args {@i[line1] @i[line2]}]
+These predicates test the ordering of @i[line1] and @i[line2].  If the
+lines are in unconnected pieces of text it is an error to test their
+ordering.
+@enddefun
+
+@defun[fun {lines-related}, args {@i[line1] @i[line2]}]
+This function returns @true if @i[line1] and @i[line2] are in the same
+piece of text, or @nil otherwise.
+@enddefun
+
+@defun[fun {first-line-p}, args {@i[mark]}]
+@defun1[fun {last-line-p}, args {@i[mark]}]
+@f[first-line-p] returns @true if there is no line before the line
+@i[mark] is on, and @nil otherwise.  @i[Last-line-p] similarly tests
+tests whether there is no line after @i[mark].
+@enddefun
+
+
+@section(Kill Ring)
+@index(Kill ring)
+@label(kill-ring)
+
+@defvar[var {kill-ring}]
+This is a ring (see section @ref[rings]) of regions deleted from buffers.
+Some commands save affected regions on the kill ring before performing
+modifications.  You should consider making the command undoable (see section
+@ref[undo]), but this is a simple way of achieving a less satisfactory means
+for the user to recover.
+@enddefvar
+
+@defun[fun {kill-region}, args {@i[region] @i[current-type]}]
+This kills @i[region] saving it in @var[kill-ring].  @i[Current-type] is either
+@kwd[kill-forward] or @kwd[kill-backward].  When the @funref[last-command-type]
+is one of these, this adds @i[region] to the beginning or end, respectively, of
+the top of @var[kill-ring].  The result of calling this is undoable using the
+command @hid[Undo] (see the @i[Hemlock User's Manual]).  This sets
+@f[last-command-type] to @i[current-type], and it interacts with
+@f[kill-characters].
+@enddefun
+
+@defun[fun {kill-characters}, args {@i[mark] @i[count]}]
+@defhvar1[var {Character Deletion Threshold}, val {5}]
+@f[kill-characters] kills @i[count] characters after @i[mark] if @i[count] is
+positive, otherwise before @i[mark] if @i[count] is negative.  When @i[count]
+is greater than or equal to @hid[Character Deletion Threshold], the killed
+characters are saved on @var[kill-ring].  This may be called multiple times
+contiguously (that is, without @funref[last-command-type] being set) to
+accumulate an effective count for purposes of comparison with the threshold.
+
+This sets @f[last-command-type], and it interacts with @f[kill-region].  When
+this adds a new region to @var[kill-ring], it sets @f[last-command-type] to
+@kwd[kill-forward] (if @i[count] is positive) or @kwd[kill-backward] (if
+@i[count] is negative).  When @f[last-command-type] is @kwd[kill-forward] or
+@kwd[kill-backward], this adds the killed characters to the beginning (if
+@i[count] is negative) or the end (if @i[count] is positive) of the top of
+@var[kill-ring], and it sets @f[last-command-type] as if it added a new region
+to @var[kill-ring].  When the kill ring is unaffected, this sets
+@f[last-command-type] to @kwd[char-kill-forward] or @kwd[char-kill-backward]
+depending on whether @i[count] is positive or negative, respectively.
+
+This returns mark if it deletes characters.  If there are not @i[count]
+characters in the appropriate direction, this returns nil.
+@enddefun
+
+
+@section(Active Regions)
+@index(Active regions)
+@label(active-regions)
+
+Every buffer has a mark stack (page @pageref[mark-stack]) and a mark known as
+the point where most text altering nominally occurs.  Between the top of the
+mark stack, the @f[current-mark], and the @f[current-buffer]'s point, the
+@f[current-point], is what is known as the @f[current-region].  Certain
+commands signal errors when the user tries to operate on the @f[current-region]
+without its having been activated.  If the user turns off this feature, then
+the @f[current-region] is effectively always active.
+
+When writing a command that marks a region of text, the programmer should make
+sure to activate the region.  This typically occurs naturally from the
+primitives that you use to mark regions, but sometimes you must explicitly
+activate the region.  These commands should be written this way, so they do not
+require the user to separately mark an area and then activate it.  Commands
+that modify regions do not have to worry about deactivating the region since
+modifying a buffer automatically deactivates the region.  Commands that insert
+text often activate the region ephemerally; that is, the region is active for
+the immediately following command, allowing the user wants to delete the region
+inserted, fill it, or whatever.
+
+Once a marking command makes the region active, it remains active until:
+@begin[itemize]
+a command uses the region,
+
+a command modifies the buffer,
+
+a command changes the current window or buffer,
+
+a command signals an editor-error,
+
+or the user types @binding[C-g].
+@end[itemize]
+
+@defhvar[var "Active Regions Enabled", val {t}]
+When this variable is non-@nil, some primitives signal an editor-error if
+the region is not active.  This may be set to @nil for more traditional @emacs
+region semantics.
+@enddefhvar
+
+@defvar[var {ephemerally-active-command-types}]
+This is a list of command types (see section @ref[command-types]), and its
+initial value is the list of @kwd[ephemerally-active] and @kwd[unkill].  When
+the previous command's type is one of these, the @f[current-region] is active
+for the currently executing command only, regardless of whether it does
+something to deactivate the region.  However, the current command may activate
+the region for future commands.  @kwd[ephemerally-active] is a default command
+type that may be used to ephemerally activate the region, and @kwd[unkill] is
+the type used by two commands, @hid[Un-kill] and @hid[Rotate Kill Ring] (what
+users typically think of as @binding[C-y] and @binding[M-y]).
+@enddefvar
+
+@defun[fun {activate-region}]
+This makes the @f[current-region] active.
+@enddefun
+
+@defun[fun {deactivate-region}]
+After invoking this the @f[current-region] is no longer active.
+@enddefun
+
+@defun[fun {region-active-p}]
+Returns whether the @f[current-region] is active, including ephemerally.  This
+ignores @hid[Active Regions Enabled].
+@enddefun
+
+@defun[fun {check-region-active}]
+This signals an editor-error when active regions are enabled, and the
+@f[current-region] is not active.
+@enddefun
+
+@defun[fun {current-region},
+       args {@optional @i[error-if-not-active] @i[deactivate-region]}]
+This returns a region formed with @f[current-mark] and @f[current-point],
+optionally signaling an editor-error if the current region is not active.
+@i[Error-if-not-active] defaults to @true.  Each call returns a distinct region
+object.  Depending on @i[deactivate-region] (defaults to @true), fetching the
+current region deactivates it.  @hemlock primitives are free to modify text
+regardless of whether the region is active, so a command that checks for this
+can deactivate the region whenever it is convenient.
+@enddefun
+
+
+@section(Searching and Replacing)
+@index(Searching)
+@index(Replacing)
+
+Before using any of these functions to do a character search, look at character
+attributes (page @pageref[character-attributes]).  They provide a facility
+similar to the syntax table in real EMACS.  Syntax tables are a powerful,
+general, and efficient mechanism for assigning meanings to characters in
+various modes.
+
+@defcon[var {search-char-code-limit}]
+An exclusive upper limit for the char-code of characters given to the searching
+functions.  The result of searches for characters with a char-code greater than
+or equal to this limit is ill-defined, but it is @i[not] an error to do such
+searches.
+@enddefcon
+
+@defun[fun {new-search-pattern},
+args {@i[kind] @i[direction] @i[pattern] @optional @i[result-search-pattern]}] 
+
+Returns a @i[search-pattern] object which can be given to the @f[find-pattern]
+and @f[replace-pattern] functions.  A search-pattern is a specification of a
+particular sort of search to do.  @i[direction] is either @kwd[forward] or
+@kwd[backward], indicating the direction to search in.  @i[kind] specifies the
+kind of search pattern to make, and @i[pattern] is a thing which specifies what
+to search for.
+
+The interpretation of @i[pattern] depends on the @i[kind] of pattern being
+made.  Currently defined kinds of search pattern are:
+@begin(description)
+@kwd[string-insensitive]@\Does a case-insensitive string search,
+@i[pattern] being the string to search for.
+
+@kwd[string-sensitive]@\Does a case-sensitive string search for
+@i[pattern].
+
+@kwd[character]@\Finds an occurrence of the character @i[pattern].
+This is case sensitive.
+
+@kwd[not-character]@\Find a character which is not the character
+@i[pattern].
+
+@kwd[test]@\Finds a character which satisfies the function @i[pattern].
+This function may not be applied an any particular fashion, so it
+should depend only on what its argument is, and should have no
+side-effects.
+
+@kwd[test-not]@\Similar to as @kwd[test], except it finds a character that
+fails the test.
+
+@kwd[any]@\Finds a character that is in the string @i[pattern].
+
+@kwd[not-any]@\Finds a character that is not in the string @i[pattern].
+@end(description)
+
+@i[result-search-pattern], if supplied, is a search-pattern to
+destructively modify to produce the new pattern.  Where reasonable
+this should be supplied, since some kinds of search patterns may
+involve large data structures.
+@enddefun
+
+@defun[fun {search-pattern-p}, args {@i[search-pattern]}]
+Returns @true if @i[search-pattern] is a @f[search-pattern] object, otherwise
+@nil.
+@enddefun
+
+@defun[fun {get-search-pattern}, args {@i[string] @i[direction]}]
+@defvar1[var {last-search-pattern}]
+@defvar1[var {last-search-string}]
+@f[get-search-pattern] interfaces to a default search string and pattern that
+search and replacing commands can use.  These commands then share a default
+when prompting for what to search or replace, and save on consing a search
+pattern each time they execute.  This uses @hid[Default Search Kind] (see the
+@i[Hemlock User's Manual]) when updating the pattern object.  This returns the
+pattern, so you probably don't need to refer to @var[last-search-pattern], but
+@var[last-search-string] is useful when prompting.
+@enddefun
+
+@defun[fun {find-pattern}, args {@i[mark] @i[search-pattern]}]
+Find the next match of @i[search-pattern] starting at @i[mark].  If a
+match is found then @i[mark] is altered to point before the matched text
+and the number of characters matched is returned.  If no match is
+found then @nil is returned and @i[mark] is not modified.
+@enddefun
+
+@defun[fun {replace-pattern}, args
+        {@i[mark] @i[search-pattern] @i[replacement] @optional @i[n]}]
+Replace @i[n] matches of @i[search-pattern] with the string
+@i[replacement] starting at @i[mark].  If @i[n] is @nil (the default)
+then replace all matches.  A mark pointing before the last replacement
+done is returned.
+@enddefun
+
+
+
+@Chapter(The Current Environment)
+@label(current-environment)
+@index(Current environment)
+
+@section(Different Scopes)
+    In @hemlock the values of @i[variables] (page @pageref[variables]),
+@i[key-bindings] (page @pageref(key-bindings)) and
+@i[character-attributes] (page @pageref[character-attributes]) may
+depend on the @funref(current-buffer) and the modes
+active in it.  There are three possible scopes for
+@hemlock values:
+@begin(description)
+@i[buffer local]@\The value is present only if the buffer it is local
+to is the @f[current-buffer].
+
+@i[mode local]@\The value is present only when the mode it is local to
+is active in the @f[current-buffer].
+
+@i[global]@\The value is always present unless shadowed by a buffer or
+mode local value.
+@end(description)
+
+
+@section(Shadowing)
+    It is possible for there to be a conflict between different values
+for the same thing in different scopes.  For example, there be might a
+global binding for a given variable and also a local binding in the
+current buffer.  Whenever there is a conflict shadowing occurs,
+permitting only one of the values to be visible in the current
+environment.
+
+    The process of resolving such a conflict can be described as a
+search down a list of places where the value might be defined, returning
+the first value found.  The order for the search is as follows:
+@begin(enumerate)
+Local values in the current buffer.
+
+Mode local values in the minor modes of the current buffer, in order
+from the highest precedence mode to the lowest precedence mode.  The
+order of minor modes with equal precedences is undefined.
+
+Mode local values in the current buffer's major mode.
+
+Global values.
+@end(enumerate)
+
+
+
+@chapter(Hemlock Variables)
+@index (Hemlock variables)
+@label(variables)
+@hemlock implements a system of variables separate from normal Lisp variables
+for the following reasons:
+@begin(enumerate)
+@hemlock has different scoping rules which are useful in an editor.  @hemlock
+variables can be local to a @i(buffer) (page @pageref[buffers]) or a @i(mode)
+(page @pageref[modes]).
+
+@hemlock variables have @i(hooks) (page @pageref[hooks]), lists of functions
+called when someone sets the variable.  See @f[variable-value] for the
+arguments @hemlock passes to these hook functions.
+
+There is a database of variable names and documentation which makes it easier
+to find out what variables exist and what their values mean.
+@end(enumerate)
+
+
+@section(Variable Names)
+To the user, a variable name is a case insensitive string.  This
+string is referred to as the @i[string name] of the variable.  A
+string name is conventionally composed of words separated by spaces.
+
+In Lisp code a variable name is a symbol.  The name of this symbol is
+created by replacing any spaces in the string name with hyphens.  This
+symbol name is always interned in the @hemlock package and referring
+to a symbol with the same name in the wrong package is an error.
+
+@defvar[var {global-variable-names}]
+This variable holds a string-table of the names of all the global @hemlock
+variables.  The value of each entry is the symbol name of the variable.
+@enddefvar
+
+@defun[fun {current-variable-tables}]
+This function returns a list of variable tables currently established,
+globally, in the @f[current-buffer], and by the modes of the
+@f[current-buffer].  This list is suitable for use with
+@f[prompt-for-variable].
+@enddefun
+
+
+@section(Variable Functions)
+In the following descriptions @i[name] is the symbol name of the variable.
+
+@defun[fun {defhvar}, args {@i[string-name] @i[documentation]},
+	keys {[mode][buffer][hooks][value]}]
+ This function defines a @hemlock variable.  Functions that take a variable
+name signal an error when the variable is undefined.
+@begin(description)
+@i[string-name]@\The string name of the variable to define.
+
+@i[documentation]@\The documentation string for the variable.
+
+@multiple{
+@kwd[mode],
+@kwd[buffer]}@\
+ If @i[buffer] is supplied, the variable is local to that buffer.  If @i[mode]
+is supplied, it is local to that mode.  If neither is supplied, it is global.
+
+@kwd[value]@\
+ This is the initial value for the variable, which defaults to @nil.
+
+@kwd[hooks]@\
+ This is the initial list of functions to call when someone sets the variable's
+value.  These functions execute before @hemlock establishes the new value.  See
+@f[variable-value] for the arguments passed to the hook functions.
+@end(description)
+If a variable with the same name already exists in the same place, then
+@f[defhvar] sets its hooks and value from @i[hooks] and @i[value] if the user
+supplies these keywords.
+@enddefun
+
+@defun[fun {variable-value}, args {@i[name] @optional @i[kind] @i[where]}]
+This function returns the value of a @hemlock variable in some place.
+The following values for @i[kind] are defined:
+@begin[description]
+@kwd[current]@\
+ Return the value present in the current environment, taking into consideration
+any mode or buffer local variables.  This is the default.
+
+@kwd[global]@\
+ Return the global value.
+
+@kwd[mode]@\
+ Return the value in the mode named @i[where].
+
+@kwd[buffer]@\
+ Return the value in the buffer @i[where].
+@end[description]
+When set with @f[setf], @hemlock sets the value of the specified variable and
+invokes the functions in its hook list with @i[name], @i[kind], @i[where], and
+the new value.
+@enddefun
+
+@defun[fun {variable-documentation}, args
+	{@i[name] @optional @i[kind] @i[where]}] 
+@defun1[fun {variable-hooks}, args
+        {@i[name] @optional @i[kind] @i[where]}]
+@defun1[fun {variable-name}, args
+	{@i[name] @optional @i[kind] @i[where]}]
+These function return the documentation, hooks and string name of a
+@hemlock variable.  The @i[kind] and @i[where] arguments are the same
+as for @f[variable-value].  The documentation and hook list may be set
+using @f[setf].
+@enddefun
+
+@defun[fun {string-to-variable}, args {@i[string]}]
+This function converts a string into the corresponding variable symbol
+name.  @i[String] need not be the name of an actual @hemlock variable.
+@enddefun
+
+@defmac[fun {value}, args {@i[name]}] 
+@defmac1[fun {setv}, args {@i[name] @i[new-value]}]
+These macros get and set the current value of the @hemlock variable
+@i[name].  @i[Name] is not evaluated.  There is a @f[setf] form for
+@f[value].
+@enddefmac
+
+@Defmac[Fun {hlet}, Args {(@Mstar<(@i[var] @i[value])>) @Mstar<@i[form]>}]
+This macro is very similar to @f[let] in effect; within its scope each
+of the @hemlock variables @i[var] have the respective @i[value]s, but
+after the scope is exited by any means the binding is removed.  This
+does not cause any hooks to be invoked.  The value of the last
+@i[form] is returned.
+@enddefmac
+
+@defun[fun {hemlock-bound-p}, args {@i[name] @optional @i[kind] @i[where]}]
+Returns @true if @i[name] is defined as a @hemlock variable in the
+place specified by @i[kind] and @i[where], or @nil otherwise.
+@enddefun
+
+@defun[fun {delete-variable}, args {@i(name) @optional @i[kind] @i[where]}]
+@defhvar1[var {Delete Variable Hook}]
+@f[delete-variable] makes the @hemlock variable @i[name] no longer
+defined in the specified place.  @i[Kind] and @i[where] have the same
+meanings as they do for @f[variable-value], except that @kwd[current]
+is not available, and the default for @i[kind] is @kwd[global]
+
+An error will be signaled if no such variable exists.  The hook,
+@hid[Delete Variable Hook] is invoked with the same arguments before the
+variable is deleted.
+@enddefun
+
+
+@section(Hooks)
+@index(Hooks)
+@label[hooks]
+@hemlock actions such as setting variables, changing buffers, changing windows,
+turning modes on and off, etc., often have hooks associated with them.  A hook
+is a list of functions called before the system performs the action.  The
+manual describes the object specific hooks with the rest of the operations
+defined on these objects.
+
+Often hooks are stored in @hemlock variables, @hid[Delete Buffer Hook] and
+@hid[Set Window Hook] for example.  This leads to a minor point of confusion
+because these variables have hooks that the system executes when someone
+changes their values.  These hook functions @hemlock invokes when someone sets
+a variable are an example of a hook stored in an object instead of a @hemlock
+variable.  These are all hooks for editor activity, but @hemlock keeps them in
+different kinds of locations.  This is why some of the routines in this section
+have a special interpretation of the hook @i[place] argument.
+
+@defmac[fun {add-hook}, args {@i[place] @i[hook-fun]}]
+@defmac1[fun {remove-hook}, args {@i[place] @i[hook-fun]}]
+These macros add or remove a hook function in some @i[place].  If @i[hook-fun]
+already exists in @i[place], this call has no effect.  If @i[place] is a
+symbol, then it is a @hemlock variable; otherwise, it is a generalized variable
+or storage location.  Here are two examples:
+@Begin[ProgramExample]
+(add-hook delete-buffer-hook 'remove-buffer-from-menu)
+
+(add-hook (variable-hooks 'check-mail-interval)
+          'reschedule-mail-check)
+@End[ProgramExample]
+@enddefmac
+
+@defmac[fun {invoke-hook}, args {@i[place] @rest @i[args]}]
+This macro calls all the functions in @i[place].  If @i[place] is a symbol,
+then it is a @hemlock variable; otherwise, it is a generalized variable.
+@enddefun
+
+
+
+@chapter(Commands)
+@index (Commands)
+@label[commands]
+
+
+@section(Introduction)
+The way that the user tells @hemlock to do something is by invoking a
+@i(command).  Commands have three attributes:
+@begin(description)
+@i[name]@\A command's name provides a way to refer to it.  Command
+names are usually capitalized words separated by spaces, such as 
+@hid[Forward Word].
+
+@i[documentation]@\The documentation for a command is used by
+on-line help facilities.
+
+@i[function]@\A command is implemented by a Lisp function, which is callable
+from Lisp.
+@end(description)
+
+@defvar[var {command-names}]
+Holds a string-table (page @pageref[string-tables]) associating
+command names to command objects.  Whenever a new command is defined
+it is entered in this table.
+@enddefvar
+
+
+@subsection(Defining Commands)
+
+@defmac[fun {defcommand}, args 
+{@^@mgroup<@i[command-name] @MOR (@i[command-name] @i[function-name])> @i[lambda-list]
+@\@i[command-doc] @i[function-doc] @mstar<@i[form]>}]
+
+Defines a command named @i[name].  @f[defcommand] creates a function to
+implement the command from the @i[lambda-list] and @i[form]'s supplied.  The
+@i[lambda-list] must specify one required argument, see section
+@ref[invoking-commands-as-functions], which by convention is typically named
+@f[p].  If the caller does not specify @i[function-name], @f[defcommand]
+creates the command name by replacing all spaces with hyphens and appending
+"@f[-command]".  @i[Function-doc] becomes the documentation for the function
+and should primarily describe issues involved in calling the command as a
+function, such as what any additional arguments are.  @i[Command-doc] becomes
+the command documentation for the command.  @enddefmac
+
+@defun[fun {make-command}, args 
+	{@i[name] @i[documentation] @i[function]}] 
+Defines a new command named @i[name], with command documentation
+@I[documentation] and function @i[function].  The command in entered
+in the string-table @varref[command-names], with the command object as
+its value.  Normally command implementors will use the @f[defcommand]
+macro, but this permits access to the command definition mechanism at
+a lower level, which is occasionally useful.
+@enddefun
+
+@defun[fun {commandp}, args {@i[command]}]
+Returns @true if @i[command] is a @f[command] object, otherwise @nil.
+@enddefun
+
+@defun[fun {command-documentation}, args {@i[command]}]
+@defun1[fun {command-function}, args {@i[command]}]
+@defun1[fun {command-name}, args {@i[command]}]
+Returns the documentation, function, or name for @i[command].  These
+may be set with @f[setf].
+@enddefun
+
+
+@subsection(Command Documentation)
+@i[Command documentation] is a description of what the command does
+when it is invoked as an extended command or from a key.  Command
+documentation may be either a string or a function.  If the
+documentation is a string then the first line should briefly summarize
+the command, with remaining lines filling the details.  Example:
+@lisp
+(defcommand "Forward Character" (p)
+  "Move the point forward one character.
+   With prefix argument move that many characters, with negative
+   argument go backwards."
+  "Move the point of the current buffer forward p characters."
+   . . .)
+@endlisp
+
+Command documentation may also be a function of one argument.  The
+function is called with either @kwd[short] or @kwd[full], indicating
+that the function should return a short documentation string or do
+something to document the command fully.
+
+
+@section(The Command Interpreter)
+@index[Interpreter, command]
+@index[Invocation, command]
+@index[Command interpreter]
+
+The @i[command interpreter] is a function which reads key-events (see section
+@ref[key-events-intro]) from the keyboard and dispatches to different commands
+on the basis of what the user types.  When the command interpreter executes a
+command, we say it @i[invokes] the command.  The command interpreter also
+provides facilities for communication between commands contiguously running
+commands, such as a last command type register.  It also takes care of
+resetting communication mechanisms, clearing the echo area, displaying partial
+keys typed slowly by the user, etc.
+
+@defvar[var {invoke-hook}]
+This variable contains a function the command interpreter calls when it wants
+to invoke a command.  The function receives the command and the prefix argument
+as arguments.  The initial value is a function which simply funcalls the
+@f[command-function] of the command with the supplied prefix argument.  This is
+useful for implementing keyboard macros and similar things.
+@enddefhvar
+
+@defhvar[var "Command Abort Hook"]
+The command interpreter invokes the function in this variable whenever someone
+aborts a command (for example, if someone called @f[editor-error]).
+@enddefhvar
+
+When @hemlock initially starts the command interpreter is in control, but
+commands may read from the keyboard themselves and assign whatever
+interpretation they will to the key-events read.  Commands may call the command
+interpreter recursively using the function @funref[recursive-edit].
+
+
+@subsection(Editor Input)
+@label[key-events-intro]
+@index[key-events]
+
+The canonical representation of editor input is a key-event structure.  Users
+can bind commands to keys (see section @ref[key-bindings]), which are non-zero
+length sequences of key-events.  A key-event consists of an identifying token
+known as a @i[keysym] and a field of bits representing modifiers.  Users define
+keysyms, integers between 0 and 65535 inclusively, by supplying names that
+reflect the legends on their keyboard's keys.  Users define modifier names
+similarly, but the system chooses the bit and mask for recognizing the
+modifier.  You can use keysym and modifier names to textually specify
+key-events and Hemlock keys in a @f[#k] syntax.  The following are some
+examples:
+@begin[programexample]
+   #k"C-u"
+   #k"Control-u"
+   #k"c-m-z"
+   #k"control-x meta-d"
+   #k"a"
+   #k"A"
+   #k"Linefeed"
+@end[programexample]
+This is convenient for use within code and in init files containing
+@f[bind-key] calls.
+
+The @f[#k] syntax is delimited by double quotes, but the system parses the
+contents rather than reading it as a Common Lisp string.  Within the double
+quotes, spaces separate multiple key-events.  A single key-event optionally
+starts with modifier names terminated by hyphens.  Modifier names are
+alphabetic sequences of characters which the system uses case-insensitively.
+Following modifiers is a keysym name, which is case-insensitive if it consists
+of multiple characters, but if the name consists of only a single character,
+then it is case-sensitive.
+
+You can escape special characters @dash hyphen, double quote, open angle
+bracket, close angle bracket, and space @dash with a backslash, and you can
+specify a backslash by using two contiguously.  You can use angle brackets to
+enclose a keysym name with many special characters in it.  Between angle
+brackets appearing in a keysym name position, there are only two special
+characters, the closing angle bracket and backslash.
+
+For more information on key-events see section @ref[key-events].
+
+
+
+@subsection(Binding Commands to Keys)
+@label[Key-Bindings]
+@Index[Key Bindings]
+
+The command interpreter determines which command to invoke on the basis of
+@i[key bindings].  A key binding is an association between a command and a
+sequence of key-events (see section @ref[key-events-intro].  A sequence of
+key-events is called a @i[key] and is represented by a single key-event or a
+sequence (list or vector) of key-events.
+
+Since key bindings may be local to a mode or buffer, the current environment
+(page @pageref[current-environment]) determines the set of key bindings in
+effect at any given time.  When the command interpreter tries to find the
+binding for a key, it first checks if there is a local binding in the
+@w[@funref[current-buffer]], then if there is a binding in each of the minor
+modes and the major mode for the current buffer @w[(page @pageref[modes])], and
+finally checks to see if there is a global binding.  If no binding is found,
+then the command interpreter beeps or flashes the screen to indicate this.
+
+@defun[fun {bind-key}, args
+        {@i(name) @i(key) @optional @i[kind] @i[where]}]
+ This function associates command @i[name] and @i[key] in some environment.
+@i[Key] is either a key-event or a sequence of key-events.  There are three
+possible values of @i[kind]:
+@begin(description)
+@kwd[global]@\
+ The default, make a global key binding.
+
+@kwd[mode]@\
+ Make a mode specific key binding in the mode whose name is @i[where].
+
+@kwd[buffer]@\
+ Make a binding which is local to buffer @i[where].
+@end(description)
+
+This processes @i[key] for key translations before establishing the binding.
+See section @ref[key-trans].
+
+If the key is some prefix of a key binding which already exists in the
+specified place, then the new one will override the old one, effectively
+deleting it.
+
+@f[ext:do-alpha-key-events] is useful for setting up bindings in certain new
+modes.
+@enddefun
+
+@defun[fun {command-bindings}, args {@i[command]}]
+This function returns a list of the places where @i[command] is bound.  A place
+is specified as a list of the key (always a vector), the kind of binding, and
+where (either the mode or buffer to which the binding is local, or @nil if it
+is a global).
+@enddefun
+
+@defun[fun {delete-key-binding}, args {@i[key] @optional @i[kind] @i[where]}]
+This function removes the binding of @i[key] in some place.  @i[Key] is either
+a key-event or a sequence of key-events.  @i[kind] is the kind of binding to
+delete, one of @kwd[global] (the default), @kwd[mode] or @kwd[buffer].  If
+@i[kind] is @kwd[mode], @i[where] is the mode name, and if @i[kind] is
+@kwd[buffer], then @i[where] is the buffer.
+
+This function signals an error if @i[key] is unbound.
+
+This processes @i[key] for key translations before deleting the binding.  See
+section @ref[key-trans].
+@enddefun
+
+@defun[fun {get-command}, args {@i[key] @optional @i[kind] @i[where]}]
+This function returns the command bound to @i[key], returning @nil if it is
+unbound.  @i[Key] is either a key-event or a sequence of key-events.  If
+@i[key] is an initial subsequence of some keys, then this returns the keyword
+@kwd[prefix].  There are four cases of @i[kind]:
+@begin(description)
+@kwd[current]@\
+ Return the current binding of @i[key] using the current buffer's search list.
+If there are any transparent key bindings for @i[key], then they are returned
+in a list as a second value.
+
+@kwd[global]@\
+ Return the global binding of @i[key].  This is the default.
+
+@kwd[mode]@\
+ Return the binding of @i[key] in the mode named @i[where].
+
+@kwd[buffer]@\
+ Return the binding of @i[key] local to the buffer @i[where].
+@end(description)
+
+This processes @i[key] for key translations before looking for any binding.
+See section @ref[key-trans].
+@enddefun
+
+@defun[fun {map-bindings}, Args {@i[function] @i[kind] @optional @i[where]}]
+This function maps over the key bindings in some place.  For each binding, this
+passes @i[function] the key and the command bound to it.  @i[Kind] and
+@i[where] are the same as in @f[bind-key].  The key is not guaranteed to remain
+valid after a given iteration.
+@enddefmac
+
+
+@subsection[Key Translation]
+@index[bit-prefix keys]
+@index[key translation]
+@index[translating keys]
+@label[key-trans]
+Key translation is a process that the command interpreter applies to keys
+before doing anything else.  There are two kinds of key translations:
+substitution and bit-prefix.  In either case, the command interpreter
+translates a key when a specified key-event sequence appears in a key.
+
+In a substitution translation, the system replaces the matched subsequence with
+another key-event sequence.  Key translation is not recursively applied to the
+substituted key-events.
+
+In a bit-prefix translation, the system removes the matched subsequence and
+effectively sets the specified bits in the next key-event in the key.
+
+While translating a key, if the system encounters an incomplete final
+subsequence of key-events, it aborts the translation process.  This happens
+when those last key-events form a prefix of some translation.  It also happens
+when they translate to a bit-prefix, but there is no following key-event to
+which the system can apply the indicated modifier.  If there is a binding for
+this partially untranslated key, then the command interpreter will invoke that
+command; otherwise, it will wait for the user to type more key-events.
+
+@defun[fun {key-translation}, args {@i[key]}]
+This form is @f[setf]'able and allows users to register key translations that
+the command interpreter will use as users type key-events.
+
+This function returns the key translation for @i[key], returning @nil if there
+is none.  @i[Key] is either a key-event or a sequence of key-events.  If
+@i[key] is a prefix of a translation, then this returns @kwd[prefix].
+
+A key translation is either a key or modifier specification.  The bits
+translations have a list form: @w<@f[(:bits {]@i[bit-name]@f[}*)]>.
+
+Whenever @i[key] appears as a subsequence of a key argument to the binding
+manipulation functions, that portion will be replaced with the translation.
+@enddefun
+
+
+
+@subsection[Transparent Key Bindings]
+@label[transparent-key-bindings]
+@index[Transparent key bindings]
+
+Key bindings local to a mode may be @i[transparent].  A transparent key
+binding does not shadow less local key bindings, but rather indicates that
+the bound command should be invoked before the first normal key binding.
+Transparent key bindings are primarily useful for implementing minor modes
+such as auto fill and word abbreviation.  There may be several transparent
+key bindings for a given key, in which case all of the commands bound are
+invoked in the order they were found.  If there no normal key binding for a
+key typed, then the command interpreter acts as though the key is unbound
+even if there are transparent key bindings.
+
+The @kwd[transparent-p] argument to @funref[defmode] determines whether the
+key bindings in a mode are transparent or not.
+
+
+@subsection (Interactive)
+@index (Keyboard macro vs. interactive)
+@index (Interactive vs. keyboard macro)
+@Hemlock supports keyboard macros.  A user may enter a mode where the editor
+records his actions, and when the user exits this mode, the command @hid[Last
+Keyboard Macro] plays back the actions.  Some commands behave differently when
+invoked as part of the definition of a keyboard macro.  For example, when used
+in a keyboard macro, a command that @f[message]'s useless user confirmation
+will slow down the repeated invocations of @hid[Last Keyboard Macro] because
+the command will pause on each execution to make sure the user sees the
+message.  This can be eliminated with the use of @f[interactive].  As another
+example, some commands conditionally signal an editor-error versus simply
+beeping the device depending on whether it executes on behalf of the user or a
+keyboard macro.
+
+@defun[fun {interactive}]
+This returns @true when the user invoked the command directly.
+@enddefun
+
+
+@section(Command Types)
+@index(Command types)
+@label(command-types)
+In many editors the behavior of a command depends on the kind of command
+invoked before it.  @hemlock provides a mechanism to support this known as
+@i(command type).
+
+@defun[fun {last-command-type}]
+This returns the command type of the last command invoked.  If this is set with
+@f[setf], the supplied value becomes the value of @f[last-command-type] until
+the next command completes.  If the previous command did not set
+@f[last-command-type], then its value is @nil.  Normally a command type is a
+keyword.  The command type is not cleared after a command is invoked due to a
+transparent key binding.
+@enddefun
+
+
+@section(Command Arguments)
+@label[invoking-commands-as-functions]
+There are three ways in which a command may be invoked: It may be bound to a
+key which has been typed, it may be invoked as an extended command, or it may
+be called as a Lisp function.  Ideally commands should be written in such a way
+that they will behave sensibly no matter which way they are invoked.  The
+functions which implement commands must obey certain conventions about argument
+passing if the command is to function properly.
+
+
+@subsection(The Prefix Argument)
+@index(Prefix arguments)
+Whenever a command is invoked it is passed as its first argument what
+is known as the @i[prefix argument].  The prefix argument is always
+either an integer or @nil.  When a command uses this value it is
+usually as a repeat count, or some conceptually similar function.
+
+@defun[fun {prefix-argument}]
+This function returns the current value of the prefix argument.  When
+set with @f[setf], the new value becomes the prefix argument for the
+next command.
+@enddefun
+
+If the prefix argument is not set by the previous command then the
+prefix argument for a command is @nil.  The prefix argument is not cleared
+after a command is invoked due to a transparent key binding.
+
+
+@subsection(Lisp Arguments)
+It is often desirable to call commands from Lisp code, in which case
+arguments which would otherwise be prompted for are passed as optional
+arguments following the prefix argument.  A command should prompt for
+any arguments not supplied.
+
+
+@section(Recursive Edits)
+@index(Recursive edits)
+@defmac[fun {use-buffer}, args {@i[buffer] @mstar<@i[form]>}]
+The effect of this is similar to setting the current-buffer to @i[buffer]
+during the evaluation of @i[forms].  There are restrictions placed on what the
+code can expect about its environment.  In particular, the value of any global
+binding of a @hemlock variable which is also a mode local variable of some mode
+is ill-defined; if the variable has a global binding it will be bound, but the
+value may not be the global value.  It is also impossible to nest
+@f[use-buffer]'s in different buffers.  The reason for using @f[use-buffer] is
+that it may be significantly faster than changing @f[current-buffer] to
+@i[buffer] and back.
+@enddefmac
+
+@defun[fun {recursive-edit}, args {@optional @i[handle-abort]}]
+@defhvar1[var {Enter Recursive Edit Hook}]
+@index[aborting]
+@f[recursive-edit] invokes the command interpreter.  The command interpreter
+will read from the keyboard and invoke commands until it is terminated with
+either @f[exit-recursive-edit] or @f[abort-recursive-edit].
+
+Normally, an editor-error or @bf[C-g] aborts the command in progress and
+returns control to the top-level command loop.  If @f[recursive-edit] is used
+with @i[handle-abort] true, then @f[editor-error] or @bf[C-g] will only abort
+back to the recursive command loop.
+
+Before the command interpreter is entered the hook
+@hid[Enter Recursive Edit Hook] is invoked.
+@enddefun
+
+@defun[fun {in-recursive-edit}]
+This returns whether the calling point is dynamically within a recursive edit
+context.
+@enddefun
+
+@defun[fun {exit-recursive-edit}, args {@optional @i[values-list]}]
+@defhvar1[var {Exit Recursive Edit Hook}]
+@f[exit-recursive-edit] exits a recursive edit returning as multiple values
+each element of @i[values-list], which defaults to @nil.  This invokes
+@hid[Exit Recursive Edit Hook] after exiting the command interpreter.  If no
+recursive edit is in progress, then this signals an error.
+@enddefun
+
+@defun[fun {abort-recursive-edit}, args {@rest @i[args]}]
+@defhvar1[var {Abort Recursive Edit Hook}]
+@f[abort-recursive-edit] terminates a recursive edit by applying
+@funref[editor-error] to @i[args] after exiting the command interpreter.  This
+invokes @hid[Abort Recursive Edit Hook] with @i[args] before aborting the
+recursive edit .  If no recursive edit is in progress, then this signals an
+error.
+@enddefun
+
+
+
+@Chapter(Modes)
+@label[modes]
+@index (Modes)
+A mode is a collection of @hemlock values which may be present in the current
+environment @w<(page @pageref(current-environment))> depending on the editing
+task at hand.  Examples of typical modes are @hid[Lisp], for editing Lisp code,
+and @hid[Echo Area], for prompting in the echo area.
+
+
+@section(Mode Hooks)
+  When a mode is added to or removed from a buffer, its @i[mode hook]
+is invoked.  The hook functions take two arguments, the buffer
+involved and @true if the mode is being added or @nil if it is being
+removed. 
+
+Mode hooks are typically used to make a mode do something additional to
+what it usually does.  One might, for example, make a text mode hook
+that turned on auto-fill mode when you entered.
+
+
+@section(Major and Minor Modes)
+There are two kinds of modes, @i[major] modes and @i[minor] modes.  A buffer
+always has exactly one major mode, but it may have any number of minor modes.
+Major modes may have mode character attributes while minor modes may not.
+
+A major mode is usually used to change the environment in some major way, such
+as to install special commands for editing some language.  Minor modes
+generally change some small attribute of the environment, such as whether lines
+are automatically broken when they get too long.  A minor mode should work
+regardless of what major mode and minor modes are in effect.
+
+@defhvar[var {Default Modes}, val {("Fundamental" "Save")}]
+This variable contains a list of mode names which are instantiated in a
+buffer when no other information is available.
+@enddefhvar
+
+@defvar[var {mode-names}]
+Holds a string-table of the names of all the modes.
+@enddefvar
+
+@defcom[com "Illegal"]
+This is a useful command to bind in modes that wish to shadow global bindings
+by making them effectively illegal.  Also, although less likely, minor modes
+may shadow major mode bindings with this.  This command calls @f[editor-error].
+@enddefcom
+
+
+@section(Mode Functions)
+
+@defun[fun {defmode}, args {@i[name]},
+        keys {[setup-function][cleanup-function][major-p]},
+        morekeys {[precedence][transparent-p][documentation]}]
+This function defines a new mode named @i[name], and enters it in
+@varref[mode-names].  If @i[major-p] is supplied and is not @nil
+then the mode is a major mode; otherwise it is a minor mode.
+
+@i[Setup-function] and @i[cleanup-function] are functions which are
+invoked with the buffer affected, after the mode is turned on, and
+before it is turned off, respectively.  These functions typically are
+used to make buffer-local key or variable bindings and to remove them
+when the mode is turned off.
+
+@i[Precedence] is only meaningful for a minor mode.  The precedence of a
+minor mode determines the order in which it in a buffer's list of modes.
+When searching for values in the current environment, minor modes are
+searched in order, so the precedence of a minor mode determines which value
+is found when there are several definitions.
+
+@i[Transparent-p] determines whether key bindings local to the defined mode
+are transparent.  Transparent key bindings are invoked in addition to the
+first normal key binding found rather than shadowing less local key bindings.
+
+@i[Documentation] is some introductory text about the mode.  Commands such as
+@hid[Describe Mode] use this.
+@enddefun
+
+@defun[fun {mode-documentation}, args {@i[name]}]
+This function returns the documentation for the mode named @i[name].
+@enddefun
+
+@defun[fun {buffer-major-mode}, args {@i[buffer]}]
+@defhvar1[var {Buffer Major Mode Hook}]
+@f[buffer-major-mode] returns the name of @i[buffer]'s major mode.
+The major mode may be changed with @f[setf]; then
+ @hid[Buffer Major Mode Hook] is invoked with
+@i[buffer] and the new mode.
+@enddefun
+
+@defun[fun {buffer-minor-mode}, args {@i[buffer] @i[name]}]
+@defhvar1[var {Buffer Minor Mode Hook}]
+@f[buffer-minor-mode] returns @true if the minor mode @i[name] is active
+in @i[buffer], @nil otherwise.  A minor mode may be turned on or off
+by using @f[setf]; then @hid[Buffer Minor Mode Hook] is
+invoked with @i[buffer], @i[name] and the new value.
+@enddefun
+
+@defun[fun {mode-variables}, args {@i[name]}]
+Returns the string-table of mode local variables.
+@enddefun
+
+@defun[fun {mode-major-p}, args {@i[name]}]
+Returns @true if @i[name] is the name of a major mode, or @nil if
+it is the name of a minor mode.  It is an error for @i[name] not to be
+the name of a mode.
+@enddefun
+
+
+
+@chapter(Character Attributes)
+@label(character-attributes)
+@index(Character attributes)
+@index(Syntax tables)
+
+@section(Introduction)
+Character attributes provide a global database of information about characters.
+This facility is similar to, but more general than, the @i[syntax tables] of
+other editors such as @f[EMACS].  For example, you should use character
+attributes for commands that need information regarding whether a character is
+@i[whitespace] or not.  Use character attributes for these reasons:
+@begin(enumerate)
+If this information is all in one place, then it is easy the change the
+behavior of the editor by changing the syntax table, much easier than it would
+be if character constants were wired into commands.
+
+This centralization of information avoids needless duplication of effort.
+
+The syntax table primitives are probably faster than anything that can be
+written above the primitive level.
+@end(enumerate)
+
+Note that an essential part of the character attribute scheme is that
+@i[character attributes are global and are there for the user to change.]
+Information about characters which is internal to some set of commands (and
+which the user should not know about) should not be maintained as a character
+attribute.  For such uses various character searching abilities are provided by
+the function @funref[find-pattern].
+
+@defcon[var {syntax-char-code-limit}]
+The exclusive upper bound on character codes which are significant in
+the character attribute functions.  Font and bits are always ignored.
+@enddefcon
+
+
+@section(Character Attribute Names)
+
+As for @hemlock variables, character attributes have a user visible
+string name, but are referred to in Lisp code as a symbol.  The string
+name, which is typically composed of capitalized words separated by
+spaces, is translated into a keyword by replacing all spaces with
+hyphens and interning this string in the keyword package.  The
+attribute named @hid[Ada Syntax] would thus become @kwd[ada-syntax].
+
+@defvar[var {character-attribute-names}]
+Whenever a character attribute is defined, its name is entered in
+this string table (page @pageref[string-tables]), with the
+corresponding keyword as the value.
+@enddefvar
+
+
+@section(Character Attribute Functions)
+
+@defun[fun {defattribute}, args 
+	{@i[name] @i[documentation] @optional @i[type] @i[initial-value]}]
+ This function defines a new character attribute with @i[name], a
+simple-string.  Character attribute operations take attribute arguments as a
+keyword whose name is @i[name] uppercased with spaces replaced by hyphens.
+
+@i[Documentation] describes the uses of the character attribute.
+
+@i[Type], which defaults to @w<@f[(mod 2)]>, specifies what type the values of
+the character attribute are.  Values of a character attribute may be of any
+type which may be specified to @f[make-array].  @i[Initial-value] (default
+@f[0]) is the value which all characters will initially have for this
+attribute.
+@enddefun
+
+@defun[fun {character-attribute-name}, args {@i[attribute]}]
+@defun1[fun {character-attribute-documentation}, args {@i[attribute]}]
+These functions return the name or documentation for @i[attribute].
+@enddefun
+
+@defun[fun {character-attribute}, args	{@i[attribute] @i[character]}]
+@defhvar1[var {Character Attribute Hook}]
+@f[character-attribute] returns the value of @i[attribute] for @i[character].
+This signals an error if @i[attribute] is undefined.
+
+@f[setf] will set a character's attributes.  This @f[setf] method invokes the
+functions in @hid[Character Attribute Hook] on the attribute and character
+before it makes the change.
+
+If @i[character] is @nil, then the value of the attribute for the beginning or
+end of the buffer can be accessed or set.  The buffer beginning and end thus
+become a sort of fictitious character, which simplifies the use of character
+attributes in many cases.
+@enddefun
+
+@defun[fun {character-attribute-p}, args {@i[symbol]}]
+This function returns @true if @i[symbol] is the name of a character attribute,
+@nil otherwise.
+@enddefun
+
+@defun[fun {shadow-attribute}, args 
+{@i[attribute] @i[character] @i[value] @i[mode]}]
+@defhvar1[var {Shadow Attribute Hook}]
+This function establishes @i[value] as the value of @i[character]'s
+@i[attribute] attribute when in the mode @i[mode].  @i[Mode] must be the name
+of a major mode.  @hid[Shadow Attribute Hook] is invoked with the same
+arguments when this function is called.  If the value for an attribute is set
+while the value is shadowed, then only the shadowed value is affected, not the
+global one.
+@enddefun
+
+@defun[fun {unshadow-attribute}, args {@i[attribute] @i[character] @i[mode]}]
+@defhvar1[var {Unshadow Attribute Hook}]
+Make the value of @i[attribute] for @i[character] no longer be shadowed in
+@i[mode].  @hid[Unshadow Attribute Hook] is invoked with the same arguments
+when this function is called.
+@enddefun
+
+@defun[fun {find-attribute},
+	args {@i[mark] @i[attribute] @optional @i[test]}]
+@defun1[fun {reverse-find-attribute},
+	args {@i[mark] @i[attribute] @optional @i[test]}]
+ These functions find the next (or previous) character with some value for the
+character attribute @i[attribute] starting at @i[mark].  They pass @i[Test] one
+argument, the value of @i[attribute] for the character tested.  If the test
+succeeds, then these routines modify @i[mark] to point before (after for
+@f[reverse-find-attribute]) the character which satisfied the test.  If no
+characters satisfy the test, then these return @nil, and @i[mark] remains
+unmodified.  @i[Test] defaults to @f[not zerop].  There is no guarantee that
+the test is applied in any particular fashion, so it should have no side
+effects and depend only on its argument.
+@enddefun
+
+
+@section(Character Attribute Hooks)
+
+It is often useful to use the character attribute mechanism as an abstract
+interface to other information about characters which in fact is stored
+elsewhere.  For example, some implementation of @hemlock might decide to define
+a @hid[Print Representation] attribute which controls how a character is
+displayed on the screen.
+
+To make this easy to do, each attribute has a list of hook functions
+which are invoked with the attribute, character and new value whenever
+the current value changes for any reason.
+
+@defun[fun {character-attribute-hooks}, args {@i[attribute]}]
+Return the current hook list for @i[attribute].  This may be set with
+@f[setf].  The @f[add-hook] and @macref[remove-hook] macros should
+be used to manipulate these lists.
+@enddefun
+
+
+@section (System Defined Character Attributes)
+@label(sys-def-chars)
+These are predefined in @hemlock:
+@begin[description]
+@hid[Whitespace]@\
+A value of @f[1] indicates the character is whitespace.
+
+@hid[Word Delimiter]@\
+A value of @f[1] indicates the character separates words (see section
+@ref[text-functions]).
+
+@hid[Digit]@\
+A value of @f[1] indicates the character is a base ten digit.  This may be
+shadowed in modes or buffers to mean something else.
+
+@hid[Space]@\
+This is like @hid[Whitespace], but it should not include @binding[Newline].
+@hemlock uses this primarily for handling indentation on a line.
+
+@hid[Sentence Terminator]@\
+A value of @f[1] indicates these characters terminate sentences (see section
+@ref[text-functions]).
+
+@hid[Sentence Closing Char]@\
+A value of @f[1] indicates these delimiting characters, such as @binding["]
+or @binding[)], may follow a @hid[Sentence Terminator] (see section
+@ref[text-functions]).
+
+@hid[Paragraph Delimiter]@\
+A value of @f[1] indicates these characters delimit paragraphs when they begin
+a line (see section @ref[text-functions]).
+
+@hid[Page Delimiter]@\
+A value of @f[1] indicates this character separates logical pages (see section
+@ref[logical-pages]) when it begins a line.
+
+@hid[Scribe Syntax]@\
+This uses the following symbol values:
+@begin[multiple]
+@begin[description]
+@nil@\These characters have no interesting properties.
+
+@kwd[escape]@\This is @binding[@@] for the Scribe formatting language.
+
+@kwd[open-paren]@\These characters begin delimited text.
+
+@kwd[close-paren]@\These characters end delimited text.
+
+@kwd[space]@\These characters can terminate the name of a formatting command.
+
+@kwd[newline]@\These characters can terminate the name of a formatting command.
+@end[description]
+@end[multiple]
+
+
+@hid[Lisp Syntax]@\
+This uses symbol values from the following:
+@begin[multiple]
+@begin[description]
+@nil@\These characters have no interesting properties.
+
+@kwd[space]@\These characters act like whitespace and should not include
+@binding[Newline].
+
+@kwd[newline]@\This is the @binding[Newline] character.
+
+@kwd[open-paren]@\This is @binding[(] character.
+
+@kwd[close-paren]@\This is @binding[)] character.
+
+@kwd[prefix]@\This is a character that is a part of any form it precedes @dash
+for example, the single quote, @binding['].
+
+@kwd[string-quote]@\This is the character that quotes a string literal,
+@binding["].@comment["]
+
+@kwd[char-quote]@\This is the character that escapes a single character,
+@binding[\].
+
+@kwd[comment]@\This is the character that makes a comment with the rest of the
+line, @binding[;].
+
+@kwd[constituent]@\These characters are constitute symbol names.
+@end[description]
+@end[multiple]
+
+@end[description]
+
+
+
+@chapter (Controlling the Display)
+@section (Windows)
+@tag[windows]
+@index(Windows)
+@index(modelines)
+
+A window is a mechanism for displaying part of a buffer on some physical
+device.  A window is a way to view a buffer but is not synonymous with one; a
+buffer may be viewed in any number of windows.  A window may have a
+@i[modeline] which is a line of text displayed across the bottom of a window to
+indicate status information, typically related to the buffer displayed.
+
+
+@section (The Current Window)
+@index (Current window)
+@defun[fun {current-window}, args {}]
+@defhvar1[var {Set Window Hook}]
+@f[current-window] returns the window in which the cursor is currently
+displayed.  The cursor always tracks the buffer-point of the corresponding
+buffer.  If the point is moved to a position which would be off the screen the
+recentering process is invoked.  Recentering shifts the starting point of the
+window so that the point is once again displayed.  The current window may be
+changed with @f[setf].  Before the current window is changed, the hook @hid[Set
+Window Hook] is invoked with the new value.
+@enddefun
+
+@defvar[var {window-list}]
+Holds a list of all the window objects made with @funref[make-window].
+@enddefvar
+
+
+@section(Window Functions)
+
+@defun[fun {make-window}, args {@i[mark]},
+	keys {[modelinep][window][ask-user]},
+	morekeys {[x][y][width][height]}]
+@defhvar1[var {Default Window Width}]
+@defhvar1[var {Default Window Height}]
+@defhvar1[var {Make Window Hook}]
+@f[make-window] returns a window displaying text starting at @i[mark], which
+must point into a buffer.  If it could not make a window on the device, it
+returns nil.  The default action is to split the current window to make room
+for the new window.
+
+@i[Modelinep] specifies whether the window should display buffer modelines.
+
+Window is a X window to be used with the Hemlock window.
+
+@i[Window] is a device dependent window to be used with the Hemlock window.
+The device may not support this argument.  @i[Window] becomes the parent window
+for a new group of windows that behave in a stack orientation as windows do on
+the terminal.
+
+If @i[ask-user] is non-@nil, @hemlock prompts the user for the missing
+dimensions (@i[x], @i[y], @i[width], and @i[height]) to make a new group of
+windows, as with the @i[window] argument.  The device may not support this
+argument.  Non-null values other than @f[t] may have device dependent meanings.
+@i[X] and @i[y] are in pixel units, but @i[width] and @i[height] are characters
+units.  @hid[Default Window Width] and @hid[Default Window Height] are the
+default values for the @i[width] and @i[height] arguments.
+
+This invokes @hid[Make Window Hook] with the new window.
+@enddefun
+
+@defun[fun {windowp}, args {@i[window]}]
+This function returns @true if @i[window] is a @f[window] object, otherwise
+@nil.
+@enddefun
+
+@defun[fun {delete-window}, args {@i[window]}]
+@defhvar1[var {Delete Window Hook}]
+@f[delete-window] makes @i[window] go away, first invoking @hid[Delete Window
+Hook] with @i[window].
+@enddefun
+
+@defun[fun {window-buffer}, args {@i[window]}]
+@defhvar1[var {Window Buffer Hook}]
+@f[window-buffer] returns the buffer from which the window displays
+text.  This may be changed with @f[setf], in which case the hook
+@hid[Window Buffer Hook] is invoked beforehand with the window and the
+new buffer.
+@enddefun
+
+@defun[fun {window-display-start}, args {@i[window]}]
+@defun1[fun {window-display-end}, args {@i[window]}] 
+@f[window-display-start] returns the mark that points before the first
+character displayed in @i[window].  Note that if @i[window] is the current
+window, then moving the start may not prove much, since recentering may move it
+back to approximately where it was originally.
+
+@f[window-display-end] is similar, but points after the last character
+displayed.  Moving the end is meaningless, since redisplay always moves it to
+after the last character.
+@enddefun
+
+@defun[fun {window-point}, args {@i[window]}]
+This function returns as a mark the position in the buffer where the cursor is
+displayed.  This may be set with @f[setf].  If @i[window] is the current
+window, then setting the point will have little effect; it is forced to track
+the buffer point.  When the window is not current, the window point is the
+position that the buffer point will be moved to when the window becomes
+current.
+@enddefun
+
+@defun[fun {center-window}, args {@i[window] @i[mark]}]
+This function attempts to adjust window's display start so the that @i[mark] is
+vertically centered within the window.
+@enddefun
+
+@defun[fun {scroll-window}, args {@i[window] @i[n]}]
+This function scrolls the window down @i[n] display lines; if @i[n] is negative
+scroll up.  Leave the cursor at the same text position unless we scroll it off
+the screen, in which case the cursor is moved to the end of the window closest
+to its old position.
+@enddefun
+
+@defun[fun {displayed-p}, args {@i[mark] @i[window]}]
+Returns @true if either the character before or the character after @i[mark]
+is being displayed in @i[window], or @nil otherwise.  
+@enddefun
+
+@defun[fun {window-height}, args {@i[window]}]
+@defun1[fun {window-width}, args {@i[window]}]
+Height or width of the area of the window used for displaying the
+buffer, in character positions.  These values may be changed with
+@f[setf], but the setting attempt may fail, in which case nothing is done.
+@enddefun
+
+@defun[fun {next-window}, args {@i[window]}]
+@defun1[fun {previous-window}, args {@i[window]}]
+Return the next or previous window of @i[window].  The exact meaning of next
+and previous depends on the device displaying the window.  It should be
+possible to cycle through all the windows displayed on a device using either
+next or previous (implying that these functions wrap around.)
+@enddefun
+
+
+@section(Cursor Positions)
+@index(Cursor positions)
+A cursor position is an absolute position within a window's coordinate
+system.  The origin is in the upper-left-hand corner and the unit
+is character positions.
+
+@defun[fun {mark-to-cursorpos}, args {@i[mark] @i[window]}]
+Returns as multiple values the @f[X] and @f[Y] position on which
+@i[mark] is being displayed in @i[window], or @nil if it is not within the
+bounds displayed.
+@enddefun
+
+@defun[fun {cursorpos-to-mark}, args {@i[X] @i[Y] @i[window]}]
+Returns as a mark the text position which corresponds to the given
+(@i[X], @i[Y]) position within window, or @nil if that
+position does not correspond to any text within @i[window].
+@enddefun
+
+@defun[fun {last-key-event-cursorpos}]
+Interprets mouse input.  It returns as multiple values the (@i[X], @i[Y])
+position and the window where the pointing device was the last time some key
+event happened.  If the information is unavailable, this returns @nil.
+@enddefun
+
+@defun[fun {mark-column}, args {@i[mark]}]
+This function returns the @i[X] position at which @i[mark] would be displayed,
+supposing its line was displayed on an infinitely wide screen.  This takes into
+consideration strange characters such as tabs.
+@enddefun
+
+@defun[fun {move-to-column}, args {@i[mark] @i[column] @optional @i[line]}]
+This function is analogous to @funref[move-to-position], except that
+it moves @i[mark] to the position on @i[line] which corresponds to the
+specified @i[column].  @i[Line] defaults to the line that @i[mark] is
+currently on.  If the line would not reach to the specified column,
+then @nil is returned and @i[mark] is not modified.  Note that since a
+character may be displayed on more than one column on the screen,
+several different values of @i[column] may cause @i[mark] to be moved
+to the same position.
+@enddefun
+
+@defun[fun {show-mark}, args {@i[mark] @i[window] @i[time]}]
+This function highlights the position of @i[mark] within @i[window] for
+@i[time] seconds, possibly by moving the cursor there.  The wait may be aborted
+if there is pending input.  If @i[mark] is positioned outside the text
+displayed by @i[window], then this returns @nil, otherwise @true.
+@enddefun
+
+
+@section(Redisplay)
+Redisplay is the process by which the editor translates changes in the internal
+representation of text into changes on the screen.  Ideally this process finds
+the minimal transformation of the screen that brings it into correspondence
+with the text, in order to maximize the speed of redisplay.
+
+@defun[fun {redisplay}]
+@defhvar1[var "Redisplay Hook"]
+@f[redisplay] invokes the redisplay process, and the command interpreter
+typically causes this after the completion of each command.  The redisplay
+process repeatedly checks for input, and if any is detected, redisplay aborts.
+This function invokes the functions in @hid[Redisplay Hook] on the current
+window after completely preparing for but not executing redisplay.  After
+invoking the hook, it recomputes the redisplay again and then finally executes
+it on the current window.
+@enddefun
+
+@defun[fun {redisplay-all}]
+This causes all editor windows to be completely redisplayed.
+@enddefun
+
+@defun[fun {editor-finish-output}, args {@i[window]}]
+This makes sure the editor is synchronized with respect to redisplay output to
+@i[window].  This may do nothing on some devices.
+@enddefun
+
+
+
+@chapter(Logical Key-Events)
+@label[logical-key-events]
+@index[Logical key-events]
+
+
+@section[Introduction]
+Some primitives such as @funref[prompt-for-key] and commands such as EMACS
+query replace read key-events directly from the keyboard instead of using the
+command interpreter.  To encourage consistency between these commands and to
+make them portable and easy to customize, there is a mechanism for defining
+@i[logical key-events].
+
+A logical key-event is a keyword which stands for some set of key-events.  The
+system globally interprets these key-events as indicators a particular action.
+For example, the @kwd[help] logical key-event represents the set of key-events
+that request help in a given @hemlock implementation.  This mapping is a
+many-to-many mapping, not one-to-one, so a given logical key-event may have
+multiple corresponding actual key-events.  Also, any key-event may represent
+different logical key-events.
+
+
+@section[Logical Key-Event Functions]
+
+@defvar[var {logical-key-event-names}]
+This variable holds a string-table mapping all logical key-event names to the
+keyword identifying the logical key-event.
+@enddefvar
+
+@defun[fun {define-logical-key-event}, args {@i[string-name] @i[documentation]}]
+ This function defines a new logical key-event with name @i[string-name], a
+simple-string.  Logical key-event operations take logical key-events arguments
+as a keyword whose name is @i[string-name] uppercased with spaces replaced by
+hyphens.
+
+@i[Documentation] describes the action indicated by the logical key-event.
+@enddefun
+
+@defun[fun {logical-key-event-key-events}, args {@i[keyword]}]
+This function returns the list of key-events representing the logical key-event
+@i[keyword].
+@enddefun
+
+@defun[fun {logical-key-event-name}, args {@i[keyword]}]
+@defun1[fun {logical-key-event-documentation}, args {@i[keyword]}]
+These functions return the string name and documentation given to
+@f[define-logical-key-event] for logical key-event @i[keyword].
+@enddefun
+
+@defun[fun {logical-key-event-p}, args {@i[key-event] @i[keyword]}]
+This function returns @f[t] if @i[key-event] is the logical key-event
+@i[keyword].  This is @f[setf]'able establishing or disestablishing key-events
+as particular logical key-events.  It is a error for @i[keyword] to be an
+undefined logical key-event.
+@enddefun
+
+
+@section[System Defined Logical Key-Events]
+There are many default logical key-events, some of which are used by functions
+documented in this manual.  If a command wants to read a single key-event
+command that fits one of these descriptions then the key-event read should be
+compared to the corresponding logical key-event instead of explicitly
+mentioning the particular key-event in the code.  In many cases you can use the
+@macref[command-case] macro.  It makes logical key-events easy to use and takes
+care of prompting and displaying help messages.
+
+@begin[description]
+@kwd[yes]@\
+ Indicates the prompter should take the action under consideration.
+
+@kwd[no]@\
+ Indicates the prompter should NOT take the action under consideration.
+
+@kwd[do-all]@\
+ Indicates the prompter should repeat the action under consideration as many
+times as possible.
+
+@kwd[do-once]@\
+ Indicates the prompter should execute the action under consideration once and
+then exit.
+
+@kwd[exit]@\
+ Indicates the prompter should terminate its activity in a normal fashion.
+
+@kwd[abort]@\
+ Indicates the prompter should terminate its activity without performing any
+closing actions of convenience, for example.
+
+@kwd[keep]@\
+ Indicates the prompter should preserve something.
+
+@kwd[help]@\
+ Indicates the prompter should display some help information.
+
+@kwd[confirm]@\
+ Indicates the prompter should take any input provided or use the default if
+the user entered nothing.
+
+@kwd[quote]@\
+ Indicates the prompter should take the following key-event as itself without
+any sort of command interpretation.
+
+@kwd[recursive-edit]@\
+ Indicates the prompter should enter a recursive edit in the current context.
+
+@kwd[cancel]@\
+ Indicates the prompter should cancel the effect of a previous key-event input.
+
+@kwd[forward-search]@\
+ Indicates the prompter should search forward in the current context.
+
+@kwd[backward-search]@\
+ Indicates the prompter should search backward in the current context.
+@end[description]
+
+@blankspace(1 line)
+Define a new logical key-event whenever:
+@begin[enumerate]
+The key-event concerned represents a general class of actions, and
+several commands may want to take a similar action of this type.
+
+The exact key-event a command implementor chooses may generate violent taste
+disputes among users, and then the users can trivially change the command in
+their init files.
+
+You are using @f[command-case] which prevents implementors from specifying
+non-standard characters for dispatching in otherwise possibly portable code, 
+and you can define and set the logical key-event in a site dependent file where
+you can mention implementation dependent characters.
+@end[enumerate]
+
+
+
+@chapter(The Echo Area)
+
+@hemlock provides a number of facilities for displaying information and
+prompting the user for it.  Most of these work through a small window displayed
+at the bottom of the screen.  This is called the echo area and is supported by
+a buffer and a window.  This buffer's modeline (see section @ref[modelines]) is
+referred to as the status line, which, unlike other buffers' modelines, is used
+to show general status about the editor, Lisp, or world.
+
+@defhvar[var {Default Status Line Fields}]
+This is the initial list of modeline-field objects stored in the echo area
+buffer.
+@enddefhvar
+
+@defhvar[var "Echo Area Height", val {3}]
+This variable determines the initial height in lines of the echo area window. 
+@enddefhvar
+
+
+@section(Echo Area Functions)
+It is considered poor taste to perform text operations on the echo area buffer
+to display messages; the @f[message] function should be used instead.  A
+command must use this function or set @funref[buffer-modified] for the
+@hid[Echo Area] buffer to @nil to cause @hemlock to leave text in the echo area
+after the command's execution.
+
+@defun[fun {clear-echo-area}]
+Clears the echo area.
+@enddefun
+
+@defun[fun {message}, args {@i[control-string] @rest @i[format-arguments]}]
+@defun1[fun {loud-message}, args {@i[control-string] @rest @i[format-arguments]}]
+@defhvar1[var {Message Pause}, val {0.5}]
+Displays a message in the echo area.  The message is always displayed on a
+fresh line.  @f[message] pauses for @hid[Message Pause] seconds before
+returning to assure that messages are not displayed too briefly to be seen.
+Because of this, @f[message] is the best way to display text in the echo area.
+
+@f[loud-message] is like @f[message], but it first clears the echo area and
+beeps.
+@enddefun
+
+@defvar[var {echo-area-window}]
+@defvar1[var {echo-area-buffer}]
+@f[echo-area-buffer] contains the buffer object for the echo area, which is
+named @hid[Echo Area].  This buffer is usually in @hid[Echo Area] mode.
+@f[echo-area-window] contains a window displaying @f[echo-area-buffer].  Its
+modeline is the status line, see the beginning of this chapter.
+@enddefvar
+
+@defvar[var {echo-area-stream}]
+@index (Echo area)
+This is a buffered @hemlock output stream
+(@pageref[make-hemlock-output-stream-fun]) which inserts text written to it at
+the point of the echo area buffer.  Since this stream is buffered a
+@f[force-output] must be done when output is complete to assure that it is
+displayed.
+@enddefvar
+
+
+@section(Prompting Functions)
+@index(Prompting functions)
+Most of the prompting functions accept the following keyword arguments:
+@begin(description)
+@kwd[must-exist] @\If @kwd[must-exist] has a non-@nil value then the
+user is prompted until a valid response is obtained.  If
+@kwd[must-exist] is @nil then return as a string whatever is input.
+The default is @true.
+
+@kwd[default] @\If null input is given when the user is prompted 
+then this value is returned.  If no default is given then
+some input must be given before anything interesting will happen.
+
+@kwd[default-string] @\If a @kwd[default] is given then this is a
+string to be printed to indicate what the default is.  The default is
+some representation of the value for @kwd[default], for example for a
+buffer it is the name of the buffer.
+
+@kwd[prompt] @\This is the prompt string to display.
+
+@kwd[help] @\@multiple{
+This is similar to @kwd[prompt], except that it is displayed when
+the help command is typed during input.  @comment{If there is some known number
+of options as in keyword parses, then they may be displayed, depending
+on the setting of @hvarref[Help Show Options].}
+
+This may also be a function.  When called with no arguments, it should either
+return a string which is the help text or perform some action to help the user,
+returning @Nil.}
+@end(description)
+
+@defun[fun {prompt-for-buffer}, keys {[prompt][help][must-exist][default]},
+	morekeys {[default-string]}] 
+Prompts with completion for a buffer name and returns the corresponding buffer.
+If @i[must-exist] is @nil, then it returns the input string if it is not a
+buffer name.  This refuses to accept the empty string as input when
+@kwd[default] and @kwd[default-string] are @nil.  @kwd[default-string] may be
+used to supply a default buffer name when @kwd[default] is @nil, but when
+@kwd[must-exist] is non-@nil, it must name an already existing buffer.
+@enddefun
+
+@defmac[fun {command-case}, Args {(@mstar<@i[key] @i[value]>) @Mstar<(@Mgroup"(@MSTAR'@i[tag]') @MOR @i[tag]" @i[help] @MSTAR'@i[form]')>}] 
+ This macro is analogous to the Common Lisp @f[case] macro.  Commands such as
+@hid[Query Replace] use this to get a key-event, translate it to a character,
+and then to dispatch on the character to some case.  In addition to character
+dispatching, this supports logical key-events @w<(page
+@pageref[logical-key-events])> by using the input key-event directly without
+translating it to a character.  Since the description of this macro is rather
+complex, first consider the following example:
+@lisp
+(defcommand "Save All Buffers" (p)
+  "Give the User a chance to save each modified buffer."
+  "Give the User a chance to save each modified buffer."
+  (dolist (b *buffer-list*)
+    (select-buffer-command () b)
+    (when (buffer-modified b)
+      (command-case (:prompt "Save this buffer: [Y] "
+		     :help "Save buffer, or do something else:")
+	((:yes :confirm)
+	 "Save this buffer and go on to the next."
+	 (save-file-command () b))
+	(:no "Skip saving this buffer, and go on to the next.")
+	(:recursive-edit
+	 "Go into a recursive edit in this buffer."
+	 (do-recursive-edit) (reprompt))
+	((:exit #\p) "Punt this silly loop."
+	 (return nil))))))
+@endlisp
+
+@f[command-case] prompts for a key-event and then executes the code in the
+first branch with a logical key-event or a character (called @i[tags]) matching
+the input.  Each character must be a standard-character, one that satisfies the
+Common Lisp @f[standard-char-p] predicate, and the dispatching mechanism
+compares the input key-event to any character tags by mapping the key-event to
+a character with @f[ext:key-event-char].  If the tag is a logical key-event,
+then the search for an appropriate case compares the key-event read with the
+tag using @f[logical-key-event-p].
+
+All uses of @f[command-case] have two default cases, @kwd[help] and
+@kwd[abort].  You can override these easily by specifying your own branches
+that include these logical key-event tags.  The @kwd[help] branch displays in a
+pop-up window the a description of the valid responses using the variously
+specified help strings.  The @kwd[abort] branch signals an editor-error.
+
+The @i[key]/@i[value] arguments control the prompting.  The following are valid
+values:
+@begin[description]
+@kwd[help]@\
+ The default @kwd[help] case displays this string in a pop-up window.  In
+addition it formats a description of the valid input including each case's
+@i[help] string.
+
+@kwd[prompt]@\
+ This is the prompt used when reading the key-event.
+
+@kwd[change-window]@\
+ If this is non-nil (the default), then the echo area window becomes the
+current window while the prompting mechanism reads a key-event.  Sometimes it
+is desirable to maintain the current window since it may be easier for users to
+answer the question if they can see where the current point is.
+
+@kwd[bind]@\
+ This specifies a variable to which the prompting mechanism binds the input
+key-event.  Any case may reference this variable.  If you wish to know what
+character corresponds to the key-event, use @f[ext:key-event-char].
+@end(description)
+
+Instead of specifying a tag or list of tags, you may use @true.  This becomes
+the default branch, and its forms execute if no other branch is taken,
+including the default @kwd[help] and @kwd[abort] cases.  This option has no
+@i[help] string, and the default @kwd[help] case does not describe the default
+branch.  Every @f[command-case] has a default branch; if none is specified, the
+macro includes one that @f[system:beep]'s and @f[reprompt]'s (see below).
+
+Within the body of @f[command-case], there is a defined @f[reprompt] macro.
+It causes the prompting mechanism and dispatching mechanism to immediately
+repeat without further execution in the current branch.
+@enddefmac
+
+
+@defun[fun {prompt-for-key-evnet}, keys {[prompt][change-window]}]
+This function prompts for a key-event returning immediately when the user types
+the next key-event.  @macref[command-case] is more useful for most purposes.
+When appropriate, use logical key-events @w<(page
+@pageref[logical-key-events])>.
+@enddefun
+
+@defun[fun {prompt-for-key}, keys {[prompt][help][must-exist][default]},
+	morekeys {[default-string]}]
+ This function prompts for a @i[key], a vector of key-events, suitable for
+passing to any of the functions that manipulate key bindings @w<(page
+@pageref[key-bindings])>.  If @i[must-exist] is true, then the key must be
+bound in the current environment, and the command currently bound is returned
+as the second value.
+@enddefun
+
+@defun[fun {prompt-for-file}, keys {[prompt][help][must-exist][default]},
+	morekeys {[default-string]}]
+ This function prompts for an acceptable filename in some system dependent
+fashion.  "Acceptable" means that it is a legal filename, and it exists if
+@i[must-exist] is non-@nil.  @f[prompt-for-file] returns a Common Lisp
+pathname.
+
+If the file exists as entered, then this returns it, otherwise it is merged
+with @i[default] as by @f[merge-pathnames].
+@enddefun
+
+@defun[fun {prompt-for-integer}, keys {[prompt][help][must-exist][default]},
+	morekeys {[default-string]}] 
+ This function prompts for a possibly signed integer.  If @i[must-exist] is
+@nil, then @f[prompt-for-integer] returns the input as a string if it is not a
+valid integer.
+@enddefun
+
+@defun[fun {prompt-for-keyword}, args {@i[string-tables]},
+	keys {[prompt][help][must-exist]},
+	morekeys {[default][default-string]}]
+ This function prompts for a keyword with completion, using the string tables
+in the list @i[string-tables].  If @I[must-exist] is non-@nil, then the result
+must be an unambiguous prefix of a string in one of the @i[string-tables], and
+the returns the complete string even if only a prefix of the full string was
+typed.  In addition, this returns the value of the corresponding entry in the
+string table as the second value.
+
+If @i[must-exist] is @nil, then this function returns the string exactly as
+entered.  The difference between @f[prompt-for-keyword] with @i[must-exist]
+@nil, and @f[prompt-for-string], is the user may complete the input using the
+@hid<Complete Parse> and @hid<Complete Field> commands.
+@enddefun
+
+@defun[fun {prompt-for-expression},
+	keys {[prompt][help][must-exist][default]},
+	morekeys {[default-string]}]
+ This function reads a Lisp expression.  If @i[must-exist] is @nil, and a read
+error occurs, then this returns the string typed.
+@enddefun
+
+@defun[fun {prompt-for-string}, keys 
+{[prompt][help][default][default-string]}]
+ This function prompts for a string; this cannot fail.
+@enddefun
+
+@defun[fun {prompt-for-variable}, keys {[prompt][help][must-exist][default]},
+	morekeys {[default-string]}]
+ This function prompts for a variable name.  If @i[must-exist] is non-@nil,
+then the string must be a variable @i[defined in the current environment], in
+which case the symbol name of the variable found is returned as the second
+value.
+@enddefun
+
+@defun[fun {prompt-for-y-or-n}, keys {[prompt][help][must-exist][default]},
+	morekeys {[default-string]}]
+ This prompts for @binding[y], @binding[Y], @binding[n], or @binding[N],
+returning @true or @nil without waiting for confirmation.  When the user types
+a confirmation key, this returns @i[default] if it is supplied.  If
+@i[must-exist] is @nil, this returns whatever key-event the user first types;
+however, if the user types one of the above key-events, this returns @true or
+@nil.  This is analogous to the Common Lisp function @f[y-or-n-p].
+@enddefun
+
+@defun[fun {prompt-for-yes-or-no}, keys {[prompt][help][must-exist][default]},
+	morekeys {[default-string]}]
+ This function is to @f[prompt-for-y-or-n] as @f[yes-or-no-p] is to
+@f[y-or-n-p].  "Yes" or "No" must be typed out in full and
+confirmation must be given.
+@enddefun
+
+
+@section(Control of Parsing Behavior)
+
+@defhvar[var {Beep On Ambiguity}, val {@true}]
+If this variable is true, then an attempt to complete a parse which is
+ambiguous will result in a "beep".
+@enddefhvar
+
+
+@begin(comment)
+@hemlock provides for limited control of parsing routine behaviour The
+character attribute @hid[Parse Field Separator] is a boolean attribute, a value
+of @f[1] indicating that the character is a field separator recognized by the
+@hid<Complete Field> command.
+@end(comment)
+
+@begin(comment)
+@defhvar[var {Help Show Options}]
+During a keyword or similar parse, typing the help command may cause a
+list of options to be displayed.  If displaying the help would take up
+more lines than the value of this variable then confirmation will be
+asked for before they will be displayed.
+@enddefhvar
+@end(comment)
+
+
+
+@section(Defining New Prompting Functions)
+Prompting functions are implemented as a recursive edit in the
+@hid[Echo Area] buffer.  Completion, help, and other parsing features
+are implemented by commands which are bound in @hid[Echo Area Mode].
+
+A prompting function passes information down into the recursive edit
+by binding a collection of special variables.
+
+@defvar[var {parse-verification-function}]
+The system binds this to a function that @comref[Confirm Parse] calls.  It does
+most of the work when parsing prompted input.  @comref[Confirm Parse] passes
+one argument, which is the string that was in @var<parse-input-region> when the
+user invokes the command.  The function should return a list of values which
+are to be the result of the recursive edit, or @nil indicating that the parse
+failed.  In order to return zero values, a non-@nil second value may be
+returned along with a @nil first value.
+@enddefvar
+
+@defvar[var {parse-string-tables}]
+This is the list of @f[string-table]s, if any, that pertain to this parse.
+@enddefvar
+
+@defvar[var {parse-value-must-exist}]
+This is bound to the value of the @kwd[must-exist] argument, and is
+referred to by the verification function, and possibly some of the
+commands.
+@enddefvar
+
+@defvar[var {parse-default}]
+When prompting the user, this is bound to a string representing the default
+object, the value supplied as the @kwd[default] argument.  @hid<Confirm Parse>
+supplies this to the parse verification function when the
+@var<parse-input-region> is empty.
+@enddefvar
+
+@defvar[var {parse-default-string}]
+When prompting the user, if @var[parse-default] is @nil, @hemlock displays this
+string as a representation of the default object; for example, when prompting
+for a buffer, this variable would be bound to the buffer name.
+@enddefvar
+
+@defvar[var {parse-type}]
+The kind of parse in progress, one of @kwd[file], @kwd[keyword] or
+@kwd[string].  This tells the completion commands how to do completion, with
+@kwd[string] disabling completion.
+@enddefvar
+
+@defvar[var {parse-prompt}]
+The prompt being used for the current parse.
+@enddefvar
+
+@defvar[var {parse-help}]
+The help string or function being used for the current parse.
+@enddefvar
+
+@defvar[var {parse-starting-mark}]
+This variable holds a mark in the @varref[echo-area-buffer] which
+is the position at which the parse began.
+@enddefvar
+
+@defvar[var {parse-input-region}]
+This variable holds a region with @var[parse-starting-mark] as its
+start and the end of the echo-area buffer as its end.  When
+@hid[Confirm Parse] is called, the text in this region is the text
+that will be parsed.
+@enddefvar
+
+
+@section(Some Echo Area Commands)
+
+These are some of the @hid[Echo Area] commands that coordinate with the
+prompting routines.  @Hemlock binds other commands specific to the @hid[Echo
+Area], but they are uninteresting to mention here, such as deleting to the
+beginning of the line or deleting backwards a word.
+
+@defcom[com {Help On Parse},
+	stuff (bound to @bf[Home, C-_] in @hid[Echo Area] mode)]
+Display the help text for the parse currently in progress.
+@enddefcom
+
+@defcom[com {Complete Keyword},
+	stuff (bound to @bf[Escape] in @hid[Echo Area] mode)] 
+This attempts to complete the current region as a keyword in
+@var[string-tables].  It signals an editor-error if the input is ambiguous
+or incorrect.
+@enddefcom
+
+@defcom[com {Complete Field},
+	stuff (bound to @bf[Space] in @hid[Echo Area] mode)]
+Similar to @hid[Complete Keyword], but only attempts to complete up to and
+including the first character in the keyword with a non-zero
+@kwd[parse-field-separator] attribute.  If
+there is no field separator then attempt to complete the entire keyword.
+If it is not a keyword parse then just self-insert.
+@enddefcom
+
+@defcom[com {Confirm Parse},
+	stuff (bound to @bf[Return] in @hid[Echo Area] mode)]
+If @var[string-tables] is non-@nil find the string in the region in
+them.  Call @var[parse-verification-function] with the current input.
+If it returns a non-@nil value then that is returned as the value of
+the parse.  A parse may return a @nil value if the verification
+function returns a non-@nil second value.
+@enddefcom
+
+
+
+@chapter (Files)
+@index (Files)
+This chapter discusses ways to read and write files at various levels @dash at
+marks, into regions, and into buffers.  This also treats automatic mechanisms
+that affect the state of buffers in which files are read.
+
+@section (File Options and Type Hooks)
+@index (File options)
+@index (Type hooks)
+@index (File type hooks)
+The user specifies file options with a special syntax on the first line of a
+file.  If the first line contains the string "@f[-*-]", then @hemlock
+interprets the text between the first such occurrence and the second, which
+must be contained in one line , as a list of @w{"@f<@i[option]: @i[value]>"}
+pairs separated by semicolons.  The following is a typical example:
+@begin[programexample]
+;;; -*- Mode: Lisp, Editor; Package: Hemlock -*-
+@end[programexample]
+See the @i[Hemlock User's Manual] for more details and predefined options.
+
+File type hooks are executed when @hemlock reads a file into a buffer based on
+the type of the pathname.  When the user specifies a @hid[Mode] file option
+that turns on a major mode, @hemlock ignores type hooks.  This mechanism is
+mostly used as a simple means for turning on some appropriate default major
+mode.
+
+@defmac[fun {define-file-option}, args
+{@i[name] (@i[buffer] @i[value]) @mstar<@i[declaration]> @mstar<@i[form]>}]
+This defines a new file option with the string name @i[name].  @i[Buffer] and
+@i[value] specify variable names for the buffer and the option value string,
+and @i[form]'s are evaluated with these bound.
+@enddefmac
+
+@defmac[fun {define-file-type-hook}, args 
+{@i[type-list] (@i[buffer] @i[type]) @mstar<@i[declaration]> @mstar<@i[form]>}]
+
+This defines some code that @f[process-file-options] (below) executes when the
+file options fail to set a major mode.  This associates each type, a
+@f[simple-string], in @i[type-list] with a routine that binds @i[buffer] to the
+buffer the file is in and @i[type] to the type of the pathname.
+@enddefmac
+
+@defun[fun {process-file-options}, args {@i[buffer] @optional @i[pathname]}]
+This checks for file options in buffer and invokes handlers if there are any.
+@i[Pathname] defaults to @i[buffer]'s pathname but may be @nil.  If there is no
+@hid[Mode] file option that specifies a major mode, and @i[pathname] has a
+type, then this tries to invoke the appropriate file type hook.
+@f[read-buffer-file] calls this.
+@enddefun
+
+
+@section (Pathnames and Buffers)
+There is no good way to uniquely identify buffer names and pathnames.  However,
+@hemlock has one way of mapping pathnames to buffer names that should be used
+for consistency among customizations and primitives.  Independent of this,
+@hemlock provides a means for consistently generating prompting defaults when
+asking the user for pathnames.
+
+@defun[fun {pathname-to-buffer-name}, args {@i[pathname]}]
+This function returns a string of the form "@f[file-namestring]
+@f[directory-namestring]".
+@enddefun
+
+@defhvar[var "Pathname Defaults", val {(pathname "gazonk.del")}]
+@defhvar1[var "Last Resort Pathname Defaults Function"]
+@defhvar1[var "Last Resort Pathname Defaults", val {(pathname "gazonk")}]
+These variables control the computation of default pathnames when needed for
+promting the user.  @hid[Pathname Defaults] is a @i[sticky] default.
+See the @i[Hemlock User's Manual] for more details.
+@enddefhvar
+
+@defun[fun {buffer-default-pathname}, args {@i[buffer]}]
+This returns @hid[Buffer Pathname] if it is bound.  If it is not bound, and
+@i[buffer]'s name is composed solely of alphnumeric characters, then return a
+pathname formed from @i[buffer]'s name.  If @i[buffer]'s name has other
+characters in it, then return the value of @hid[Last Resort Pathname Defaults
+Function] called on @i[buffer].
+@enddefun
+
+@section (File Groups)
+@index (File groups)
+File groups provide a simple way of collecting the files that compose a system
+and naming that collection.  @Hemlock supports commands for searching,
+replacing, and compiling groups.
+
+@defvar[var {active-file-group}]
+This is the list of files that constitute the currently selected file group.
+If this is @nil, then there is no current group.
+@enddefvar
+
+@defmac[fun {do-active-group}, args {@mstar<@i[form]>}]
+@defhvar1[var "Group Find File", val {nil}]
+@defhvar1[var "Group Save File Confirm", val {t}]
+@f[do-active-group] iterates over @var[active-file-group] executing the forms
+once for each file.  While the forms are executing, the file is in the current
+buffer, and the point is at the beginning.  If there is no active group, this
+signals an editor-error.
+
+This reads each file into its own buffer using @f[find-file-buffer].  Since
+unwanted buffers may consume large amounts of memory, @hid[Group Find File]
+controls whether to delete the buffer after executing the forms.  When the
+variable is false, this deletes the buffer if it did not previously exist;
+however, regardless of this variable, if the user leaves the buffer modified,
+the buffer persists after the forms have completed.  Whenever this processes a
+buffer that already existed, it saves the location of the buffer's point before
+and restores it afterwards.  
+
+After processing a buffer, if it is modified, @f[do-active-group] tries to save
+it.  If @hid[Group Save File Confirm] is non-@nil, it asks for confirmation.
+@enddefmac
+
+
+@section (File Reading and Writing)
+Common Lisp pathnames are used by the file primitives.  For probing, checking
+write dates, and so forth, all of the Common Lisp file functions are available.
+
+@defun[fun {read-file}, args {@i[pathname] @i[mark]}]
+This inserts the file named by @i[pathname] at @i[mark].
+@enddefun
+
+@defun[fun {write-file}, args {@i[region] @i[pathname]},
+	keys {[keep-backup][access]}]
+@defhvar1[var {Keep Backup Files}, val {@nil}]
+@f[write-file] writes the contents of @i[region] to the file named by
+@i[pathname].  This writes @i[region] using a stream as if it were opened with
+@kwd[if-exists] supplied as @kwd[rename-and-delete].  When @i[keep-backup],
+which defaults to the value of @hid[Keep Backup Files], is non-nil, it is as if
+the stream were opened with @kwd[if-exists] supplied as @kwd[rename].
+@i[Access] is an implementation dependent value that is suitable for setting
+@i[pathname]'s access or protection bits.
+@enddefun
+
+
+@defun[fun {write-buffer-file}, args {@i[buffer] @i[pathname]}]
+@defhvar1[var {Write File Hook}]
+@defhvar1[var {Add Newline at EOF on Writing File}, val {@kwd[ask-user]}]
+@f[write-buffer-file] writes @i[buffer] to the file named by @i[pathname]
+including the following:
+@begin[itemize]
+It assumes pathname is somehow related to @i[buffer]'s pathname: if the
+@i[buffer]'s write date is not the same as @i[pathname]'s, then this prompts
+the user for confirmation before overwriting the file.
+
+It consults @hid[Add Newline at EOF on Writing File] (see @i[Hemlock User's
+Manual] for possible values) and interacts with the user if necessary.
+
+It sets @hid[Pathname Defaults], and after using @f[write-file], marks
+@i[buffer] unmodified.
+
+It updates @i[Buffer]'s pathname and write date.
+
+It renames the buffer according to the new pathname if possible.
+
+It invokes @hid[Write File Hook].
+@end[itemize]
+
+@hid[Write File Hook] is a list of functions that take the newly written buffer
+as an argument.
+@enddefun
+
+
+@defun[fun {read-buffer-file}, args {@i[pathname] @i[buffer]}]
+@defhvar1[var {Read File Hook}]
+@f[read-buffer-file] deletes @i[buffer]'s region and uses @f[read-file] to read
+@i[pathname] into it, including the following:
+@begin[itemize]
+It sets @i[buffer]'s write date to the file's write date if the file exists;
+otherwise, it @f[message]'s that this is a new file and sets @i[buffer]'s write
+date to @nil.
+
+It moves @i[buffer]'s point to the beginning.
+
+It sets @i[buffer]'s unmodified status.
+
+It sets @i[buffer]'s pathname to the result of probing @i[pathname] if the file
+exists; otherwise, this function sets @i[buffer]'s pathname to the result of
+merging @i[pathname] with @f[default-directory].
+
+It sets @hid[Pathname Defaults] to the result of the previous item.
+
+It processes the file options.
+
+It invokes @hid[Read File Hook].
+@end[itemize]
+
+@hid[Read File Hook] is a list functions that take two arguments @dash the
+buffer read into and whether the file existed, @true if so.
+@enddefun
+
+
+@defun[fun {find-file-buffer}, args {@i[pathname]}]
+This returns a buffer assoicated with the @i[pathname], reading the file into a
+new buffer if necessary.  This returns a second value indicating whether a new
+buffer was created, @true if so.  If the file has already been read, this
+checks to see if the file has been modified on disk since it was read, giving
+the user various recovery options.  This is the basis of the @hid[Find File]
+command.
+@enddefun
+
+
+
+@chapter (Hemlock's Lisp Environment)
+
+@index (Lisp environment)
+This chapter is sort of a catch all for any functions and variables
+which concern @hemlock's interaction with the outside world.
+
+@section(Entering and Leaving the Editor)
+
+@defun[fun {ed}, args {@optional @i[x]}]
+@defhvar1[var "Entry Hook"]
+@f[ed] enters the editor.  It is basically as specified in Common Lisp.  If
+@i[x] is supplied and is a symbol, the definition of @i[x] is put into a
+buffer, and that buffer is selected.  If @i[x] is a pathname, the file
+specified by @i[x] is visited in a new buffer.  If @i[x] is not supplied or
+@nil, the editor is entered in the same state as when last exited.
+	
+The @hid[Entry Hook] is invoked each time the editor is entered.
+@enddefhvar
+
+@defun[fun {exit-hemlock}, args {@optional @i[value]}]
+@defhvar1[var {Exit Hook}]
+@f[exit-hemlock] leaves @hemlock and return to Lisp; @i[value] is the
+value to return, which defaults to @true.  The hook 
+@hvarref[Exit Hook] is invoked before this is done.
+@enddefun
+
+@defun[fun {pause-hemlock}]
+@f[pause-hemlock] suspends the editor process and returns control to the shell.
+When the process is resumed, it will still be running @hemlock.
+@enddefun
+
+
+@section(Keyboard Input)
+@index(I/O)
+@index[keyboard input]
+@index[input, keyboard]
+
+Keyboard input interacts with a number of other parts of the editor.  Since the
+command loop works by reading from the keyboard, keyboard input is the initial
+cause of everything that happens.  Also, @hemlock redisplays in the low-level
+input loop when there is no available input from the user.
+
+
+@defvar[var {editor-input}]
+@defvar1[var {real-editor-input}]
+@defhvar1[var "Input Hook"]
+@defhvar1[var "Abort Hook"]
+@index[aborting]
+@var[editor-input] is an object on which @hemlock's I/O routines operate.  You
+can get input, clear input, return input, and listen for input.  Input appears
+as key-events.
+
+@var[real-editor-input] holds the initial value of @var[editor-input].  This is
+useful for reading from the user when @var[editor-input] is rebound (such as
+within a keyboard macro.)
+
+@Hemlock invokes the functions in @hid[Input Hook] each time someone reads a
+key-event from @var[real-editor-input].  These take no arguments.
+@enddefvar
+
+@defun[fun {get-key-event}, args {@i[editor-input] @optional @i[ignore-abort-attempts-p]}]
+This function returns a key-event as soon as it is available on
+@i[editor-input].  @i[Editor-input] is either @var[editor-input] or
+@var[real-editor-input].  @i[Ignore-abort-attempts-p] indicates whether
+@binding[C-g] and @binding[C-G] throw to the editor's top-level command loop;
+when this is non-nil, this function returns those key-events when the user
+types them.  Otherwise, it aborts the editor's current state, returning to the
+command loop.
+
+When the user aborts, @Hemlock invokes the functions in @hid[Abort Hook].
+These functions take no arguments.  When aborting, @Hemlock ignores the
+@hid[Input Hook].
+@enddefun
+
+
+@defun[fun {unget-key-event}, args {@i[key-event] @i[editor-input]}]
+This function returns @i[key-event] to @i[editor-input], so the next invocation
+of @f[get-key-event] will return @i[key-event].  If @i[key-event] is
+@f[#k"C-g"] or @f[#k"C-G"], then whether @f[get-key-event] returns it depends
+on that function's second argument.  @i[Editor-input] is either
+@var[editor-input] or @var[real-editor-input].
+@enddefun
+
+@defun[fun {clear-editor-input}, args {@i[editor-input]}]
+This function flushes any pending input on @i[editor-input].  @i[Editor-input]
+is either @var[editor-input] or @var[real-editor-input].
+@enddefun
+
+@defun[fun {listen-editor-input}, args {@i[editor-input]}]
+This function returns whether there is any input available on @i[editor-input].
+@i[Editor-input] is either @var[editor-input] or @var[real-editor-input].
+@enddefun
+
+@defun[fun {editor-sleep}, args {@i[time]}]
+Return either after @i[time] seconds have elapsed or when input is available on
+@var[editor-input].
+@enddefun
+
+@defvar[var {key-event-history}]
+This is a @hemlock ring buffer (see page @pageref[rings]) that holds the last
+60 key-events read from the keyboard.
+@enddefvar
+
+@defvar[var {last-key-event-typed}]
+Commands use this variable to realize the last key-event the user typed to
+invoke the commands.  Before @hemlock ever reads any input, the value is @nil.
+This variable usually holds the last key-event read from the keyboard, but it
+is also maintained within keyboard macros allowing commands to behave the same
+on each repetition as they did in the recording invocation.
+@enddefvar
+
+@defvar[var {input-transcript}]
+If this is non-@nil then it should be an adjustable vector with a fill-pointer.
+When it is non-@nil, @hemlock pushes all input read onto this vector.
+@enddefvar
+
+
+
+@section(Hemlock Streams)
+It is possible to create streams which output to or get input from a buffer.
+This mechanism is quite powerful and permits easy interfacing of @hemlock to
+Lisp.
+
+@defun[fun {make-hemlock-output-stream}, args 
+	{@i[mark] @optional @i[buffered]}]
+@defun1[fun {hemlock-output-stream-p}, args {@i[object]}]
+@f[make-hemlock-output-stream] returns a stream that inserts at the permanent
+mark @i[mark] all output directed to it.  @i[Buffered] controls whether the
+stream is buffered or not, and its valid values are the following keywords:
+@begin[description]
+@kwd[none]@\No buffering is done.  This is the default.
+
+@kwd[line]@\The buffer is flushed whenever a newline is written or
+when it is explicitly done with @f[force-output].
+
+@kwd[full]@\The screen is only brought up to date when it is
+explicitly done with @f[force-output]
+@end[description]
+
+@f[hemlock-output-stream-p] returns @true if @i[object] is a
+@f[hemlock-output-stream] object.
+@enddefun
+
+@defun[fun {make-hemlock-region-stream}, args {@i[region]}]
+@defun1[fun {hemlock-region-stream-p}, args {@i[object]}]
+@f[make-hemlock-region-stream] returns a stream from which the text in
+@i[region] can be read.  @f[hemlock-region-stream-p] returns @true if
+@i[object] is a @f[hemlock-region-stream] object.
+@enddefun
+
+@defmac[fun {with-input-from-region}, args
+{(@i[var] @i[region]) @mstar<@i[declaration]> @mstar<@i[form]>}]
+While evaluating @i[form]s, binds @i[var] to a stream which returns input
+from @i[region].
+@enddefmac
+
+@defmac[fun {with-output-to-mark}, args
+{(@i[var] @i[mark] @mopt<@i"buffered">) @mstar<@i[declaration]> @mstar<@i[form]>}]
+ During the evaluation of the @i[form]s, binds @i[var] to a stream which
+inserts output at the permanent @i[mark].  @i[Buffered] has the same meaning as
+for @f[make-hemlock-output-stream].
+@enddefmac
+
+@defmac[fun {with-pop-up-display}, args {(@i[var] @key @i[height name]) @mstar<@i[declaration]> @mstar<@i[form]>}]
+@defvar1[var {random-typeout-buffers}]
+ This macro executes @i[forms] in a context with @i[var] bound to a stream.
+@Hemlock collects output to this stream and tries to pop up a display of the
+appropriate height containing all the output.  When @i[height] is supplied,
+@Hemlock creates the pop-up display immediately, forcing output on line breaks.
+The system saves the output in a buffer named @i[name], which defaults to
+@hid[Random Typeout].  When the window is the incorrect height, the display
+mechanism will scroll the window with more-style prompting.  This is useful
+for displaying information of temporary interest.
+
+When a buffer with name @i[name] already exists and was not previously created
+by @f[with-pop-up-display], @Hemlock signals an error.
+
+@var[random-typeout-buffers] is an association list mapping random typeout
+buffers to the streams that operate on the buffers.
+@enddefmac
+
+
+@section (Interface to the Error System)
+The error system interface is minimal.  There is a simple editor-error
+condition which is a subtype of error and a convenient means for signaling
+them.  @Hemlock also provides a standard handler for error conditions while in
+the editor.
+
+@defun[fun {editor-error-format-string}, args {@i[condition]}]
+@defun1[fun {editor-error-format-arguments}, args {@i[condition]}]
+Handlers for editor-error conditions can access the condition object with
+these.
+@enddefun
+
+@defun[fun {editor-error}, args {@rest @i[args]}]
+This function is called to signal minor errors within Hemlock; these are errors
+that a normal user could encounter in the course of editing such as a search
+failing or an attempt to delete past the end of the buffer.  This function
+@f[signal]'s an editor-error condition formed from @i[args], which are @nil or
+a @f[format] string possibly followed by @f[format] arguments.  @Hemlock
+invokes commands in a dynamic context with an editor-error condition handler
+bound.  This default handler beeps or flashes (or both) the display.  If the
+condition passed to the handler has a non-@nil string slot, the handler also
+invokes @f[message] on it.  The command in progress is always aborted, and this
+function never returns.
+@enddefun
+
+@defmac[fun {handle-lisp-errors}, args {@mstar<@i[form]>}]
+Within the body of this macro any Lisp errors that occur are handled in some
+fashion more gracefully than simply dumping the user in the debugger.  This
+macro should be wrapped around code which may get an error due to some action
+of the user @dash for example, evaluating code fragments on the behalf of and
+supplied by the user.  Using this in a command allows the established handler
+to shadow the default editor-error handler, so commands should take care to
+signal user errors (calls to @f[editor-errors]) outside of this context.
+@enddefmac
+
+
+@section (Definition Editing)
+@index (Definition editing)
+@hemlock provides commands for finding the definition of a function, macro, or
+command and placing the user at the definition in a buffer.  This, of course,
+is implementation dependent, and if an implementation does not associate a
+source file with a routine, or if @hemlock cannot get at the information, then
+these commands do not work.  If the Lisp system does not store an absolute
+pathname, independent of the machine on which the maintainer built the system,
+then users need a way of translating a source pathname to one that will be able
+to locate the source.
+
+@defun[fun {add-definition-dir-translation}, args {@i[dir1] @i[dir2]}]
+This maps directory pathname @i[dir1] to @i[dir2].  Successive invocations
+using the same @i[dir1] push into a translation list.  When @hemlock seeks a
+definition source file, and it has a translation, then it tries the
+translations in order.  This is useful if your sources are on various machines,
+some of which may be down.  When @hemlock tries to find a translation, it first
+looks for translations of longer directory pathnames, finding more specific
+translations before shorter, more general ones.
+@enddefun
+
+@defun[fun {delete-definition-dir-translation}, args {@i[dir]}]
+This deletes the mapping of @i[dir] to all directories to which it has been
+mapped.
+@enddefun
+
+
+@section (Event Scheduling)
+@index (Event scheduling)
+@index (Scheduling events)
+The mechanism described in this chapter is only operative when the Lisp process
+is actually running inside of @hemlock, within the @f[ed] function.  The
+designers intended its use to be associated with the editor, such as with
+auto-saving files, reminding the user, etc.
+
+@defun[fun {schedule-event}, args {@i[time] @i[function] @optional @i[repeat]}]
+This causes @hemlock to call @i[function] after @i[time] seconds have passed,
+optionally repeating every @i[time] seconds.  @i[Repeat] defaults to @true.
+This is a rough mechanism since commands can take an arbitrary amount of time
+to run; @hemlock invokes @i[function] at the first possible moment after
+@i[time] has elapsed.  @i[Function] takes the time in seconds that has elapsed
+since the last time it was called (or since it was scheduled for the first
+invocation).
+@enddefun
+
+@defun[fun {remove-scheduled-event}, args {@i[function]}]
+This removes @i[function] from the scheduling queue.  @i[Function] does not
+have to be in the queue.
+@enddefun
+
+
+@section (Miscellaneous)
+
+@defun[fun {in-lisp}, args {@mstar<@i[form]>}]
+@index[Evaluating Lisp code]
+This evaluates @i[form]'s inside @f[handle-lisp-errors].  It also binds
+@var[package] to the package named by @hid[Current Package] if it is non-@nil.
+Use this when evaluating Lisp code on behalf of the user.
+@enddefun
+
+@defmac[fun {do-alpha-chars}, args {(@i[var] @i[kind] [@i[result]]) @mstar<@i[form]>}]
+This iterates over alphabetic characters in Common Lisp binding @i[var] to each
+character in order as specified under character relations in @i[Common Lisp the
+Language].  @i[Kind] is one of @kwd[lower], @kwd[upper], or @kwd[both].  When
+the user supplies @kwd[both], lowercase characters are processed first.
+@enddefmac
+
+
+
+@chapter (High-Level Text Primitives)
+This chapter discusses primitives that operate on higher level text forms than
+characters and words.  For English text, there are functions that know about
+sentence and paragraph structures, and for Lisp sources, there are functions
+that understand this language.  This chapter also describes mechanisms for
+organizing file sections into @i[logical pages] and for formatting text forms.
+
+
+@section (Indenting Text)
+@index (Indenting)
+@label(indenting)
+
+@defhvar[var "Indent Function", val {tab-to-tab-stop}]
+The value of this variable determines how indentation is done, and it is a
+function which is passed a mark as its argument.  The function should indent
+the line that the mark points to.  The function may move the mark around on
+the line.  The mark will be @f[:left-inserting].  The default simply inserts a
+@binding[tab] character at the mark.  A function for @hid[Lisp] mode probably
+moves the mark to the beginning of the line, deletes horizontal whitespace, and
+computes some appropriate indentation for Lisp code.
+@enddefhvar
+
+@defhvar[var "Indent with Tabs", val {indent-using-tabs}]
+@defhvar1[var "Spaces per Tab", val {8}]
+@hid[Indent with Tabs] holds a function that takes a mark and a number of
+spaces.  The function will insert a maximum number of tabs and a minimum number
+of spaces at mark to move the specified number of columns.  The default
+definition uses @hid[Spaces per Tab] to determine the size of a tab.  @i[Note,]
+@hid[Spaces per Tab] @i[is not used everywhere in @hemlock yet, so changing
+this variable could have unexpected results.]
+@enddefhvar
+
+@defun[fun {indent-region}, args {@i[region]}]
+@defun1[fun {indent-region-for-commands}, args {@i[region]}]
+@f[indent-region] invokes the value of @hid[Indent Function] on every line of
+region.  @f[indent-region-for-commands] uses @f[indent-region] but first saves
+the region for the @hid[Undo] command.
+@enddefun
+
+@defun[fun {delete-horizontal-space}, args {@i[mark]}]
+This deletes all characters with a @hid[Space] attribute (see section
+@ref[sys-def-chars]) of @f[1].
+@enddefun
+
+
+@section (Lisp Text Buffers)
+@index (Lisp text functions)
+@hemlock bases its Lisp primitives on parsing a block of the buffer and
+annotating lines as to what kind of Lisp syntax occurs on the line or what kind
+of form a mark might be in (for example, string, comment, list, etc.).  These
+do not work well if the block of parsed forms is exceeded when moving marks
+around these forms, but the block that gets parsed is somewhat programmable.
+
+There is also a notion of a @i[top level form] which this documentation often
+uses synonymously with @i[defun], meaning a Lisp form occurring in a source
+file delimited by parentheses with the opening parenthesis at the beginning of
+some line.  The names of the functions include this inconsistency.
+
+@defun[fun {pre-command-parse-check}, args {@i[mark] @i[for-sure]}]
+@defhvar1[var {Parse Start Function}, val {start-of-parse-block}]
+@defhvar1[var {Parse End Function}, val {end-of-parse-block}]
+@defhvar1[var {Minimum Lines Parsed}, val {50}]
+@defhvar1[var {Maximum Lines Parsed}, val {500}]
+@defhvar1[var {Defun Parse Goal}, val {2}]
+@f[pre-command-parse-check] calls @hid[Parse Start Function] and @hid[Parse End
+Function] on @i[mark] to get two marks.  It then parses all the lines between
+the marks including the complete lines they point into.  When @i[for-sure] is
+non-@nil, this parses the area regardless of any cached information about the
+lines.  Every command that uses the following routines calls this before doing
+so.
+
+The default values of the start and end variables use @hid[Minimum Lines
+Parsed], @hid[Maximum Lines Parsed], and @hid[Defun Parse Goal] to determine
+how big a region to parse.  These two functions always include at least the
+minimum number of lines before and after the mark passed to them.  They try to
+include @hid[Defun Parse Goal] number of top level forms before and after the
+mark passed them, but these functions never return marks that include more than
+the maximum number of lines before or after the mark passed to them.
+@enddefun
+
+@defun[fun {form-offset}, args {@i[mark] @i[count]}]
+This tries to move @i[mark] @i[count] forms forward if positive or -@i[count]
+forms backwards if negative.  @i[Mark] is always moved.  If there were enough
+forms in the appropriate direction, this returns @i[mark], otherwise nil.
+@enddefun
+
+@defun[fun {top-level-offset}, args {@i[mark] @i[count]}]
+This tries to move @i[mark] @i[count] top level forms forward if positive or
+-@i[count] top level forms backwards if negative.  If there were enough top
+level forms in the appropriate direction, this returns @i[mark], otherwise nil.
+@i[Mark] is moved only if this is successful.
+@enddefun
+
+@defun[fun {mark-top-level-form}, args {@i[mark1] @i[mark2]}]
+This moves @i[mark1] and @i[mark2] to the beginning and end, respectively, of
+the current or next top level form.  @i[Mark1] is used as a reference to start
+looking.  The marks may be altered even if unsuccessful.  If successful, return
+@i[mark2], else nil.  @i[Mark2] is left at the beginning of the line following
+the top level form if possible, but if the last line has text after the closing
+parenthesis, this leaves the mark immediately after the form.
+@enddefun
+
+@defun[fun {defun-region}, args {@i[mark]}]
+This returns a region around the current or next defun with respect to
+@i[mark].  @i[Mark] is not used to form the region.  If there is no appropriate
+top level form, this signals an editor-error.  This calls
+@f[pre-command-parse-check] first.
+@enddefun
+
+@defun[fun {inside-defun-p}, args {@i[mark]}]
+@defun1[fun {start-defun-p}, args {@i[mark]}]
+These return, respectively, whether @i[mark] is inside a top level form or at
+the beginning of a line immediately before a character whose @hid[Lisp Syntax]
+(see section @ref[sys-def-chars]) value is @kwd[opening-paren].
+@enddefun
+
+@defun[fun {forward-up-list}, args {@i[mark]}]
+@defun1[fun {backward-up-list}, args {@i[mark]}]
+Respectively, these move @i[mark] immediately past a character whose @hid[Lisp
+Syntax] (see section @ref[sys-def-chars]) value is @kwd[closing-paren] or
+immediately before a character whose @hid[Lisp Syntax] value is
+@kwd[opening-paren].
+@enddefun
+
+@defun[fun {valid-spot}, args {@i[mark] @i[forwardp]}]
+This returns @true or @nil depending on whether the character indicated by
+@i[mark] is a valid spot.  When @i[forwardp] is set, use the character after
+mark and vice versa.  Valid spots exclude commented text, inside strings, and
+character quoting.
+@enddefun
+
+@defun[fun {defindent}, args {@i[name] @i[count]}]
+This defines the function with @i[name] to have @i[count] special arguments.
+@f[indent-for-lisp], the value of @hid[Indent Function] (see section
+@ref[indenting]) in @hid[Lisp] mode, uses this to specially indent these
+arguments.  For example, @f[do] has two, @f[with-open-file] has one, etc.
+There are many of these defined by the system including definitions for special
+@hemlock forms.  @i[Name] is a simple-string, case insensitive and purely
+textual (that is, not read by the Lisp reader); therefore, @f["with-a-mumble"]
+is distinct from @f["mumble:with-a-mumble"].
+@enddefun
+
+
+@section (English Text Buffers)
+@index (English text functions)
+@label(text-functions)
+This section describes some routines that understand basic English language
+forms.
+
+@defun[fun {word-offset}, args {@i[mark] @i[count]}]
+This moves @i[mark] @i[count] words forward (if positive) or backwards (if
+negative).  If @i[mark] is in the middle of a word, that counts as one.  If
+there were @i[count] (-@i[count] if negative) words in the appropriate
+direction, this returns @i[mark], otherwise nil.  This always moves @i[mark].
+A word lies between two characters whose @hid[Word Delimiter] attribute value
+is @f[1] (see section @ref[sys-def-chars]).
+@enddefun
+
+@defun[fun {sentence-offset}, args {@i[mark] @i[count]}]
+This moves @i[mark] @i[count] sentences forward (if positive) or backwards (if
+negative).  If @i[mark] is in the middle of a sentence, that counts as one.  If
+there were @i[count] (-@i[count] if negative) sentences in the appropriate
+direction, this returns @i[mark], otherwise nil.  This always moves @i[mark].
+
+A sentence ends with a character whose @hid[Sentence Terminator] attribute is
+@f[1] followed by two spaces, a newline, or the end of the buffer.  The
+terminating character is optionally followed by any number of characters whose
+@hid[Sentence Closing Char] attribute is @f[1].  A sentence begins after a
+previous sentence ends, at the beginning of a paragraph, or at the beginning of
+the buffer.
+@enddefun
+
+@defun[fun {paragraph-offset}, args {@i[mark] @i[count] @optional @i[prefix]}]
+@defhvar1[var {Paragraph Delimiter Function}, var {default-para-delim-function}]
+This moves @i[mark] @i[count] paragraphs forward (if positive) or backwards (if
+negative).  If @i[mark] is in the middle of a paragraph, that counts as one.
+If there were @i[count] (-@i[count] if negative) paragraphs in the appropriate
+direction, this returns @i[mark], otherwise nil.  This only moves @i[mark] if
+there were enough paragraphs.
+
+@hid[Paragraph Delimiter Function] holds a function that takes a mark,
+typically at the beginning of a line, and returns whether or not the current
+line should break the paragraph.  @f[default-para-delim-function] returns @true
+if the next character, the first on the line, has a @hid[Paragraph Delimiter]
+attribute value of @f[1].  This is typically a space, for an indented
+paragraph, or a newline, for a block style.  Some modes require a more
+complicated determinant; for example, @hid[Scribe] modes adds some characters
+to the set and special cases certain formatting commands.
+
+@i[Prefix] defaults to @hid[Fill Prefix] (see section @ref[filling]), and the
+right prefix is necessary to correctly skip paragraphs.  If @i[prefix] is
+non-@nil, and a line begins with @i[prefix], then the scanning process skips
+the prefix before invoking the @hid[Paragraph Delimiter Function].
+Note, when scanning for paragraph bounds, and @i[prefix] is non-@nil, lines are
+potentially part of the paragraph regardless of whether they contain the prefix;
+only the result of invoking the delimiter function matters.
+
+The programmer should be aware of an idiom for finding the end of the current
+paragraph.  Assume @f[paragraphp] is the result of moving @f[mark] one
+paragraph, then the following correctly determines whether there actually is a
+current paragraph:
+@begin[programexample]
+(or paragraphp
+    (and (last-line-p mark)
+         (end-line-p mark)
+	 (not (blank-line-p (mark-line mark)))))
+@end[programexample]
+In this example @f[mark] is at the end of the last paragraph in the buffer, and
+there is no last newline character in the buffer.  @f[paragraph-offset] would
+have returned @nil since it could not skip any paragraphs since @f[mark] was at
+the end of the current and last paragraph.  However, you still have found a
+current paragraph on which to operate.  @f[mark-paragraph] understands this
+problem.
+@enddefun
+
+@defun[fun {mark-paragraph}, args {@f[mark1] @f[mark2]}]
+This marks the next or current paragraph, setting @i[mark1] to the beginning
+and @i[mark2] to the end.  This uses @hid[Fill Prefix] (see section
+@ref[filling]).  @i[Mark1] is always on the first line of the paragraph,
+regardless of whether the previous line is blank.  @i[Mark2] is typically at
+the beginning of the line after the line the paragraph ends on, this returns
+@i[mark2] on success.  If this cannot find a paragraph, then the marks are left
+unmoved, and @nil is returned.
+@enddefun
+
+
+@section (Logical Pages)
+@index (Logical pages)
+@index (Page functions)
+@label(logical-pages)
+Logical pages are a way of dividing a file into coarse divisions.  This is
+analogous to dividing a paper into sections, and @hemlock provides primitives
+for moving between the pages of a file and listing a directory of the page
+titles.  Pages are separated by @hid[Page Delimiter] characters (see section
+@ref[sys-def-chars]) that appear at the beginning of a line.
+
+@defun[fun {goto-page}, args {@i[mark] @i[n]}]
+This moves @i[mark] to the absolute page numbered @i[n].  If there are less
+than @i[n] pages, it signals an editor-error.  If it returns, it returns
+@i[mark].  @hemlock numbers pages starting with one for the page delimited by
+the beginning of the buffer and the first @hid[Page Delimiter] (or the end of
+the buffer).
+@enddefun
+
+@defun[fun {page-offset}, args {@i[mark] @i[n]}]
+This moves mark forward @i[n] (-@i[n] backwards, if @i[n] is negative)
+@hid[Page Delimiter] characters that are in the zero'th line position.  If a
+@hid[Page Delimiter] is the immediately next character after mark (or before
+mark, if @i[n] is negative), then skip it before starting.  This always moves
+@i[mark], and if there were enough pages to move over, it returns @i[mark];
+otherwise, it returns @nil.
+@enddefun
+
+@defun[fun {page-directory}, args {@i[buffer]}]
+This returns a list of each first non-blank line in @i[buffer] that follows a
+@hid[Page Delimiter] character that is in the zero'th line position.  This
+includes the first line of the @i[buffer] as the first page title.  If a page
+is empty, then its title is the empty string.
+@enddefun
+
+@defun[fun {display-page-directory}, args {@i[stream] @i[directory]}]
+This writes the list of strings, @i[directory], to @i[stream], enumerating them
+in a field three wide.  The number and string are separated by two spaces, and
+the first line contains headings for the page numbers and title strings.
+@enddefun
+
+
+@section (Filling)
+@index (filling)
+@label(filling)
+Filling is an operation on text that breaks long lines at word boundaries
+before a given column and merges shorter lines together in an attempt to make
+each line roughly the specified length.  This is different from justification
+which tries to add whitespace in awkward places to make each line exactly the
+same length.  @Hemlock's filling optionally inserts a specified string at the
+beginning of each line.  Also, it eliminates extra whitespace between lines and
+words, but it knows two spaces follow sentences (see section
+@ref[text-functions]).
+
+@defhvar[var "Fill Column", val {75}]
+@defhvar1[var "Fill Prefix", val {nil}]
+These variables hold the default values of the prefix and column arguments to
+@hemlock's filling primitives.  If @hid[Fill Prefix] is @nil, then there is no
+fill prefix.
+@enddefhvar
+
+@defun[fun {fill-region}, args {@i[region] @optional @i[prefix] @i[column]}]
+This deletes any blank lines in region and fills it according to prefix and
+column.  @i[Prefix] and @i[column] default to @hid[Fill Prefix] and @hid[Fill
+Column].
+@enddefun
+
+@defun[fun {fill-region-by-paragraphs},
+	args {@i[region] @optional @i[prefix] @i[column]}]
+This finds paragraphs (see section @ref[text-functions]) within region and
+fills them with @f[fill-region].  This ignores blank lines between paragraphs.
+@i[Prefix] and @i[column] default to @hid[Fill Prefix] and @hid[Fill Column].
+@enddefun
+
+
+
+@chapter (Utilities)
+@index (Utilities)
+This chapter describes a number of utilities for manipulating some types of
+objects @hemlock uses to record information.  String-tables are used to store
+names of variables, commands, modes, and buffers.  Ring lists can be used to
+provide a kill ring, recent command history, or other user-visible features.
+
+
+@section(String-table Functions)
+@index (String-tables)
+@label(string-tables)
+
+String tables are similar to Common Lisp hash tables in that they associate a
+value with an object.  There are a few useful differences: in a string table
+the key is always a case insensitive string, and primitives are provided to
+facilitate keyword completion and recognition.  Any type of string may be added
+to a string table, but the string table functions always return
+@f[simple-string]'s.
+
+A string entry in one of these tables may be thought of as being separated into
+fields or keywords.  The interface provides keyword completion and recognition
+which is primarily used to implement some @hid[Echo Area] commands.  These
+routines perform a prefix match on a field-by-field basis allowing the
+ambiguous specification of earlier fields while going on to enter later fields.
+While string tables may use any @f[string-char] as a separator, the use of
+characters other than @binding[space] may make the @hid[Echo Area] commands
+fail or work unexpectedly.
+
+@defun[fun {make-string-table}, keys {[separator][initial-contents]}]
+This function creates an empty string table that uses @i[separator] as the
+character, which must be a @f[string-char], that distinguishes fields.
+@i[Initial-contents] specifies an initial set of strings and their values in
+the form of a dotted @f[a-list], for example:
+@Begin[ProgramExample]
+'(("Global" . t) ("Mode" . t) ("Buffer" . t))
+@End[ProgramExample]
+@enddefun
+
+@defun[fun {string-table-p}, args {@i[string-table]}]
+This function returns @true if @i[string-table] is a @f[string-table] object,
+otherwise @nil.
+@enddefun
+
+@defun[fun {string-table-separator}, args {@i[string-table]}]
+This function returns the separator character given to @f[make-string-table].
+@enddefun
+
+@defun[fun {delete-string}, args {@i[string] @i[table]}]
+@defun1[fun {clrstring}, args {@i[table]}]
+@f[delete-string] removes any entry for @i[string] from the @f[string-table]
+@i[table], returning @true if there was an entry.  @f[clrstring] removes all
+entries from @i[table].
+@enddefun
+
+@defun[fun {getstring}, args {@i[string] @i[table]}]
+This function returns as multiple values, first the value corresponding to the
+string if it is found and @nil if it isn't, and second @true if it is found and
+@nil if it isn't.
+
+This may be set with @f[setf] to add a new entry or to store a new value for a
+string.  It is an error to try to insert a string with more than one
+field separator character occurring contiguously.
+@enddefun
+
+@defun[fun {complete-string}, args {@i[string] @i[tables]}]
+This function completes @i[string] as far as possible over the list of
+@i[tables], returning five values.  It is an error for @i[tables] to have
+different separator characters.  The five return values are as follows:
+@begin[itemize]
+The maximal completion of the string or @nil if there is none.
+
+An indication of the usefulness of the returned string:
+@begin[description]
+@kwd[none]@\
+There is no completion of @i[string].
+
+@kwd[complete]@\
+The completion is a valid entry, but other valid completions exist too.  This
+occurs when the supplied string is an entry as well as initial substring of
+another entry.
+
+@kwd[unique]@\
+The completion is a valid entry and unique.
+
+@kwd[ambiguous]@\
+The completion is invalid; @f[get-string] would return @nil and @nil if given
+the returned string.
+@end[description]
+
+The value of the string when the completion is @kwd[unique] or @kwd[complete],
+otherwise @nil.
+
+An index, or nil, into the completion returned, indicating where the addition
+of a single field to @i[string] ends.  The command @hid[Complete Field] uses
+this when the completion contains the addition to @i[string] of more than one
+field.
+
+An index to the separator following the first ambiguous field when the
+completion is @kwd[ambiguous] or @kwd[complete], otherwise @nil.
+@end[itemize]
+@enddefun
+
+@defun[fun {find-ambiguous}, args {@i[string] @i[table]}]
+@defun1[fun {find-containing}, args {@i[string] @i[table]}]
+@f[find-ambiguous] returns a list in alphabetical order of all the
+strings in @i[table] matching @i[string].  This considers an entry as matching
+if each field in @i[string], taken in order, is an initial substring of the
+entry's fields; entry may have fields remaining.
+ 
+@f[find-containing] is similar, but it ignores the order of the fields in
+@i[string], returning all strings in @i[table] matching any permutation of the
+fields in @i[string].
+@enddefun
+
+@defmac[fun {do-strings}, args {(@i[string-var] @i[value-var] @i[table] @MOPT<@i[result]>) @mstar<@i[declaration]> @mstar<@i[tag] @MOR @i[statement]>}]
+This macro iterates over the strings in @i[table] in alphabetical order.  On
+each iteration, it binds @i[string-var] to an entry's string and @i[value-var]
+to an entry's value.
+@enddefmac
+
+
+@section (Ring Functions)
+@index (Rings)
+@label[rings]
+There are various purposes in an editor for which a ring of values can be used,
+so @hemlock provides a general ring buffer type.  It is used for maintaining a
+ring of killed regions (see section @ref[kill-ring]), a ring of marks (see
+section @ref[mark-stack]), or a ring of command strings which various modes and
+commands maintain as a history mechanism.
+
+@defun[fun {make-ring}, args {@i[length] @optional @i[delete-function]}]
+Makes an empty ring object capable of holding up to @i[length] Lisp objects.
+@i[Delete-function] is a function that each object is passed to before it falls
+off the end.  @i[Length] must be greater than zero.
+@enddefun
+
+@defun[fun {ringp}, args {@i[ring]}]
+Returns @true if @i[ring] is a @f[ring] object, otherwise @nil.
+@enddefun
+
+@defun[fun {ring-length}, args {@i[ring]}]
+Returns as multiple-values the number of elements which @i[ring]
+currently holds and the maximum number of elements which it may hold.
+@enddefun
+
+@defun[fun {ring-ref}, args {@i[ring] @i[index]}]
+Returns the @i[index]'th item in the @i[ring], where zero is the index
+of the most recently pushed.  This may be set with @f[setf].
+@enddefun
+
+@defun[fun {ring-push}, args {@i[object] @i[ring]}]
+Pushes @i[object] into @i[ring], possibly causing the oldest item to
+go away.
+@enddefun
+
+@defun[fun {ring-pop}, args {@i[ring]}]
+Removes the most recently pushed object from @i[ring] and returns it.
+If the ring contains no elements then an error is signalled.
+@enddefun
+
+@defun[fun {rotate-ring}, args {@i[ring] @i[offset]}]
+With a positive @i[offset], rotates @i[ring] forward that many times.
+In a forward rotation the index of each element is reduced by one,
+except the one which initially had a zero index, which is made the
+last element.  A negative offset rotates the ring the other way.
+@enddefun
+
+
+@section (Undoing commands)
+@index (Undo functions)
+@label(undo)
+
+@defun[fun {save-for-undo}, args {@i[name] @i[method] @optional @i[cleanup] @i[method-undo] @i[buffer]}]
+This saves information to undo a command.  @i[Name] is a string to display when
+prompting the user for confirmation when he invokes the @hid[Undo] command (for
+example, @f["kill"] or @f["Fill Paragraph"]).  @i[Method] is the function to
+invoke to undo the effect of the command.  @i[Method-undo] is a function that
+undoes the undo function, or effectively re-establishes the state immediately
+after invoking the command.  If there is any existing undo information, this
+invokes the @i[cleanup] function; typically @i[method] closes over or uses
+permanent marks into a buffer, and the @i[cleanup] function should delete such
+references.  @i[Buffer] defaults to the @f[current-buffer], and the @hid[Undo]
+command only invokes undo methods when they were saved for the buffer that is
+current when the user invokes @hid[Undo].
+@enddefun
+
+@defun[fun {make-region-undo}, args {@i[kind] @i[name] @i[region] @optional @i[mark-or-region]}]
+This handles three common cases that commands fall into when setting up undo
+methods, including cleanup and method-undo functions (see @f[save-for-undo]).
+These cases are indicated by the @i[kind] argument:
+@begin[description]
+@kwd[twiddle]@\
+Use this kind when a command modifies a region, and the undo information
+indicates how to swap between two regions @dash the one before any modification
+occurs and the resulting region.  @i[Region] is the resulting region, and it
+has permanent marks into the buffer.  @i[Mark-or-region] is a region without
+marks into the buffer (for example, the result of @f[copy-region]).  As a
+result of calling this, a first invocation of @hid[Undo] deletes @i[region],
+saving it, and inserts @i[mark-or-region] where @i[region] used to be.  The
+undo method sets up for a second invocation of @hid[Undo] that will undo the
+effect of the undo; that is, after two calls, the buffer is exactly as it was
+after invoking the command.  This activity is repeatable any number of times.
+This establishes a cleanup method that deletes the two permanent marks into the
+buffer used to locate the modified region.
+
+@kwd[insert]@\
+Use this kind when a command has deleted a region, and the undo information
+indicates how to re-insert the region.  @i[Region] is the deleted and saved
+region, and it does not contain marks into any buffer.  @i[Mark-or-region] is a
+permanent mark into the buffer where the undo method should insert @i[region].
+As a result of calling this, a first invocation of @hid[Undo] inserts
+@i[region] at @i[mark-or-region] and forms a region around the inserted text
+with permanent marks into the buffer.  This allows a second invocation of
+@hid[Undo] to undo the effect of the undo; that is, after two calls, the buffer
+is exactly as it was after invoking the command.  This activity is repeatable
+any number of times.  This establishes a cleanup method that deletes either the
+permanent mark into the buffer or the two permanent marks of the region,
+depending on how many times the user used @hid[Undo].
+
+@kwd[delete]@\
+Use this kind when a command has inserted a block of text, and the undo
+information indicates how to delete the region.  @i[Region] has permanent marks
+into the buffer and surrounds the inserted text.  Leave @i[Mark-or-region]
+unspecified.  As a result of calling this, a first invocation of @hid[Undo]
+deletes @i[region], saving it, and establishes a permanent mark into the buffer
+to remember where the @i[region] was.  This allows a second invocation of
+@hid[Undo] to undo the effect of the undo; that is, after two calls, the buffer
+is exactly as it was after invoking the command.  This activity is repeatable
+any number of times.  This establishes a cleanup method that deletes either the
+permanent mark into the buffer or the two permanent marks of the region,
+depending on how many times the user used @hid[Undo].
+@end[description]
+
+@blankspace(1 line)
+@i[Name] in all cases is an appropriate string indicating what the command did.
+This is used by @hid[Undo] when prompting the user for confirmation before
+calling the undo method.  The string used by @hid[Undo] alternates between this
+argument and something to indicate that the user is undoing an undo.
+@enddefun
+
+
+
+@chapter (Miscellaneous)
+This chapter is somewhat of a catch-all for comments and features that don't
+fit well anywhere else.
+
+
+@section (Generic Pointer Up)
+@hid[Generic Pointer Up] is a @hemlock command bound to mouse up-clicks.  It
+invokes a function supplied with the interface described in this section.  This
+command allows different commands to be bound to the same down-click in various
+modes with one command bound to the corresponding up-click.
+
+@defun[fun {supply-generic-pointer-up-function}, args {@i[function]}]
+@index[Generic Pointer Up]
+This function supplies a function that @hid[Generic Pointer Up] invokes the
+next time it executes.
+@enddefun
+
+
+@section (Using View Mode)
+@hid[View] mode supports scrolling through files automatically terminating the
+buffer at end-of-file as well as commands for quitting the mode and popping
+back to the buffer that spawned the @hid[View] mode buffer.  Modes such as
+@hid[Dired] and @hid[Lisp-Lib] use this to view files and description of
+library entries.
+
+Modes that want similar commands should use @f[view-file-command] to view a
+file and get a handle on the view buffer.  To allow the @hid[View Return] and
+@hid[View Quit] commands to return to the originating buffer, you must set the
+variable @hid[View Return Function] in the viewing buffer to a function that
+knows how to do this.  Furthermore, since you now have a reference to the
+originating buffer, you must add a buffer local delete hook to it that will
+clear the view return function's reference.  This needs to happen for two
+reasons in case the user deletes the originating buffer:
+@Begin[Enumerate]
+You don't want the return function to go to a non-existing, invalid buffer.
+
+Since the viewing buffer still exists, its @hid[View Return Function] buffer
+local variable still exists.  This means the function still references the
+deleted originating buffer, and garbage collection cannot reclaim the memory
+locked down by the deleted buffer.
+@End[Enumerate]
+
+The following is a piece of code that could implement part of @hid[Dired View
+File] that uses two closures to accomplish that described above:
+@Begin[ProgramExample]
+(let* ((dired-buf (current-buffer))
+       (buffer (view-file-command nil pathname)))
+  (push #'(lambda (buffer)
+	    (declare (ignore buffer))
+	    (setf dired-buf nil))
+	(buffer-delete-hook dired-buf))
+  (setf (variable-value 'view-return-function :buffer buffer)
+	#'(lambda ()
+	    (if dired-buf
+		(change-to-buffer dired-buf)
+		(dired-from-buffer-pathname-command nil)))))
+@End[ProgramExample]
+
+The @hid[Dired] buffer's delete hook clears the return function's reference to
+the @hid[Dired] buffer.  The return function tests the variable to see if it
+still holds a buffer when the function executes.
+
+
+
+@comment[@chapter (Auxiliary Systems)]
+@include(aux-sys)
diff --git a/docs/hem/hem-docs.log b/docs/hem/hem-docs.log
new file mode 100644
index 000000000..25528a02e
--- /dev/null
+++ b/docs/hem/hem-docs.log
@@ -0,0 +1,43 @@
+/usr1/lisp/scribe/hem/user/lisp.mss, 01-Sep-89 10:27:47, Edit by Chiles.
+  Modifying slave interaction description.
+
+/usr1/lisp/scribe/hem/cim/cim.mss, 01-Sep-89 10:25:15, Edit by Chiles.
+  Added description of LOUD-MESSAGE.
+
+/usr1/lisp/scribe/hem/cim/aux-sys.mss, 01-Sep-89 10:22:22, Edit by Chiles.
+  Updating slave Lisp interaction functions.
+
+/usr1/lisp/scribe/hem/cim.mss, 27-Jun-89 15:19:47, Edit by Chiles.
+  Moved "Auxiliary Systems" chapter into its own file, and qualified lots of
+  the described symbols with their home package.
+
+/usr1/lisp/scribe/hem/hemimpl.mss, 22-Jun-89 12:56:23, Edit by Chiles.
+  Added new WITH-POP-UP-DISPLAY.
+
+  Updated all the English in the prompting functions section.
+
+  Added the "Keep" logical character description.
+
+
+/usr1/lisp/scribe/hem/hemuser.mss, 22-Jun-89 12:55:03, Edit by Chiles.
+  Added new pop-up windows section.
+
+  Modified modelines section, talked about status line.
+
+  Added completion section.
+
+
+/usr1/lisp/scribe/hem/hemuser.mss, 20-May-89 18:03:57, Edit by Chiles.
+  Modified example after "Name Keyboard Macro".  Scribe was screwing up a paren
+  in the @binding.  I changed it to a programexample, but check the result.
+
+/usr1/lisp/scribe/hemimpl.mss, 18-May-89 13:00:09, Edit by Chiles.
+  Addes sections to miscellaneous chapter for View mode interaction and
+  SUPPLY-GENERIC-POINTER-UP-FUNCTION
+
+/usr1/lisp/scribe/hemimpl.mss, 15-May-89 17:40:09, Edit by Chiles.
+  Added new Miscellaneous chapter.
+
+/usr1/lisp/scribe/hemuser.mss, 15-May-89 14:14:37, Edit by Chiles.
+  Modified "View" mode section.
+
diff --git a/docs/hem/hem.dict b/docs/hem/hem.dict
new file mode 100644
index 000000000..312c9d225
--- /dev/null
+++ b/docs/hem/hem.dict
@@ -0,0 +1,446 @@
+NEWLINE
+WHITESPACE
+MISINTERPRETED
+ENDCOMMANDS
+RUBOUT
+COMMANDBODY
+DEFCOMMAND
+ENDDEFCOMMAND
+ALT
+BF
+LINEFEED
+TRANSPOSITION
+SPICETITLEPAGE
+CONTENTSMACROS
+TIMESROMANKERN
+NEWFACECODE
+COPYFONT
+PRESSFILE
+BINDINGFONT
+TIMESROMAN
+SUBSTITUTECHAR
+ASSOCFONT
+SETFONTINFO
+STANDARDR
+STANDARDBBI
+SSF
+HELVETICA
+BOLDPAGENO
+PAGENO
+BEGINENTRY
+TABCLEAR
+TABSET
+EXTRALEFTMARGIN
+ENDENTRY
+ININIT
+COMMANDENV
+CM
+COMMANDTEXT
+LEFTMARGIN
+RIGHTMARGIN
+ARGS
+TABDIVIDE
+CHPGNO
+NCONV
+CHAPTERNO
+CHAPID
+PAGEHEADING
+BORDERSTYLE
+SPICETP
+MACLACHLAN
+ABS
+WHIZZY
+SCREENFULL
+REF
+RIGHTDOWN
+LEFTDOWN
+MIDDLEDOWN
+MIDDLEUP
+BIZZARE
+FORMFEED
+NEWLINES
+UN
+YANKS
+YANKED
+OOPS
+TYPOS
+LOWERCASE
+UPPERCASE
+TRANSPOSING
+TRANSPOSE
+EMACS
+UNINITIATED
+TRANSPOSITIONS
+TRANSPOSES
+LF
+PAREN
+COMMANDEND
+BOYER
+MOORE
+UNREADING
+FOO
+FILENAME
+BUFFER'S
+SYS
+TECO
+PROGRAMEXAMPLE
+TRASHED
+SEMI
+PATHNAME
+UPD
+SRCCOM
+LOSSAGE
+DEFUN
+PARENS
+DEFSTRUCT
+DEFMACRO
+UNREADABLE
+ED
+RECOMPILATION
+RECOMPILE
+SFASL
+EVAL
+UNDAMAGED
+NEWPAGE
+INDEXINCLUDE
+NLM
+EMS
+RLM
+CENUMERATE
+LEFTMPOSN
+BULLETPOSN
+NRM
+CDESCRIPTION
+RRM
+DEFHVAR
+ENDDEFHVAR
+HVAR
+SLISP
+PICE
+ISP
+CLISP
+OMMON
+MACS
+DOC
+PORTED
+ZWEI
+'S
+BLOTCH
+PERQ
+META
+KEYPAD
+LEFTUP
+COMMAND
+'S
+FACECODE
+VARS
+SOS
+MODELESS
+MODELINE
+MSS
+UNDERRATED
+MALCOORDINATION
+RIGHTARROW
+LEFTARROW
+DOWNARROW
+UPARROW
+SPASTIC
+EOF
+PATHNAMES
+GAZONK
+DEL
+IO
+INOPERATIVE
+TYPESCRIPT
+KEYTRAN
+REDIRECTED
+BACKTRACE
+CONDITIONALIZE
+INIT
+'HEMLOCK
+SETV
+DEFINDENT
+ABBREVIATORY
+NEUTRALIZES
+UNEXPAND
+RESYNCHRONIZING
+FORMFEEDS
+COMMAND'S
+HEMLOCKMAN
+READDEFS
+RESHAPE
+IDIOM
+CURVACEOUS
+PERCENTAGEWISE
+ABBREVS
+ABBREV
+PROB
+BINARIES
+ENDDEFVAR
+FEEP
+KWD
+DEFUNS
+VAL
+DEFCOM
+ENDDEFCOM
+LLISP
+REBINDS
+TYPESCRIPTS
+SYNTAXES
+COMREF
+MAKUNBOUND
+DEFVAR
+ENDDEFUN
+VAR
+ARGS
+DEFUN
+DEFVAR
+ENDDEFVAR
+CHECKIN
+EXT
+GETSTRING
+CLRSTRING
+HASHTABLES
+TYPEOUT
+ERRORP
+REPROMPT
+DOLIST
+CURSORPOS
+RECENTERING
+MACREF
+ZEROP
+UNSHADOW
+MOD
+DEFATTRIBUTE
+ADA
+INTERNING
+MOREKEYS
+CLEANUP
+DEFMODE
+FUNCALLS
+MGROUP
+HLET
+ENDDEFCON
+DEFCON
+UPCASE
+'STRING
+UPPERCASED
+NINSERT
+FUNLABEL
+EQ
+VARREF
+TRUENAME
+HVARREF
+FUNREF
+ENDLISP
+MIN
+ENDDEFMAC
+MOPT
+POS
+MSTAR
+DEFMAC
+'TH
+MARK'S
+CHARPOS
+EQL
+LINE'S
+REMF
+PUTF
+GETF
+PLIST
+SETF
+MULTICS
+WHOLEY
+SKEF
+UTTIR
+SINGLESIDED
+HYPHENATION
+NAMESTRING
+NAMESTRINGS
+FASL
+DEF
+DEFANYTHING
+CRYPTIC
+WILDCARDS
+FILESYSTEM
+PAGEREF
+XTERM
+TERMCAP
+UNIX
+LIB
+MISC
+VERBATIM
+MODELINES
+PIXELS
+BITMAP
+WORKSTATION
+USR
+COM
+PREFIXING
+HYPER
+CRUFT
+LIBRARYFILE
+FONTFAMILY
+STRINGMAX
+BEEPING
+AUTORAISE
+TELNET
+SLAVE'S
+SERVER'S
+PREPENDING
+OFFLOADING
+ICONIFY
+LPR
+INFO
+CHECKPOINTED
+ROBERT
+MUNGING
+DEACTIVATED
+EPHEMERALLY
+DEACTIVATE
+HQB
+MODELINEP
+RINGP
+SUBTYPES
+SUBTYPE
+MSTAR'
+WINDOWP
+COMMANDP
+MOR
+GTR
+GEQ
+NEQ
+LEQ
+LSS
+FIELD'S
+WINDOWS'
+BUFFERS'
+BUFFERP
+DEACTIVATES
+REGIONP
+MARKP
+LINEP
+COMMANDSTRING
+DOD
+RESEARCHCREDIT
+CS
+CMU
+CHILES
+BLANKSPACE
+TITLEBOX
+TITLEPAGE
+REPORTTITLE
+ARPACREDIT
+DOUBLESIDED
+UNDOABLE
+LISPS
+CLX
+SPEC
+DISASSOCIATED
+MAILERS
+RAND
+AFS
+SUPFILE
+STEPPENWOLF
+GPA
+CRYPT
+HOSTBASE
+LOGIN
+RT'S
+FRAME'S
+ARPANET
+SETENV
+FORWCOMPS
+REPLCOMPS
+RMMPROC
+RM
+FORMFILE
+NOCC
+FCC
+REPL
+PREVS
+RFSLINK
+HOSTNAME
+XBIFF
+RFS
+GROUPNAME
+ACCOUNTNAME
+BLURBS
+WORKSTATION'S
+PROFILENAME
+USERNAME
+MAILDROP
+MACHINENAME
+WORKSTATIONS
+HEADERS'
+LISPY
+FIELDS'
+INBOX
+ANNO
+NOTATING
+MH
+ID
+MH'S
+MSGS
+EXP
+CC
+DATEFIELD
+BB
+MSG
+FOLDER'S
+COMP
+FORW
+DRAFTFOLDER
+DRAFTMESSAGE
+INC
+HEMLOCKDELETED
+RMM
+NOTATED
+UNDELETE
+ID'S
+RMF
+REFILE
+REFILING
+REFILED
+DEACTIVATING
+UNKILL
+ZERO'TH
+DIR
+VS
+KEYSYM
+KEYCODE
+XLIB
+KEYSYM'S
+FORWARDP
+HI
+ISPELL
+LEN
+LISP'S
+TWIDDLE
+RIGHTUP
+HEMUSER
+MACROEXPAND
+UNPROVIDED
+DIRED
+WILDCARD
+UNDELETING
+TXT
+PATHNAME'S
+SUBDIRECTORIES
+SUBDIRECTORY
+FILENAMES
+BUFED
+HINIT
+WINDOWING
+UNSUPPLIED
+CALLABLE
+'ABLE
+OP
+FORGOES
+AUX
+'RESCHEDULE
+'CHECK
+'REMOVE
+BITCHFUCKSALL
+SUBPROCESS
+KEYSYMS
diff --git a/docs/hem/user/commands.mss b/docs/hem/user/commands.mss
new file mode 100644
index 000000000..7d547bd04
--- /dev/null
+++ b/docs/hem/user/commands.mss
@@ -0,0 +1,822 @@
+@comment{-*- Dictionary: hem; Mode: spell; Package: Hemlock -*-}
+@chap[Basic Commands]
+@section[Motion Commands]
+
+@index[commands, basic]@index[motion]There is a fairly small number of
+basic commands for moving around in the buffer.  While there are many other
+more complex motion commands, these are by far the most commonly used and
+the easiest to learn.
+
+@defcom[com "Forward Character", bind (C-f, Rightarrow)]
+@defcom1[com "Backward Character", bind (C-b, Leftarrow)]
+@index[character, motion]
+@hid[Forward Character] moves the point forward by one character.  If a prefix
+argument is supplied, then the point is moved by that many characters.
+@hid[Backward Character] is identical, except that it moves the point
+backwards.
+@enddefcom
+
+@defcom[com "Forward Word", bind {M-f}]
+@defcom1[com "Backward Word", bind {M-b}]
+@index[word, motion]These commands move the point forward and backward
+over words.  The point is always left between the last word and first
+non-word character in the direction of motion.  This means that after moving
+backward the cursor appears on the first character of the word, while after
+moving forward, the cursor appears on the delimiting character.  Supplying
+a prefix argument moves the point by that many words.
+@enddefcom
+
+@defcom[com "Next Line", bind (C-n, Downarrow)]
+@defcom1[com "Previous Line", bind (C-p, Uparrow)]
+@defcom1[com "Goto Absolute Line"]
+@index[line, motion]
+@hid[Next Line] and @hid[Previous Line] move to adjacent lines, while remaining
+the same distance within a line.  Note that this motion is by logical lines,
+each of which may take up many lines on the screen if it wraps.  If a prefix
+argument is supplied, then the point is moved by that many lines.
+
+The position within the line at the start is recorded, and each successive
+use of @binding[C-p] or @binding[C-n] attempts to move the point to that
+position on the new line.  If it is not possible to move to the recorded
+position because the line is shorter, then the point is left at the end of
+the line.
+
+@hid[Goto Absolute Line] moves to the indicated line, as if you counted them
+starting at the beginning of the buffer with number one.  If the user supplies
+a prefix argument, it is the line number; otherwise, @Hemlock prompts the user
+for the line.
+@enddefcom
+
+@defcom[com "End of Line", bind {C-e}]
+@defcom1[com "Beginning of Line", bind {C-a}]
+@hid[End of Line] moves the point to the end of the current line, while 
+@hid[Beginning of Line] moves to the beginning.  If a prefix argument is
+supplied, then the point is moved to the end or beginning of the line that
+many lines below the current one.
+@enddefcom
+
+@defcom[com "Scroll Window Down", bind {C-v}]
+@defcom1[com "Scroll Window Up", bind {M-v}]
+@index[scrolling]
+@hid[Scroll Window Down] moves forward in the buffer by one screenful of text,
+the exact amount being determined by the size of the window.  If a prefix
+argument is supplied, then this scrolls the screen that many lines.  When this
+action scrolls the line with the point off the screen, it this command moves
+the point to the vertical center of the window.  @hid[Scroll Window Up] is
+identical to @hid[Scroll Window Down], except that it moves backwards.
+@enddefcom
+
+@defhvar[var "Scroll Overlap", val {2}]
+This variable is used by @hid[Scroll Window Down] and @hid[Scroll Window Up] to
+determine the number of lines by which the new and old screen should overlap.
+@enddefhvar
+
+@defcom[com "End of Buffer", bind (M-<)]
+@defcom1[com "Beginning of Buffer", bind (@bf[M->])]
+These commands are used to conveniently get to the very beginning and end of the
+text in a buffer.  Before the point is moved, its position is saved by
+pushing it on the mark stack (see page @pageref[marks]).
+@enddefcom
+
+@defcom[com "Top of Window", bind (M-,)]
+@defcom1[com "Bottom of Window", bind (M-.)]
+@index[window, motion]@hid[Top of Window] moves the point to the beginning of
+the first line displayed in the current window.  @hid[Bottom of Window] moves
+to the beginning of the last line displayed.
+@enddefcom
+
+
+@section[The Mark and The Region]
+
+@label[marks]@index[marks]@index[region]@index[selection]Each buffer has a
+distinguished position known as the @i[mark].  The mark initially points to the
+beginning of the buffer.  The area between the mark and the point is known as
+the @i[region].  Many @hemlock commands which manipulate large pieces of text
+use the text in the region.  To use these commands, one must first use some
+command to mark the region.
+
+@index[active regions]Although the mark is always pointing somewhere (initially
+to the beginning of the buffer), region commands insist that the region be made
+@i[active] before it can be used.  This prevents accidental use of a region
+command from mysteriously mangling large amounts of text.
+
+@defhvar[var "Active Regions Enabled", val {t}]
+When this variable is true, region commands beep unless the region is active.
+This may be set to @false for more traditional @emacs region semantics.
+@enddefhvar
+
+Once a marking command makes the region active, it remains active until:
+@begin[itemize]
+a command uses the region,
+
+a command modifies the buffer,
+
+a command changes the current window or buffer,
+
+a command signals an editor error,
+
+or the user types @binding[C-g].
+@end[itemize]
+Motion commands have the effect of redefining the region, since they move the
+point and leave the region active.
+
+@index[ephemerally active regions]Commands that insert a large chunk of
+text into the buffer usually set an @i[ephemerally active] region around
+the inserted text.  An ephemerally active region is always deactivated by
+the next command, regardless of the kind of command.  The ephemerally
+active region allows an immediately following region command to manipulate
+the inserted text, but doesn't persist annoyingly.  This is also very
+useful with active region highlighting, since it visibly marks the inserted
+text.
+
+
+@defhvar[var "Highlight Active Region", val {t}]
+@defhvar1[var "Active Region Highlighting Font", val {nil}]
+When @hid[Highlight Active Region] is true, @hemlock displays the text in the
+region in a different font whenever the region is active.  This provides a
+visible indication of what text will be manipulated by a region command.
+Active region highlighting is only supported under @windows.
+
+@hid[Active Region Highlighting Font] is the name of the font to use for active
+region highlighting.  If unspecified, @hemlock uses an underline font.
+@enddefhvar
+
+
+@defcom[com "Set/Pop Mark", bind (C-@@)]
+This command moves the mark to the point (saving the old mark on the mark
+stack) and activates the region.  After using this command to mark one end of
+the region, use motion commands to move to the other end, then do the region
+command.  This is the traditional @emacs marking command; when running under a
+windowing system with mouse support, it is usually easier to use the mouse with
+the @comref[Point to Here] and @comref[Generic Pointer Up].
+
+For historical reasons, the prefix argument causes this command to do things
+that are distinct commands in @Hemlock.  A prefix argument of four does
+@hid[Pop and Goto Mark], and a prefix argument of @f[16] does
+@hid[Pop Mark].
+@enddefcom
+
+@defcom[com "Mark Whole Buffer", bind (C-x h)]
+@defcom1[com "Mark to Beginning of Buffer", bind (C-<)]
+@defcom1[com "Mark to End of Buffer", bind (C->)]
+@hid[Mark Whole Buffer] sets the region around the whole buffer, with the point
+at the beginning and the mark at the end.  If a prefix argument is supplied,
+then the mark is put at the beginning and the point at the end.  The mark is
+pushed on the mark stack beforehand, so popping the stack twice will restore
+it.
+
+@hid[Mark to Beginning of Buffer] sets the current region from point to the
+beginning of the buffer.
+
+@hid[Mark to End of Buffer] sets the current region from the end of the buffer
+to point.
+@enddefcom
+
+@defcom[com "Activate Region", bind (C-x C-Space, C-x C-@@)]
+This command makes the region active, using whatever the current position of
+the mark happens to be.  This is useful primarily when the region is
+accidentally deactivated.
+@enddefcom
+
+
+@subsection[The Mark Stack]
+
+@index[mark stack]As was hinted at earlier, each buffer has a @i[mark stack],
+providing a history of positions in that buffer.  The current mark is the mark
+on the top of the stack; earlier values are recovered by popping the stack.
+Since commands that move a long distance save the old position on the mark
+stack, the mark stack commands are useful for jumping to interesting places in
+a buffer without having to do a search.
+
+@defcom[com "Pop Mark", bind (C-M-Space)]
+@defcom1[com "Pop and Goto Mark", bind (M-@@, M-Space)]
+@hid[Pop Mark] pops the mark stack, restoring the current mark to the next most
+recent value.  @hid[Pop and Goto Mark] also pops the mark stack, but instead of
+discarding the current mark, it moves the point to that position.  Both
+commands deactivate the region.
+@enddefcom
+
+@defcom[com "Exchange Point and Mark", bind (C-x C-x)]
+This command interchanges the position of the point and the mark, thus moving
+to where the mark was, and leaving the mark where the point was.  This command
+can be used to switch between two positions in a buffer, since repeating it
+undoes its effect.  The old mark isn't pushed on the mark stack, since it is
+saved in the point.
+@enddefcom
+
+
+@subsection[Using The Mouse]
+
+@index[mouse]It can be convenient to use the mouse to point to positions in
+text, especially when moving large distances.  @hemlock defines several
+commands for using the mouse.  These commands can only be used when running
+under @windows (see page @pageref[using-x].)
+
+@defcom[com "Here to Top of Window", bind (Rightdown)]
+@defcom1[com "Top Line to Here", bind (Leftdown)]
+@index[window, motion]@hid[Here to Top of Window] scrolls the window so as to
+move the line which is under the mouse cursor to the top of the window.  This
+has the effect of moving forward in the buffer by the distance from the top of
+the window to the mouse cursor.  @hid[Top Line to Here] is the inverse
+operation, it scrolls backward, moving current the top line underneath the
+mouse.
+
+If the mouse is near the left edge of a window, then these commands do smooth
+scrolling.  @hid[Here To Top of Window] repeatedly scrolls the window up by one
+line until the mouse button is released.  Similarly, @hid[Top Line to Here]
+smoothly scrolls down.
+@enddefcom
+
+@defcom[com "Point to Here", bind (Middledown, S-Leftdown)]
+This command moves the point to the position of the mouse, changing to a
+different window if necessary.
+
+When used in a window's modeline, this moves the point of the window's buffer
+to the position within the file that is the same percentage, start to end, as
+the horizontal position of the mouse within the modeline.  This also makes this
+window current if necessary.
+
+This command supplies a function @hid[Generic Pointer Up] invokes if it runs
+without any intervening generic pointer up predecessors executing.  If the
+position of the pointer is different than the current point when the user
+invokes @hid[Generic Pointer Up], then this function pushes a buffer mark at
+point and moves point to the pointer's position.  This allows the user to mark
+off a region with the mouse.
+@enddefcom
+
+@defcom[com "Generic Pointer Up", bind (Middleup, S-Leftup)]
+Other commands determine this command's action by supplying functions that
+this command invokes.  The following built-in commands supply the following
+generic up actions:
+@Begin[Description]
+@hid[Point to Here]@\
+ When the position of the pointer is different than the current point, the
+action pushes a buffer mark at point and moves point to the pointer's position.
+
+@hid[Bufed Goto and Quit]@\
+ The action is a no-op.
+@End[Description]
+@enddefcom
+
+@defcom[com "Insert Kill Buffer", bind (S-Rightdown)]
+This command is a combination of @hid[Point to Here] and @comref[Un-Kill].  It
+moves the point to the mouse location and inserts the most recently killed
+text.
+@enddefcom
+
+
+@section[Modification Commands]
+@index[commands, modification]
+
+There is a wide variety of basic text-modification commands, but once again the
+simplest ones are the most often used.
+
+@subsection[Inserting Characters]
+@index[character, insertion]
+@index[insertion, character]
+
+In @hemlock, you can insert characters with graphic representations by typing
+the corresponding key-event which you normally generate with the obvious
+keyboard key.  You can only insert characters whose codes correspond to ASCII
+codes.  To insert those without graphic representations, use @hid[Quoted
+Insert].
+
+@defcom[com "Self Insert"]
+@hid[Self Insert] inserts into the buffer the character corresponding to the
+key-event typed to invoke the command.  This command is normally bound to all
+such key-events @binding[Space].  If a prefix argument is supplied, then this
+inserts the character that many times.
+@enddefcom
+
+@defcom[com "New Line", bind (Return)]
+This command, which has roughly the same effect as inserting a @bf[Newline],
+is used to move onto a new blank line.  If there are at least two blank
+lines beneath the current one then @binding[Return] cleans off any
+whitespace on the next line and uses it, instead of inserting a newline.
+This behavior is desirable when inserting in the middle of text, because
+the bottom half of the screen does not scroll down each time @hid[New Line]
+is used.
+@enddefcom
+
+@defcom[com "Quoted Insert", bind {C-q}]
+Many key-events have corresponding ASCII characters, but these key-events are
+bound to commands other than @hid[Self Insert].  Sometimes they are otherwise
+encumbered such as with @binding[C-g].  @hid[Quoted Insert] prompts for a
+key-event, without any command interpretation semantics, and inserts the
+corresponding character.  If the appropriate character has some code other than
+an ASCII code, this will beep and abort the command.  A common use for this
+command is inserting a @bf[Formfeed] by typing @binding[C-q C-l].  If a prefix
+argument is supplied, then the character is inserted that many times.
+@enddefcom
+
+@defcom[com "Open Line", bind {C-o}]
+This command inserts a newline into the buffer without moving the point.
+This command may also be given a prefix argument to insert a number of
+newlines, thus opening up some room to work in the middle of a screen of
+text.  See also @comref[Delete Blank Lines].
+@enddefcom
+
+
+@subsection[Deleting Characters]
+@index[deletion, character]
+@index[character, deletion]
+There are a number of commands for deleting characters as well.
+
+@defhvar[var "Character Deletion Threshold", val {5}]
+If more than this many characters are deleted by a character deletion command,
+then the deleted text is placed in the kill ring.
+@enddefhvar
+
+@defcom[com "Delete Next Character", bind {C-d}]
+@defcom1[com "Delete Previous Character", bind (Delete, Backspace)]
+@hid[Delete Next Character] deletes the character immediately following the
+point, that is, the character which appears under the cursor.  When given a
+prefix argument, @binding[C-d] deletes that many characters after the
+point.  @hid[Delete Previous Character] is identical, except that it
+deletes characters before the point.
+@enddefcom
+
+@defcom[com "Delete Previous Character Expanding Tabs"]
+@hid[Delete Previous Character Expanding Tabs] is identical to
+@hid[Delete Previous Character], except that it treats tabs as the
+equivalent number of spaces.  Various language modes that use tabs for
+indentation bind @binding[Delete] to this command.
+@enddefcom
+
+
+@subsection[Killing and Deleting]
+
+@index[killing]@index[cutting]@index[pasting]@index[kill ring]@hemlock has many
+commands which kill text.  Killing is a variety of deletion which saves the
+deleted text for later retrieval.  The killed text is saved in a ring buffer
+known as the @i[kill ring].  Killing has two main advantages over deletion:
+@begin[enumerate]
+If text is accidentally killed, a not uncommon occurrence, then it can be
+restored.
+
+Text can be moved from one place to another by killing it and then
+restoring it in the new location.
+@end[enumerate]
+
+Killing is not the same as deleting.  When a command is said to delete
+text, the text is permanently gone and is not pushed on the kill ring.
+Commands which delete text generally only delete things of little
+importance, such as single characters or whitespace.
+
+@subsection[Kill Ring Manipulation]
+@defcom[com "Un-Kill", bind {C-y}]
+@index[kill ring, manipulation]This command "yanks" back the most
+recently killed piece of text, leaving the mark before the inserted text
+and the point after.  If a prefix argument is supplied, then the text that
+distance back in the kill ring is yanked.
+@enddefcom
+
+@defcom[com "Rotate Kill Ring", bind {M-y}]
+This command rotates the kill ring forward, replacing the most recently
+yanked text with the next most recent text in the kill ring. @binding[M-y]
+may only be used immediately after a use of @binding[C-y] or a previous
+use of @binding[M-y].  This command is used to step back through the text
+in the kill ring if the desired text was not the most recently killed, and
+thus could not be retrieved directly with a @binding[C-y].  If a prefix
+argument is supplied, then the kill ring is rotated that many times.
+@enddefcom
+
+@defcom[com "Kill Region", bind {C-w}]
+@index[region, killing]This command kills the text between the point and
+mark, pushing it onto the kill ring.  This command is usually the best way
+to move or remove large quantities of text.
+@enddefcom
+
+@defcom[com "Save Region", bind {M-w}]
+This command pushes the text in the region on the kill ring, but doesn't
+actually kill it, giving an effect similar to typing @binding[C-w C-y].
+This command is useful for duplicating large pieces of text.
+@enddefcom
+
+@subsection[Killing Commands]
+
+@index[commands, killing]Most commands which kill text append into the
+kill ring, meaning that consecutive uses of killing commands will insert
+all text killed into the top entry in the kill ring.  This allows large
+pieces of text to be killed by repeatedly using a killing command.
+
+@defcom[com "Kill Line", bind {C-k}]
+@defcom1[com "Backward Kill Line"]
+@index[line, killing]@hid[Kill Line] kills the text from the point to the
+end of the current line, deleting the line if it is empty.  If a prefix
+argument is supplied, then that many lines are killed.  Note that a prefix
+argument is not the same as a repeat count.
+
+@hid[Backward Kill Line] is similar, except that it kills from the point to the
+beginning of the line.  If it is called at the beginning of the line, it kills
+the newline and any trailing whitespace on the previous line.  With a prefix
+argument, this command is the same as @hid[Kill Line] with a negated argument.
+@enddefcom
+
+@defcom[com "Kill Next Word", bind {M-d}]
+@defcom1[com "Kill Previous Word", bind (M-Backspace, M-Delete)]
+@index[word, killing]@hid[Kill Next Word] kills from the point to the end
+of the current or next word.  If a prefix argument is supplied, then that
+many words are killed.  @hid[Kill Previous Word] is identical, except that
+it kills backward.
+@enddefcom
+
+@subsection[Case Modification Commands]
+
+@index[case modification]@hemlock provides a few case modification
+commands, which are often useful for correcting typos.
+
+@defcom[com "Capitalize Word", bind {M-c}]
+@defcom1[com "Lowercase Word", bind {M-l}]
+@defcom1[com "Uppercase Word", bind {M-u}]
+@index[word, case modification]These commands modify the case of the
+characters from the point to the end of the current or next word, leaving
+the point after the end of the word affected.  A positive prefix argument
+modifies that many words, moving forward.  A negative prefix argument
+modifies that many words before the point, but leaves the point unmoved.
+@enddefcom
+
+@defcom[com "Lowercase Region", bind (C-x C-l)]
+@defcom1[com "Uppercase Region", bind (C-x C-u)]
+@index[region, case modification]These commands case-fold the text in the
+region.  Since these commands can damage large amounts of text, they ask for
+confirmation before modifying large regions and can be undone with @hid[Undo].
+@enddefcom
+
+@subsection[Transposition Commands]
+
+@index[transposition]@index[commands, transposition]@hemlock provides a
+number of transposition commands.  A transposition command swaps the
+"things" before and after the point and moves forward one "thing".  Just
+how a "thing" is defined depends on the particular transposition command.
+Transposition commands, particularly
+@hid[Transpose Characters] and @hid[Transpose Words], are useful for
+correcting typos.  More obscure transposition commands can be used to amaze
+your friends and demonstrate your immense knowledge of exotic @emacs
+commands.
+
+To the uninitiated, the behavior of transposition commands may seem mysterious;
+this has led some implementors to attempt to improve the definition of
+transposition, but right-thinking people will accept no substitutes.  The
+@emacs transposition definition used in @hemlock has two useful properties:
+@begin[enumerate]
+Repeated applications of a transposition command have a useful effect.  The
+way to visualize this effect is that each use of the transposition command
+drags the previous thing over the next thing.  It is possible to correct
+double transpositions easily using @hid[Transpose Characters].
+
+Transposition commands move backward with a negative prefix argument, thus
+undoing the effect of the equivalent positive argument.
+@end[enumerate]
+
+@defcom[com "Transpose Characters", bind {C-t}]
+@index[character, transposition]This command exchanges the characters on
+either side of the point and moves forward, unless at the end of a line, in
+which case it transposes the previous two characters without moving.
+@enddefcom
+
+@defcom[com "Transpose Lines", bind (C-x C-t)]
+@index[line, transposition]This command transposes the previous and
+current line, moving down to the next line.  With a zero argument, it
+transposes the current line and the line the mark is on.
+@enddefcom
+
+@defcom[com "Transpose Words", bind {M-t}]
+@index[word, transposition]This command transposes the previous word and
+the current or next word.
+@enddefcom
+
+
+@defcom[com "Transpose Regions", bind (C-x t)]
+This command transposes two regions with endpoints defined by the mark stack
+and point.  To use this command, place three marks (in order) at the start and
+end of the first region, and at the start of the second region, then place the
+point at the end of the second region.  Unlike the other transposition
+commands, a second use will simply undo the effect of the first use, and to do
+even this, you must reactivate the current region.
+@enddefcom
+
+
+@subsection[Whitespace Manipulation]
+These commands change the amount of space between words.  See also the
+indentation commands in section @ref[indentation].
+
+@defcom[com "Just One Space", bind (M-|)]
+@index[whitespace, manipulation]@index[indentation, manipulation]This
+command deletes all whitespace characters before and after the point and then
+inserts one space.  If a prefix argument is supplied, then that number of
+spaces is inserted.
+@enddefcom
+
+@defcom[com "Delete Horizontal Space", bind (M-\)]
+This command deletes all blank characters around the point.
+@enddefcom
+
+@defcom[com "Delete Blank Lines", bind (C-x C-o)]
+This command deletes all blank lines surrounding the current line, leaving the
+point on a single blank line.  If the point is already on a single blank line,
+then that line is deleted.  If the point is on a non-blank line, then all blank
+lines immediately following that line are deleted.  This command is often used
+to clean up after @comref[Open Line].
+@enddefcom
+
+@section[Filtering]
+
+@i[Filtering] is a simple way to perform a fairly arbitrary transformation
+on text.  Filtering text replaces the string in each line with the result
+of applying a @llisp function of one argument to that string.  The function must 
+neither destructively modify the argument nor the return value.  It is an
+error for the function to return a string containing newline characters.
+
+@defcom[com "Filter Region"]
+This function prompts for an expression which is evaluated to obtain a
+function to be used to filter the text in the region.  For example, to
+capitalize all the words in the region one could respond:
+@begin[programexample]
+Function: #'@comment<>string-capitalize
+@end[programexample]
+Since the function may be called many times, it should probably be
+compiled.  Functions for one-time use can be compiled using the compile
+function as in the following example which removes all the semicolons on any line
+which contains the string "@f[PASCAL]":
+@begin[programexample]
+Function: (compile nil '(lambda (s)
+			  (if (search "PASCAL" s)
+			      (remove #\; s)
+			      s)))
+@end[programexample]
+@enddefcom
+
+@section[Searching and Replacing]
+@index[searching]@index[replacing]
+Searching for some string known to appear in the text is a commonly used method
+of moving long distances in a file.  Replacing occurrences of one pattern with
+another is a useful way to make many simple changes to text.  @hemlock provides
+powerful commands for doing both of these operations.
+
+@defhvar[var "String Search Ignore Case", val {t}]
+@index[case sensitivity]
+This variable determines the kind of search done by searching and replacing
+commands.  
+@enddefhvar
+
+@defcom[com "Incremental Search", bind {C-s}]
+@defcom1[com "Reverse Incremental Search", bind {C-r}]
+@hid[Incremental Search] searches for an occurrence of a string after the
+current point.  It is known as an incremental search because it reads
+key-events form the keyboard one at a time and immediately searches for the
+pattern of corresponding characters as you type.  This is useful because
+it is possible to initially type in a very short pattern and then add more
+characters if it turns out that this pattern has too many spurious matches.
+
+This command dispatches on the following key-events as sub-commands:
+@begin[description]
+@binding[C-s]@\
+ Search forward for an occurrence of the current pattern.  This can be used
+repeatedly to skip from one occurrence of the pattern to the next, or it can be
+used to change the direction of the search if it is currently a reverse search.
+If @binding[C-s] is typed when the search string is empty, then a search is
+done for the string that was used by the last searching command.
+
+@binding[C-r]@\
+ Similar to @binding[C-s], except that it searches backwards.
+
+@binding[Delete, Backspace]@\
+ Undoes the effect of the last key-event typed.  If that key-event simply added
+to the search pattern, then this removes the character from the pattern, moving
+back to the last match found before entering the removed character.  If the
+character was a @binding[C-s] or @binding[C-r], then this moves back to the
+previous match and possibly reverses the search direction.
+
+@binding[C-g]@\
+ If the search is currently failing, meaning that there is no occurrence of the
+search pattern in the direction of search, then @binding[C-g] deletes enough
+characters off the end of the pattern to make it successful.  If the search
+is currently successful, then @binding[C-g] causes the search to be aborted,
+leaving the point where it was when the search started.  Aborting the search
+inhibits the saving of the current search pattern as the last search string.
+
+@binding[Escape]@\
+ Exit at the current position in the text, unless the search string is empty,
+in which case a non-incremental string search is entered.
+
+@binding[C-q]@\
+ Search for the character corresponding to the next key-event, rather than
+treating it as a command.
+@end[description]
+Any key-event not corresponding to a graphic character, except those just
+described, causes the search to exit.  @hemlock then uses the key-event in it
+normal command interpretation.
+
+For example, typing @binding[C-a] will exit the search @i[and] go to the
+beginning of the current line.  When either of these commands successfully
+exits, they push the starting position (before the search) on the mark stack.
+If the current region was active when the search started, this foregoes pushing
+a mark.
+@enddefcom
+
+@defcom[com "Forward Search", bind (M-s)]
+@defcom1[com "Reverse Search", bind (M-r)]
+These commands do a normal dumb string search, prompting for the search
+string in a normal dumb fashion.  One reason for using a non-incremental
+search is that it may be faster since it is possible to specify a long
+search string from the very start.  Since @hemlock uses the Boyer--Moore
+search algorithm, the speed of the search increases with the size of the
+search string.
+When either of these commands successfully exits, they push the starting
+position (before the search) on the mark stack.  This is inhibited when the
+current region is active.
+@enddefcom
+
+@defcom[com "Query Replace", bind (M-%)]
+This command prompts in the echo area for a target string and a replacement
+string.  It then searches for an occurrence of the target after the point.
+When it finds a match, it prompts for a key-event indicating what action to
+take.  The following are valid responses:
+@begin[description]
+@binding[Space, y]@\
+ Replace this occurrence of the target with the replacement string, and search
+again.
+
+@binding[Delete, Backspace, n]@\
+ Do not replace this occurrence, but continue the search.
+
+@binding[!]@\
+ Replace this and all remaining occurrences without prompting again.
+
+@binding[.]@\
+ Replace this occurrence and exit.
+
+@binding[C-r]@\
+ Go into a recursive edit (see page @pageref[recursive-edits]) at the current
+location.  The search will be continued from wherever the point is left when
+the recursive edit is exited.  This is useful for handling more complicated
+cases where a simple replacement will not achieve the desired effect.
+
+@binding[Escape]@\
+ Exit without doing any replacement.
+
+@binding[Home, C-_, ?, h]@\
+ Print a list of all the options available.
+@end[description]
+Any other key-event causes the command to exit, returning the key-event to the
+input stream; thus, @hemlock will interpret it normally for a command binding.
+
+When the current region is active, this command uses it instead of the region
+from point to the end of the buffer.  This is especially useful when you expect
+to use the @binding[!] option.
+
+If the replacement string is all lowercase, then a heuristic is used that
+attempts to make the case of the replacement the same as that of the
+particular occurrence of the target pattern.  If "@f[foo]" is being
+replaced with "@f[bar]" then "@f[Foo]" is replaced with "@f[Bar]" and
+"@f[FOO]" with "@f[BAR]".
+
+This command may be undone with @hid[Undo], but its undoing may not be undone.
+On a successful exit from this command, the starting position (before the
+search) is pushed on the mark stack.
+@enddefcom
+
+@defhvar[var "Case Replace", val {t}]
+@index[case sensitivity]
+If this variable is true then the case preserving heuristic in
+@hid[Query Replace] is enabled, otherwise all replacements are done with
+the replacement string exactly as specified.
+@enddefhvar
+
+@defcom[com "Replace String"]
+This command is the same as @hid[Query Replace] except it operates without ever
+querying the user before making replacements.  After prompting for a target and
+replacement string, it replaces all occurrences of the target string following
+the point.  If a prefix argument is specified, then only that many occurrences
+are replaced.  When the current region is active, this command uses it instead
+of the region from point to the end of the buffer.
+@enddefcom
+
+@defcom[com "List Matching Lines"]
+This command prompts for a search string and displays in a pop-up window all
+the lines containing the string that are after the point.  If a prefix argument
+is specified, then this displays that many lines before and after each matching
+line.  When the current region is active, this command uses it instead of the
+region from point to the end of the buffer.
+@enddefcom
+
+@defcom[com "Delete Matching Lines"]
+@defcom1[com "Delete Non-Matching Lines"]
+@hid[Delete Matching Lines] prompts for a search string and deletes all lines
+containing the string that are after the point.  Similarly, @hid[Delete
+Non-Matching Lines] deletes all lines following the point that do not contain
+the specified string.  When the current region is active, these commands uses
+it instead of the region from point to the end of the buffer.
+@enddefcom
+
+
+@section[Page Commands]
+@index[page commands]
+Another unit of text recognized by @hemlock is the page.  A @i[page] is a piece
+of text delimited by formfeeds (@f[^L]'s.)  The first non-blank line after the
+page marker is the @i[page title].  The page commands are quite useful when
+logically distinct parts of a file are put on separate pages.  See also
+@comref[Count Lines Page].  These commands only recognize @f[^L]'s at the
+beginning of a lines, so those quoted in string literals do not get in the way.
+
+@defcom[com "Previous Page", bind (C-x @bf<]>)]
+@defcom1[com "Next Page", bind (C-x [)]
+@hid[Previous Page] moves the point to the previous page delimiter, while
+@hid[Next Page] moves to the next one.  Any page delimiters next to the point
+are skipped.  The prefix argument is a repeat count.
+@enddefcom
+
+@defcom[com "Mark Page", bind (C-x C-p)]
+This command puts the point at the beginning of the current page and the mark
+at the end.  If given a prefix argument, marks the page that many pages from the
+current one.
+@enddefcom
+
+@defcom[com "Goto Page"]
+This command does various things, depending on the prefix argument:
+@begin[description]
+@i[no argument]@\goes to the next page.
+
+@i[positive argument]@\goes to an absolute page number, moving that many pages
+from the beginning of the file.
+
+@i[zero argument]@\prompts for string and goes to the page with that string in
+its title.  Repeated invocations in this manner continue searching from the
+point of the last find, and a first search with a particular pattern pushes a
+buffer mark.
+
+@i[negative argument]@\moves backward by that many pages, if possible.
+@end[description]
+@enddefcom
+
+@defcom[com "View Page Directory"]
+@defcom1[com "Insert Page Directory"]
+@hid[View Page Directory] uses a pop-up window to display the number and title
+of each page in the current buffer.  @hid[Insert Page Directory] is the same
+except that it inserts the text at the beginning of the buffer.  With a prefix
+argument, @hid[Insert Page Directory] inserts at the point.
+@enddefcom
+
+
+@section[Counting Commands]
+
+@defcom[com "Count Words"]
+This command counts the number of words from the current point to the end of
+the buffer, displaying a message in the echo area.  When the current region is
+active, this uses it instead of the region from the point to the end of the
+buffer.  Word delimiters are determined by the current major mode.
+@enddefcom
+
+@defcom[com "Count Lines"]
+This command counts the number of lines from the current point to the end of
+the buffer, displaying a message in the echo area.  When the current region is
+active, this uses it instead of the region from the point to the end of the
+buffer.  
+@enddefcom
+
+@defcom[com "Count Lines Page", bind (C-x l)]
+This command displays the number of lines in the current page and the number of
+lines before and after the point within that page.  If given a prefix argument,
+the entire buffer is counted instead of just the current page.
+@enddefcom
+
+@defcom[com "Count Occurrences"]
+This command prompts for a search string and displays the number of occurrences
+of that string in the text from the point to the end of the buffer.  When the
+current region is active, this uses it instead of the region from the point to
+the end of the buffer.
+@enddefcom
+
+
+@section[Registers]
+@index[registers]
+Registers allow you to save a text position or chunk of text associated with a
+key-event.  This is a convenient way to repeatedly access a commonly-used
+location or text fragment.  The concept and key bindings should be familiar to
+TECO users.
+
+@defcom[com "Save Position", bind (C-x s)]
+@defcom1[com "Jump to Saved Position", bind (C-x j)]
+These commands manipulate registers containing textual positions.  
+@hid[Save Position] prompts for a register and saves the location of the
+current point in that register.  @hid[Jump to Saved Position] prompts for a
+register and moves the point to the position saved in that register.  If the
+saved position is in a different buffer, then that buffer is made current.
+@enddefcom
+
+@defcom[com "Put Register", bind (C-x x)]
+@defcom1[com "Get Register", bind (C-x g)]
+These commands manipulate registers containing text.  @hid[Put Register]
+prompts for a register and puts the text in the current region into the
+register.  @hid[Get Register] prompts for a register and inserts the text in
+that register at the current point.
+@enddefcom
+
+@defcom[com "List Registers"]
+@defcom1[com "Kill Register"]
+@hid[List Registers] displays a list of all the currently defined registers in
+a pop-up window, along with a brief description of their contents.  
+@hid[Kill Register] prompts for the name of a register and deletes that
+register.
+@enddefcom
diff --git a/docs/hem/user/intro.mss b/docs/hem/user/intro.mss
new file mode 100644
index 000000000..8049fc62f
--- /dev/null
+++ b/docs/hem/user/intro.mss
@@ -0,0 +1,1053 @@
+@comment{-*- Dictionary: bld:scribe/hem/hem; Mode: spell; Package: Hemlock -*-}
+@chap[Introduction]
+
+@hemlock is a text editor which follows in the tradition of @emacs
+and the Lisp Machine editor ZWEI.  In its basic form, @hemlock has almost
+the same command set as ITS/TOPS-20 @emacs@foot[In this document, "Emacs"
+refers to this, the original version, rather than to any of the large
+numbers of text editors inspired by it which may go by the same name.],
+and similar features such as multiple windows and extended commands, as
+well as built in documentation features.  The reader should bear in mind
+that whenever some powerful feature of @hemlock is described, it has
+probably been directly inspired by @emacs.
+
+This manual describes @hemlock@comment{}'s commands and other user visible
+features and then goes on to tell how to make simple customizations.  For
+complete documentation of the @hemlock primitives with which commands are
+written, the @i[Hemlock Command Implementor's Manual] is also available.
+
+@section[The Point and The Cursor]
+
+@index[point]@index[cursor]The @i[point] is the current focus of editing
+activity.  Text typed in by the user is inserted at the point.  Nearly all
+commands use the point as a indication of what text to examine or modify.
+Textual positions in @hemlock are between characters.  This may seem a bit
+curious at first, but it is necessary since text must be inserted between
+characters.  Although the point points between characters, it is sometimes said
+to point @i[at] a character, in which case the character after the point is
+referred to.
+
+The @i[cursor] is the visible indication of the current focus of attention: a
+rectangular blotch under @windows, or the hardware cursor on a terminal.  The
+cursor is usually displayed on the character which is immediately after the
+point, but it may be displayed in other places.  Wherever the cursor is
+displayed it indicates the current focus of attention.  When input is being
+prompted for in the echo area, the cursor is displayed where the input is to
+go.  Under @windows the cursor is only displayed when @hemlock is waiting
+for input.
+
+
+@section[Notation]
+
+There are a number of notational conventions used in this manual which need
+some explanation.
+
+
+@subsection[Key-events]
+
+@label[key-events]
+@index[key-events, notation]
+@index[bits, key-event]
+@index[modifiers, key-event]
+The canonical representation of editor input is a @i[key-event].  When you type
+on the keyboard, @hemlock receives key-events.  Key-events have names for their
+basic form, and we refer to this name as a @i[keysym].  This manual displays
+keysyms in a @bf[Bold] font.  For example, @bf[a] and @bf[b] are the keys that
+normally cause the editor to insert the characters @i[a] and @i[b].
+
+Key-events have @i[modifiers] or @i[bits] indicating a special interpretation
+of the root key-event.  Although the keyboard places limitations on what
+key-events you can actually type, @hemlock understands arbitrary combinations
+of the following modifiers: @i[Control], @i[Meta], @i[Super], @i[Hyper],
+@i[Shift], and @i[Lock].  This manual represents the bits in a key-event by
+prefixing the keysym with combinations of @bf[C-], @bf[M-], @bf[S-], @bf[H-],
+@bf[Shift-], and @bf[Lock].  For example, @bf[a] with both the control and meta
+bits set appears as @bf[C-M-a].  In general, ignore the shift and lock
+modifiers since this manual never talks about keysyms that explicitly have
+these bits set; that is, it may talk about the key-event @bf[A], but it would
+never mention @bf[Shift-a].  These are actually distinct key-events, but
+typical input coercion turns presents @hemlock with the former, not the latter.
+
+Key-event modifiers are totally independent of the keysym.  This may be new to
+you if you are used to thinking in terms of ASCII character codes.  For
+example, with key-events you can distinctly identify both uppercase and
+lowercase keysyms with the control bit set; therefore, @bf[C-a] and @bf[C-A]
+may have different meanings to @hemlock.
+
+Some keysyms' names consist of more than a single character, and these usually
+correspond to the legend on the keyboard.  For example, some keyboards let you
+enter @bf[Home], @bf[Return], @bf[F9], etc.
+
+In addition to a keyboard, you may have a mouse or pointer device.  Key-events
+also represent this kind of input.  For example, the down and up transitions of
+the @i[left button] correspond to the @bf[Leftdown] and @bf[Leftup] keysyms.
+
+See sections @ref[key-bindings], @ref[using-x], @ref[using-terminals]
+
+
+@subsection[Commands]
+
+@index[commands]@label[commands]Nearly everything that can be done in
+@hemlock is done using a command.  Since there are many things worth
+doing, @hemlock provides many commands, currently nearly two hundred.
+Most of this manual is a description of what commands exist, how they are
+invoked, and what they do.  This is the format of a command's
+documentation:
+
+@defcom[com "Sample Command", bind (C-M-q, C-`)]
+@begin[quotation, facecode i, leftmargin 8ems, rightmargin 3.5ems,
+below 0.8 lines]
+This command's name is @hid[Sample Command], and it is bound to
+@w(@bf(C-M-q)) and @bf[C-`], meaning that typing either of these will
+invoke it.  After this header comes a description of what the command does:
+@end[quotation]
+
+This command replaces all occurrences following the point of the string
+"@f[Pascal]" with the string "@f[Lisp]".  If a prefix argument is supplied,
+then it is interpreted as the maximum number of occurrences to replace.  If
+the prefix argument is negative then the replacements are done backwards
+from the point.
+@comment<
+@begin[quotation, facecode i, leftmargin 8ems, rightmargin 3.5ems,
+above 0.8 lines, below 0.8 lines]
+Toward the end of the description there may be information primarily of
+interest to customizers and command implementors.  If you don't understand
+this information, don't worry, the writer probably forgot to speak English.
+@end[quotation]
+
+@b[Arguments:]
+@begin[description]
+@i[target]@\The string to replace with "@f[Lisp]".
+
+@i[buffer]@\The buffer to do the replacement in.  If this is @f[:all] then
+the replacement is done in all buffers.
+@end[description]>
+@enddefcom
+
+
+@subsection[Hemlock Variables]
+
+@index[variables, hemlock]@hemlock variables supply a simple
+customization mechanism by permitting commands to be parameterized.  For
+details see page @pageref[vars].
+
+@defhvar[var "Sample Variable", val {36}]
+@begin[quotation, facecode i, leftmargin 8ems, below 0.8 lines]
+The name of this variable is @hid[Sample Variable] and its initial value is
+36.
+@end[quotation]
+This variable sets a lower limit on the number of replacements that be done
+by @hid[Sample Command].  If the prefix argument is supplied, and smaller
+in absolute value than @hid[Sample Variable], then the user is prompted as
+to whether that small a number of occurrences should be replaced, so as to
+avoid a possibly disastrous error.
+@enddefhvar
+
+
+@section[Invoking Commands]
+@index[invocation, command]
+In order to get a command to do its thing, it must be invoked.  The user can do
+this two ways, by typing the @i[key] to which the command is @i[bound] or by
+using an @i[extended command].  Commonly used commands are invoked via their
+key bindings since they are faster to type, while less used commands are
+invoked as extended commands since they are easier to remember.
+
+
+@subsection[Key Bindings]
+@index[bindings, key]
+@index[key bindings]
+@label[key-bindings]
+A key is a sequence of key-events (see section @ref[key-events]) typed on the
+keyboard, usually only one or two in length.  Sections @ref[using-x] and
+@ref[using-terminals] contain information on particular input devices.
+
+When a command is bound to a key, typing the key causes @hemlock to invoke the
+command.  When the command completes its job, @hemlock returns to reading
+another key, and this continually repeats.
+
+Some commands read key-events interpreting them however each command desires.
+When commands do this, key bindings have no effect, but you can usually abort
+@hemlock whenever it is waiting for input by typing @binding[C-g] (see section
+@ref[aborting]).  You can usually find out what options are available by typing
+@binding[C-_] or @binding[Home] (see section @ref[help]).
+
+The user can easily rebind keys to different commands, bind new keys to
+commands, or establish bindings for commands never bound before (see section
+@ref[binding-keys]).
+
+In addition to the key bindings explicitly listed with each command, there are
+some implicit bindings created by using key translations@foot[Key translations
+are documented in the @i[Hemlock Command Implementor's Manual].].  These
+bindings are not displayed by documentation commands such as @hid[Where Is].
+By default, there are only a few key translations.  The modifier-prefix
+characters @bf[C-^], @bf[Escape], @bf[C-z], or @bf[C-c] may be used when typing
+keys to convert the following key-event to a control, meta, control-meta, or
+hyper key-event.  For example, @bf[C-x Escape b] invokes the same commands as
+@bf[C-x M-b], and @bf[C-z u] is the same as @bf[C-M-u].  This allows user to
+type more interesting keys on limited keyboards that lack control, meta, and
+hyper keys.
+@index[bit-prefix key-events]
+
+
+@defhvar[var "Key Echo Delay", val {1.0}]
+A key binding may be composed of several key-events, especially when you enter
+it using modifier-prefix key-events.  @hemlock provides feedback for partially
+entered keys by displaying the typed key-events in the echo area.  In order to
+avoid excessive output and clearing of the echo area, this display is delayed
+by @hid[Key Echo Delay] seconds.  If this variable is set to @nil, then
+@hemlock foregoes displaying initial subsequences of keys.
+@enddefhvar
+
+
+@subsection[Extended Commands]
+
+@index[commands, extended]A command is invoked as an extended command by
+typing its name to the @hid[Extended Command] command, which is invoked
+using its key binding, @binding[M-x].
+
+@defcom[com "Extended Command", bind {M-x}]
+This command prompts in the echo area for the name of a command, and then
+invokes that command.  The prefix argument is passed through to the command
+invoked.  The command name need not be typed out in full, as long as enough
+of its name is supplied to uniquely identify it.  Completion is available
+using @binding[Escape] and @binding[Space], and a list of possible completions
+is given by @binding[Home] or @binding[C-_].
+@enddefcom
+
+
+@section[The Prefix Argument]
+
+@index[prefix argument]The prefix argument is an integer argument which
+may be supplied to a command.  It is known as the prefix argument because
+it is specified by invoking some prefix argument setting command
+immediately before the command to be given the argument.  The following
+statements about the interpretation of the prefix argument are true:
+@begin[itemize]
+When it is meaningful, most commands interpret the prefix argument as a
+repeat count, causing the same effect as invoking the command that many
+times.
+
+When it is meaningful, most commands that use the prefix argument interpret
+a negative prefix argument as meaning the same thing as a positive
+argument, but the action is done in the opposite direction.
+
+Most commands treat the absence of a prefix argument as meaning the same
+thing as a prefix argument of one.
+
+Many commands ignore the prefix argument entirely.
+
+Some commands do none of the above.
+@end[itemize]
+The following commands are used to set the prefix argument:
+
+@defcom[com "Argument Digit", stuff (bound to all control or meta digits)]
+Typing a number using this command sets the prefix argument to that number,
+for example, typing @binding[M-1 M-2] sets the prefix argument to twelve.
+@enddefcom
+
+@defcom[com "Negative Argument", bind {M--}]
+This command negates the prefix argument, or if there is none, sets it to
+negative one.  For example, typing @binding[M-- M-7] sets the prefix
+argument to negative seven.
+@enddefcom
+
+@defcom[com "Universal Argument", bind {C-u}]
+@defhvar1[var "Universal Argument Default", val {4}]
+This command sets the prefix argument or multiplies it by four.  If digits
+are typed immediately afterward, they are echoed in the echo area, and the
+prefix argument is set to the specified number.  If no digits are typed
+then the prefix argument is multiplied by four.  @binding[C-u - 7] sets the
+prefix argument to negative seven.  @binding[C-u C-u] sets the prefix
+argument to sixteen.  @binding[M-4 M-2 C-u] sets the prefix argument to one
+hundred and sixty-eight.  @binding[C-u M-0] sets the prefix argument to
+forty.
+
+@hid[Universal Argument Default] determines the default value and multiplier
+for the @hid[Universal Argument] command.
+@enddefcom
+
+
+@section[Modes]
+
+@label[modes]@index[modes]A mode provides a way to change @hemlock@comment{}'s
+behavior by specifying a modification to current key bindings, values of
+variables, and other things.  Modes are typically used to adjust @hemlock
+to suit a particular editing task, e.g. @hid[Lisp] mode is used for editing
+@llisp code.
+
+Modes in @hemlock are not like modes in most text editors; @hemlock is really a
+"modeless" editor.  There are two ways that the @hemlock mode concept differs
+from the conventional one:
+@begin[enumerate]
+Modes do not usually alter the environment in a very big way, i.e. replace
+the set of commands bound with another totally disjoint one.  When a mode
+redefines what a key does, it is usually redefined to have a slightly
+different meaning, rather than a totally different one.  For this reason,
+typing a given key does pretty much the same thing no matter what modes are
+in effect.  This property is the distinguishing characteristic of a
+modeless editor.
+
+Once the modes appropriate for editing a given file have been chosen, they
+are seldom, if ever, changed.  One of the advantages of modeless editors is
+that time is not wasted changing modes.
+@end[enumerate]
+
+@index[major mode]A @i[major mode] is used to make some big change in the
+editing environment.  Language modes such as @hid[Pascal] mode are major
+modes.  A major mode is usually turned on by invoking the command
+@i{mode-name}@hid[ Mode] as an extended command.  There is only one major
+mode present at a time.  Turning on a major mode turns off the one that is
+currently in effect.
+
+@index[minor mode]A @i[minor mode] is used to make a small change in the
+environment, such as automatically breaking lines if they get too long.
+Unlike major modes, any number of minor modes may be present at once.
+Ideally minor modes should do the "right thing" no matter what major and
+minor modes are in effect, but this is may not be the case when key
+bindings conflict.
+
+Modes can be envisioned as switches, the major mode corresponding to one big
+switch which is thrown into the correct position for the type of editing being
+done, and each minor mode corresponding to an on-off switch which controls
+whether a certain characteristic is present.
+
+@defcom[com "Fundamental Mode"]
+This command puts the current buffer into @hid[Fundamental] mode.
+@hid[Fundamental] mode is the most basic major mode: it's the next best thing
+to no mode at all.
+@enddefcom
+
+
+@section[Display Conventions]
+@index[display conventions]
+There are two ways that @hemlock displays information on the screen; one is
+normal @i[buffer display], in which the text being edited is shown on the
+screen, and the other is a @i[pop-up window].
+
+
+@subsection[Pop-Up Windows]
+@index[pop-up windows]
+Some commands print out information that is of little permanent value, and
+these commands use a @i[pop-up] window to display the information.  It is known
+as a @i[pop-up] window because it temporarily appears on the screen overlaying
+text already displayed.  Most commands of this nature can generate their output
+quickly, but in case there is a lot of output, or the user wants to repeatedly
+refer to the same output while editing, @hemlock saves the output in a buffer.
+Different commands may use different buffers to save their output, and we refer
+to these as @i[random typeout] buffers.
+
+If the amount of output exceeds the size of the pop-up window, @Hemlock
+displays the message @w<"@f[--More--]"> after each window full.  The following
+are valid responses to this prompt:
+@Begin[Description]
+@bf[Space], @bf[y]@\
+ Display the next window full of text.
+
+@bf[Delete], @bf[Backspace], @bf[n]@\
+ Abort any further output.
+
+@bf[Escape], @bf[!]@\
+ Remove the window and continue saving any further output in the buffer.
+
+@bf[k]@\
+ This is the same as @bf[!] or @bf[escape], but @hemlock makes a normal window
+over the pop-up window.
+@End[Description]
+Any other input causes the system to abort using the key-event to determine
+the next command to execute.
+
+When the output is complete, @hemlock displays the string @w<"@f[--Flush--]">
+in the pop-up window's modeline, indicating that the user may flush the
+temporary display.  Typing any of the key-events described above removes the
+pop-up window, but typing @bf[k] still produces a window suitable for normal
+editing.  Any other input also flushes the display, but @hemlock uses the
+key-event to determine the next command to invoke.
+
+@defcom[com "Select Random Typeout Buffer", bind {H-t}]
+This command makes the most recently used random typeout buffer the current
+buffer in the current window.
+@enddefcom
+
+Random typeout buffers are always in @hid[Fundamental] mode.
+
+
+@subsection[Buffer Display]
+@index[buffer, display]
+@index[display, buffer]
+
+If a line of text is too long to fit within the screen width it is @i[wrapped],
+with @hemlock displaying consecutive pieces of the text line on as many screen
+lines as needed to hold the text.  @hemlock indicates a wrapped line by placing
+a line-wrap character in the last column of each screen line.  Currently, the
+line-wrap character is an exclamation point (@f[!]).  It is possible for a line
+to wrap off the bottom of the screen or on to the top.
+
+@hemlock wraps screen lines when the line is completely full regardless of the
+line-wrap character.  Most editors insert the line-wrap character and wrap a
+single character when a screen line would be full if the editor had avoided
+wrapping the line.  In this situation, @hemlock would leave the screen line
+full.  This means there are always at least two characters on the next screen
+line if @hemlock wraps a line of display.  When the cursor is at the end of a
+line which is the full width of the screen, it is displayed in the last column,
+since it cannot be displayed off the edge.
+
+@hemlock displays most characters as themselves, but it treats some
+specially:
+@begin[itemize]
+Tabs are treated as tabs, with eight character tab-stops.
+
+Characters corresponding to ASCII control characters are printed as
+@f[^]@i[char]; for example, a formfeed is @f[^L].
+
+Characters with the most-significant bit on are displayed as
+@f[<]@i[hex-code]@f[>]; for example, @f[<E2>].
+@end[itemize]
+Since a character may be displayed using more than one printing character,
+there are some positions on the screen which are in the middle of a character.
+When the cursor is on a character with a multiple-character representation,
+@hemlock always displays the cursor on the first character.
+
+
+@subsection[Modelines]
+@label[modelines]
+@index[modeline]
+A modeline is the line displayed at the bottom of each window where @hemlock
+shows information about the buffer displayed in that window.  Here is a typical
+modeline:
+@begin[programexample]
+Hemlock USER: (Fundamental Fill)  /usr/slisp/hemlock/user.mss
+@end[programexample]
+This tells us that the file associated with this buffer is
+"@f[/usr/slisp/hemlock/user.mss]", and the @hid[Current Package] for Lisp
+interaction commands is the @f["USER"] package.  The modes currently present
+are @hid[Fundamental] and @hid[Fill]; the major mode is always displayed first,
+followed by any minor modes.  If the buffer has no associated file, then the
+buffer name will be present instead:
+@begin[programexample]
+Hemlock PLAY: (Lisp)  Silly:
+@end[programexample]
+In this case, the buffer is named @hid[Silly] and is in @hid[Lisp] mode.  The
+user has set @hid[Current Package] for this buffer to @f["PLAY"].
+
+@defhvar[var "Maximum Modeline Pathname Length", val {nil}]
+This variable controls how much of a pathname @hemlock displays in a modeline.
+Some distributed file systems can have very long pathnames which leads to the
+more particular information in a pathname running off the end of a modeline.
+When set, the system chops off leading directories until the name is less than
+the integer value of this variable.  Three dots, @f[...], indicate a truncated
+name.  The user can establish this variable buffer locally with the
+@hid[Defhvar] command.
+@enddefhvar
+
+If the user has modified the buffer since the last time it was read from or
+save to a file, then the modeline contains an asterisk (@f[*]) between the
+modes list and the file or buffer name:
+@begin[programexample]
+Hemlock USER: (Fundamental Fill)  * /usr/slisp/hemlock/user.mss
+@end[programexample]
+This serves as a reminder that the buffer should be saved eventually.
+
+@index[status line]
+There is a special modeline known as the @i[status line] which appears as the
+@hid[Echo Area]'s modeline.  @Hemlock and user code use this area to display
+general information not particular to a buffer @dash recursive edits, whether
+you just received mail, etc.
+
+
+@section[Use with X Windows]
+@label[using-x]
+@index[X windows, use with]
+@index[window management]
+It is preferable to use @hemlock on a workstation with a bitmap display and a
+window manager since @hemlock makes good use of the window manager and
+non-ASCII input devices such as the mouse and modifier keys.  This section
+deals with using @hemlock under X windows, which is currently the only
+supported window manager.
+
+
+@subsection[Event Translation]
+@index[keyboard use under X]
+@index[translation of keys under X]
+Each X key event is translated into a canonical input representation, a
+key-event.  The X key event consists of a scan-code and modifier bits, and
+these translate to an X keysym.  This keysym and the modifier bits map to a
+key-event.
+
+If you type a key with a shift key held down, this typically maps to a distinct
+X keysym.  For example, the shift of @bf[3] is @bf[#], and these have different
+X keysyms.  Some keys map to the same X keysym regardless of the shift bit,
+such as @bf[Tab], @bf[Space], @bf[Return], etc.  When the X lock bit is on, the
+system treats this as a caps-lock, only mapping keysyms for lowercase letters
+to shifted keysyms.
+
+The key-event has a keysym and a field of bits.  The X keysyms map directly to
+the key-event keysyms.  There is a distinct mapping for each CLX modifier bit
+to a key-event bit.  This tends to eliminate shift and lock modifiers, so
+key-events usually only have control, meta, hyper, and super bits on.  Hyper
+and super usually get turned on with prefix key-events that set them on the
+following key-event, but you can turn certain keys on the keyboard into hyper
+and super keys.  See the X manuals and the @i[Hemlock Command Implementor's
+Manual] for details.
+
+The system also maps mouse input to key-events.  Each mouse button has distinct
+key-event keysyms for whether the user pressed or released it.  For
+convenience, @hemlock makes use of an odd property of converting mouse events
+to key-events.  If you enter a mouse event with the shift key held down,
+@hemlock sees the key-event keysym for the mouse event, but the key-event has
+the super bit turned on.  For example, if you press the left button with the
+shift key pressed, @hemlock sees @bf[S-Leftdown].
+
+Note that with the two button mouse on the IBM RT PC, the only way to to send
+@bf[Middledown] is to press both the left and right buttons simultaneously.
+This is awkward, and it often confuses the X server.  For this reason, the
+commands bound to the middle button are also bound to the shifted left button,
+@bf[S-Leftdown], which is much easier to type.
+
+
+@subsection[Cut Buffer Commands]
+@index[cutting]@index[pasting] These commands allow the X cut buffer to be
+used from @hemlock .  Although @hemlock can cut arbitrarily large regions,
+a bug in the standard version 10 xterm prevents large regions from being
+pasted into an xterm window.
+
+@defcom[com "Region to Cut Buffer", bind {M-Insert}]
+@defcom1[com "Insert Cut Buffer", bind {Insert}]
+These commands manipulate the X cut buffer.  @hid[Region to Cut Buffer] puts
+the text in the region into the cut buffer.  @hid[Insert Cut Buffer] inserts
+the contents of the cut buffer at the point.
+@enddefcom
+
+@subsection[Redisplay and Screen Management]
+
+These variables control a number of the characteristics of @hemlock bitmap
+screen management.
+
+@defhvar[var "Bell Style", val {:border-flash}]
+@defhvar1[var "Beep Border Width", val {20}]
+@hid[Bell Style] determines what beeps do in @hemlock.  Acceptable values are
+@kwd[border-flash], @kwd[feep], @kwd[border-flash-and-feep], @kwd[flash],
+@kwd[flash-and-feep], and @nil (do nothing).
+
+@hid[Beep Border Width] is the width in pixels of the border flashed by border
+flash beep styles.
+@enddefhvar
+
+@defhvar[var "Reverse Video", val {nil}]
+If this variable is true, then @hemlock paints white on black in window
+bodies, black on white in modelines.
+@enddefhvar
+
+@defhvar[var "Thumb Bar Meter", val {t}]
+If this variable is true, then windows will be created to be displayed with a
+ruler in the bottom border of the window.
+@enddefhvar
+
+@defhvar[var "Set Window Autoraise", val {:echo-only}]
+When true, changing the current window will automatically raise the new current
+window.  If the value is @kwd[echo-only], then only the echo area window will
+be raised automatically upon becoming current.
+@enddefhvar
+
+@defhvar[var "Default Initial Window Width", val {80}]
+@defhvar1[var "Default Initial Window Height", val {24}]
+@defhvar1[var "Default Initial Window X"]
+@defhvar1[var "Default Initial Window Y"]
+@defhvar1[var "Default Window Height", val {24}]
+@defhvar1[var "Default Window Width", val {80}]
+@index[window placement]
+@Hemlock uses the variables with "@hid[Initial]" in their names when it first
+starts up to make its first window.  The width and height are specified in
+character units, but the x and y are specified in pixels.  The other variables
+determine the width and height for interactive window creation, such as making
+a window with @comref[New Window].
+@enddefhvar
+
+@defhvar[var "Cursor Bitmap File", val {"/usr/misc/.lisp/lib/hemlock.cursor"}]
+This variable determines where the mouse cursor bitmap is read from when
+@hemlock starts up.  The mask is found by merging this name with "@f[.mask]".
+This has to be a full pathname for the C routine.
+@enddefhvar
+
+
+@defhvar[var "Default Font"]
+This variable holds the string name of the font to be used for normal text
+display: buffer text, modelines, random typeout, etc.  The font is loaded at
+initialization time, so this variable must be set before entering @hemlock.
+When @nil, the display type is used to choose a font.
+@enddefhvar
+
+
+@section[Use With Terminals]
+@label[using-terminals]@index[terminals, use with] @hemlock can also be used
+with ASCII terminals and terminal emulators.  Capabilities that depend on
+@windows (such as mouse commands) are not available, but nearly everything else
+can be done.
+
+@subsection[Terminal Input]
+@index[ASCII keyboard translation]
+@index[bit-prefix key-events]
+@index[prefix key-events]
+@index[key-event, prefix]
+The most important limitation of a terminal is its input capabilities.  On a
+workstation with function keys and independent control, meta, and shift
+modifiers, it is possible to type 800 or so distinct single keystrokes.
+Although by default, @hemlock uses only a fraction of these combinations, there
+are many more than the 128 key-events available in ASCII.
+
+On a terminal, @hemlock attempts to translate ASCII control characters into the
+most useful key-event:
+@begin[itemize]
+On a terminal, control does not compose with shift.  If the control key is down
+when you type a letter keys, the terminal always sends one code regardless of
+whether the shift key is held.  Since @hemlock primarily binds commands to
+key-events with keysyms representing lowercase letters regardless of what bits
+are set in the key-event, the system translates the ASCII control codes to a
+keysym representing the appropriate lowercase characters.  This keysym then
+forms a key-event with the control bit set.  Users can type @bf[C-c] followed
+by an uppercase character to form a key-event with a keysym representing an
+uppercase character and bits with the control bit set.
+
+On a terminal, some of the named keys generate an ASCII control code.  For
+example, @f[Return] usually sends a @f[C-m].  The system translates these ASCII
+codes to a key-event with an appropriate keysym instead of the keysym named by
+the character which names the ASCII code.  In the above example, typing the
+@f[Return] key would generate a key-event with the @bf[Return] keysym and no
+bits.  It would NOT translate to a key-event with the @bf[m] keysym and the
+control bit.
+@end[itemize]
+
+Since terminals have no meta key, you must use the @bf[Escape] and @bf[C-Z]
+modifier-prefix key-events to invoke commands bound to key-events with the meta
+bit or meta and control bits set.  ASCII terminals cannot generate all
+key-events which have the control bit on, so you can use the @bf[C-^]
+modifier-prefix.  The @bf[C-c] prefix sets the hyper bit on the next key-event
+typed.
+
+When running @hemlock from a terminal @f[^\] is the interrupt key-event.
+Typing this will place you in the Lisp debugger.
+
+When using a terminal, pop-up output windows cannot be retained after the
+completion of the command.
+
+
+@subsection[Terminal Redisplay]
+
+Redisplay is substantially different on a terminal.  @Hemlock uses different
+algorithms, and different parameters control redisplay and screen management.
+
+Terminal redisplay uses the Unix termcap database to find out how to use a
+terminal.  @hemlock is useful with terminals that lack capabilities for
+inserting and deleting lines and characters, and some terminal emulators
+implement these operations very inefficiently (such as xterm).
+If you realize poor performance when scrolling, create a termcap entry that
+excludes these capabilities.
+
+@defhvar[var "Scroll Redraw Ratio", val {nil}]
+This is a ratio of "inserted" lines to the size of a window.  When this ratio
+is exceeded, insert/delete line terminal optimization is aborted, and every
+altered line is simply redrawn as efficiently as possible.  For example,
+setting this to 1/4 will cause scrolling commands to redraw the entire window
+instead of moving the bottom two lines of the window to the top (typically 3/4
+of the window is being deleted upward and inserted downward, hence a redraw);
+however, commands like @hid[New Line] and @hid[Open Line] will still work
+efficiently, inserting a line and moving the rest of the window's text
+downward.
+@enddefhvar
+
+
+@section[The Echo Area]
+
+@index[echo area]
+@index[prompting]
+The echo area is the region which occupies the bottom few lines on the screen.
+It is used for two purposes: displaying brief messages to the user and
+prompting.
+
+When a command needs some information from the user, it requests it by
+displaying a @i[prompt] in the echo area.  The following is a typical prompt:
+@begin[programexample]
+Select Buffer: [hemlock-init.lisp /usr/foo/]
+@end[programexample]
+The general format of a prompt is a one or two word description of the input
+requested, possibly followed by a @i[default] in brackets.  The default is a
+standard response to the prompt that @hemlock uses if you type @bf[Return]
+without giving any other input.
+
+There are four general kinds of prompts: @comment<Key prompts?>
+@begin[description]
+@i[key-event]@\
+ The response is a single key-event and no confirming @binding[Return] is
+needed.
+
+@i[keyword]@\
+ The response is a selection from one of a limited number of choices.
+Completion is available using @binding[Space] and @binding[Escape], and you
+only need to supply enough of the keyword to distinguish it from any other
+choice.  In some cases a keyword prompt accepts unknown input, indicating the
+prompter should create a new entry.  If this is the case, then you must enter
+the keyword fully specified or completed using @binding[Escape]; this
+distinguishes entering an old keyword from making a new keyword which is a
+prefix of an old one since the system completes partial input automatically.
+
+@i[file]@\
+ The response is the name of a file, which may have to exist.  Unlike other
+prompts, the default has some effect even after the user supplies some input:
+the system @i[merges] the default with the input filename.  See page
+@pageref(merging) for a description of filename merging.  @bf[Escape] and
+@bf[Space] complete the input for a file parse.
+
+@i[string]@\
+ The response is a string which must satisfy some property, such as being the
+name of an existing file.
+@end[description]
+
+@index[history, echo area]
+These key-events have special meanings when prompting:
+@begin[description]
+@binding[Return]@\
+ Confirm the current parse.  If no input has been entered, then use the
+default.  If for some reason the input is unacceptable, @hemlock does two
+things:
+@Begin[enumerate]
+beeps, if the variable @hid[Beep on Ambiguity] set, and
+
+moves the point to the end of the first word requiring disambiguation.
+@End[enumerate]
+This allows you to add to the input before confirming the it again.
+
+@binding[Home, C-_]@\
+ Print some sort of help message.  If the parse is a keyword parse, then print
+all the possible completions of the current input in a pop-up window.
+
+@binding[Escape]@\
+ Attempt to complete the input to a keyword or file parse as far as possible,
+beeping if the result is ambiguous.  When the result is ambiguous, @hemlock
+moves the point to the first ambiguous field, which may be the end of the
+completed input.
+
+@binding[Space]@\
+ In a keyword parse, attempt to complete the input up to the next space.  This
+is useful for completing the names of @hemlock commands and similar things
+without beeping a lot, and you can continue entering fields while leaving
+previous fields ambiguous.  For example, you can invoke @hid[Forward Word] as
+an extended command by typing @binding[M-X f Space w Return].  Each time the
+user enters space, @Hemlock attempts to complete the current field and all
+previous fields.
+
+@binding[C-i, Tab]@\
+ In a string or keyword parse, insert the default so that it may be edited.
+
+@binding[C-p]@\
+ Retrieve the text of the last string input from a history of echo area inputs.
+Repeating this moves to successively earlier inputs.
+
+@binding[C-n]@\
+ Go the other way in the echo area history.
+
+@binding[C-q]@\
+ Quote the next key-event so that it is not interpreted as a command.
+@end[description]
+
+@defhvar[var "Ignore File Types"]
+This variable is a list of file types (or extensions), represented as a string
+without the dot, e.g. @f["fasl"].  Files having any of the specified types will
+be considered nonexistent for completion purposes, making an unambiguous
+completion more likely.  The initial value contains most common binary and
+output file types.
+@enddefhvar
+
+
+@section[Online Help]
+
+@label[help]
+@index[online help]
+@index[documentation, hemlock]
+@hemlock has a fairly good online documentation facility.  You can get brief
+documentation for every command, variable, character attribute, and key
+by typing a key.
+
+@defcom[com "Help", bind (Home, C-_)]
+This command prompt for a key-event indicating one of a number of other
+documentation commands.  The following are valid responses:
+@begin[description]
+@bf[a]@\
+ List commands and other things whose names contain a specified keyword.
+
+@bf[d]@\
+ Give the documentation and bindings for a specified command.
+
+@bf[g]@\
+ Give the documentation for any @hemlock thing.
+
+@bf[v]@\
+ Give the documentation for a @hemlock variable and its values.
+
+@bf[c]@\
+ Give the documentation for a command bound to some key.
+
+@bf[l]@\
+ List the last sixty key-events typed.
+
+@bf[m]@\
+ Give the documentation for a mode followed by a short description of its
+mode-specific bindings.
+
+@bf[p]@\
+ Give the documentation and bindings for commands that have at least one
+binding involving a mouse/pointer key-event.
+
+@bf[w]@\
+ List all the key bindings for a specified command.
+
+@bf[t]@\
+ Describe a @llisp object.
+
+@binding[q]@\
+ Quit without doing anything.
+
+@binding[Home, C-_, ?, h]@\
+ List all of the options and what they do.
+@end[description]
+@enddefcom
+
+@defcom[com "Apropos", bind (Home a, C-_ a)]
+This command prints brief documentation for all commands, variables, and
+character attributes whose names match the input.  This performs a prefix match
+on each supplied word separately, intersecting the names in each word's result.
+For example, giving @hid[Apropos] "@f[f m]" causes it to tersely describe
+following commands and variables:
+@Begin[Itemize]   
+@hid[Auto Fill Mode]
+
+@hid[Fundamental Mode]
+
+@hid[Mark Form]
+
+@hid[Default Modeline Fields]
+
+@hid[Fill Mode Hook]
+
+@hid[Fundamental Mode Hook]
+@End[Itemize]
+Notice @hid[Mark Form] demonstrates that the "@f[f]" words may follow the
+"@f[m]" order of the fields does not matter for @hid[Apropos].
+
+The bindings of commands and values of variables are printed with the
+documentation.
+@enddefcom
+
+@defcom[com "Describe Command", bind (Home d, C-_ d)]
+This command prompts for a command and prints its full documentation and all
+the keys bound to it.
+@enddefcom
+
+@defcom[com "Describe Key", bind (Home c, C-_ c, M-?)]
+This command prints full documentation for the command which is bound to
+the specified key in the current environment.
+@enddefcom
+
+@defcom[com "Describe Mode", bind (Home m, C-_ m)]
+This command prints the documentation for a mode followed by a short
+description of each of its mode-specific bindings.
+@enddefcom
+
+@defcom[com "Show Variable"]
+@defcom1[com "Describe and Show Variable"]
+@hid[Show Variable] prompts for the name of a variable and displays
+the global value of the variable, the value local to the current buffer (if
+any), and the value of the variable in all defined modes that have it as a
+local variable.  @hid[Describe and Show Variable] displays the variable's
+documentation in addition to the values.
+@enddefcom
+
+@defcom[com "What Lossage", bind (Home l, C-_ l)]
+This command displays the last sixty key-events typed.  This can be useful
+if, for example, you are curious what the command was that you typed by
+accident.
+@enddefcom
+
+@defcom[com "Describe Pointer"]
+This command displays the documentation and bindings for commands that have
+some binding involving a mouse/pointer key-event.  It will not show the
+documentation for the @hid[Illegal] command regardless of whether it has a
+pointer binding.
+@enddefcom
+
+@defcom[com "Where Is", bind (Home w, C-_ w)]
+This command prompts for the name of a command and displays its key
+bindings in a pop-up window.  If a key binding is not global, the
+environment in which it is available is displayed.
+@enddefcom
+
+@defcom[com "Generic Describe", bind (Home g, C-_ g)]
+This command prints full documentation for any thing that has
+documentation.  It first prompts for the kind of thing to document, the
+following options being available:
+@begin[description]
+@i[attribute]@\Describe a character attribute, given its name.
+
+@i[command]@\Describe a command, given its name.
+
+@i[key]@\Describe a command, given a key to which it is bound.
+
+@i[variable]@\Describe a variable, given its name.  This is the default.
+@end[description]
+@enddefcom
+
+
+@section[Entering and Exiting]
+
+@index[entering hemlock]@hemlock is entered by using the @clisp @f[ed]
+function.  Simply typing @f[(ed)] will enter @hemlock, leaving you in the state
+that you were in when you left it.  If @hemlock has never been entered before
+then the current buffer will be @hid[Main].  The @f[-edit] command-line switch
+may also be used to enter @hemlock: see page @pageref[edit-switch].
+
+@f[ed] may optionally be given a file name or a symbol argument.  Typing 
+@f[(ed @i[filename])] will cause the specified file to be read into @hemlock,
+as though by @hid[Find File].  Typing @w<@f[(ed @i[symbol])]> will pretty-print
+the definition of the symbol into a buffer whose name is obtained by adding
+"@f[Edit ]" to the beginning of the symbol's name.
+
+@defcom[com "Exit Hemlock", bind (C-c, C-x C-z)]
+@defcom1[com "Pause Hemlock"]
+@index[exiting hemlock]@hid[Exit Hemlock] exits @hemlock, returning @f[t].
+@hid[Exit Hemlock] does not by default save modified buffers, or do
+anything else that you might think it should do; it simply exits.  At any time
+after exiting you may reenter by typing @f[(ed)] to @llisp without losing
+anything.  Before you quit from @llisp using @f[(quit)], you should
+save any modified files that you want to be saved.
+
+@hid[Pause Hemlock] is similar, but it suspends the @llisp process and returns
+control to the shell.  When the process is resumed, it will still be running
+@hemlock.
+@enddefcom
+
+
+@section[Helpful Information]
+
+@label[aborting]
+@index[aborting]
+@index[undoing]
+@index[error recovery]
+This section contains assorted helpful information which may be useful in
+staying out of trouble or getting out of trouble.
+
+@begin[itemize]
+It is possible to get some sort of help nearly everywhere by typing
+@binding[Home] or @binding[C-_].
+
+Various commands take over the keyboard and insist that you type the key-events
+that they want as input.  If you get in such a situation and want to get out,
+you can usually do so by typing @bf[C-g] some small number of times.  If this
+fails you can try typing @binding[C-x C-z] to exit @hemlock and then "@f[(ed)]"
+to re-enter it.
+
+Before you quit, make sure you have saved all your changes.  @binding[C-u C-x
+C-b] will display a list of all modified buffers.  If you exit using @bf[C-x
+M-z], then @hemlock will save all modified buffers with associated files.
+
+If you lose changes to a file due to a crash or accidental failure to save,
+look for backup ("@i[file]@f[.BAK]") or checkpoint ("@i[file]@f[.CKP]") files
+in the same directory where the file was.
+
+If the screen changes unexpectedly, you may have accidentally typed an
+incorrect command.  Use @binding[Home l] to see what it was.  If you are
+not familiar with the command, use @binding[Home c] to see what it is so that
+you know what damage has been done.  Many interesting commands can be found
+in this fashion.  This is an example of the much-underrated learning
+technique known as "Learning by serendipitous malcoordination".  Who would
+ever think of looking for a command that deletes all files in the current
+directory?
+
+If you accidentally type a "killing" command such as @binding[C-w], you can
+get the lost text back using @binding[C-y].  The @hid[Undo] command is also
+useful for recovering from this sort of problem.
+@end[itemize]
+
+@defhvar[var "Region Query Size", val {30}]
+@index[large region]
+Various commands ask for confirmation before modifying a region containing more
+than this number of lines.  If this is @nil, then these commands refrain from
+asking, no matter how large the region is.
+@enddefhvar
+
+@defcom[com "Undo"]
+This command undoes the last major modification.  Killing commands and some
+other commands save information about their modifications, so accidental uses
+may be retracted.  This command displays the name of the operation to be undone
+and asks for confirmation.  If the affected text has been modified between the
+invocations of @hid[Undo] and the command to be undone, then the result may be
+somewhat incorrect but useful.  Often @hid[Undo] itself can be undone by
+invoking it again.
+@enddefcom
+
+
+@section[Recursive Edits]
+@label[recursive-edits]
+@index[recursive edits]
+Some sophisticated commands, such as @hid[Query Replace], can place you in a
+@i[recursive edit].  A recursive edit is simply a recursive invocation of
+@hemlock done within a command.  A recursive edit is useful because it allows
+arbitrary editing to be done during the execution of a command without losing
+any state that the command might have.  When the user exits a recursive edit,
+the command that entered it proceeds as though nothing happened.  @Hemlock
+notes recursive edits in the @hid[Echo Area] modeline, or status line.  A
+counter reflects the number of pending recursive edits.
+
+@defcom[com "Exit Recursive Edit", bind (C-M-z)]
+This command exits the current recursive edit, returning @nil.  If invoked when
+not in a recursive edit, then this signals an user error.
+@enddefcom
+
+@defcom[com "Abort Recursive Edit", bind (@bf<C-]>)]
+This command causes the command which invoked the recursive edit to get an
+error.  If not in a recursive edit, this signals an user error.
+@enddefcom
+
+
+@section[User Errors]
+@index[beeping]
+@index[errors, user]
+When in the course of editing, @hemlock is unable to do what it thinks you want
+to do, then it brings this to your attention by a beep or a screen flash
+(possibly accompanied by an explanatory echo area message such as @w<"@f[No
+next line.]">.)  Although the exact attention-getting mechanism may vary on the
+output device and variable settings, this is always called @i[beeping].
+
+Whatever the circumstances, you had best try something else since @hemlock,
+being far more stupid than you, is far more stubborn.  @hemlock is an
+extensible editor, so it is always possible to change the command that
+complained to do what you wanted it to do.
+
+@section[Internal Errors]
+
+@index[errors, internal]A message of this form may appear in the echo
+area, accompanied by a beep:
+@begin[programexample]
+Internal error:
+Wrong type argument, NIL, should have been of type SIMPLE-VECTOR.
+@end[programexample]
+If the error message is a file related error such as the following, then
+you have probably done something illegal which @hemlock did not catch,
+but was detected by the file system:
+@begin[programexample]
+Internal error:
+No access to "/lisp2/emacs/teco.mid"
+@end[programexample]
+Otherwise, you have found a bug.  Try to avoid the behavior that resulted
+in the error and report the problem to your system maintainer.  Since @llisp
+has fairly robust error recovery mechanisms, probably no damage has been
+done.
+
+If a truly abominable error from which @hemlock cannot recover occurs,
+then you will be thrown into the @llisp debugger.  At this point it would be
+a good idea to save any changes with @f[save-all-buffers] and then start
+a new @llisp.
+
+@index[save-all-buffers, function]The @llisp function @f[save-all-buffers] may
+be used to save modified buffers in a seriously broken @hemlock.  To use this,
+type "@f[(save-all-buffers)]" to the top-level ("@f[* ]") or debugger
+("@f<1] >") prompt and confirm saving of each buffer that should be saved.
+Since this function will prompt in the "@f[Lisp]" window, it isn't very useful
+when called inside of @hemlock.
diff --git a/docs/hem/user/lisp.mss b/docs/hem/user/lisp.mss
new file mode 100644
index 000000000..004e6b9ed
--- /dev/null
+++ b/docs/hem/user/lisp.mss
@@ -0,0 +1,697 @@
+@comment{-*- Dictionary: bld:scribe/hem/hem; Mode: spell; Package: Hemlock; Log: /usr/lisp/scribe/hem/hem-docs.log -*-}
+@chap[Interacting With Lisp]
+@index[lisp, interaction with]
+
+Lisp encourages highly interactive programming environments by requiring
+decisions about object type and function definition to be postponed until run
+time.  @hemlock supports interactive programming in @llisp by providing
+incremental redefinition and environment examination commands.  @hemlock also
+uses Unix TCP sockets to support multiple Lisp processes, each of which may be
+on any machine.
+
+
+@section[Eval Servers]
+@label[eval-servers]
+@index[eval servers]
+
+@hemlock runs in the editor process and interacts with other Lisp processes
+called @i[eval servers].  A user's Lisp program normally runs in an eval
+server process.  The separation between editor and eval server has several
+advantages:
+@begin[itemize]
+The editor is protected from any bad things which may happen while debugging a
+Lisp program.
+
+Editing may occur while running a Lisp program.
+
+The eval server may be on a different machine, removing the load from the
+editing machine.
+
+Multiple eval servers allow the use of several distinct Lisp environments.
+@end[itemize]
+Instead of providing an interface to a single Lisp environment, @hemlock
+coordinates multiple Lisp environments.
+
+
+@subsection[The Current Eval Server]
+@index[current eval server]
+Although @hemlock can be connected to several eval servers simultaneously, one
+eval server is designated as the @i[current eval server].  This is the eval
+server used to handle evaluation and compilation requests.  Eval servers are
+referred to by name so that there is a convenient way to discriminate between
+servers when the editor is connected to more than one.  The current eval server
+is normally globally specified, but it may also be shadowed locally in specific
+buffers.
+
+@defcom[com "Set Eval Server"]
+@defcom1[com "Set Buffer Eval Server"]
+@defcom1[com "Current Eval Server"]
+@hid[Set Eval Server] prompts for the name of an eval server and makes it the
+the current eval server.  @hid[Set Buffer Eval Server] is the same except that
+is sets the eval server for the current buffer only.  @hid[Current Eval Server]
+displays the name of the current eval server in the echo area, taking any
+buffer eval server into consideration.  See also @comref[Set Compile Server].
+@enddefcom
+
+
+@subsection[Slaves]
+@index[slave buffers]
+@index[slaves]
+For now, all eval servers are @i[slaves].  A slave is a Lisp process that uses
+a typescript (see page @pageref[typescripts]) to run its top-level
+@f[read-eval-print] loop in a @hemlock buffer.  We refer to the buffer that a
+slave uses for I/O as its @i[interactive] or @i[slave] buffer.  The name of the
+interactive buffer is the same as the eval server's name.
+
+@index[background buffers]
+@hemlock creates a @i[background] buffer for each eval server.  The background
+buffer's name is @w<@hid[Background ]@i{name}>, where @i[name] is the name of
+the eval server.  Slaves direct compiler warning output to the background
+buffer to avoid cluttering up the interactive buffer.
+
+@hemlock locally sets @hid[Current Eval Server] in interactive and background
+buffers to their associated slave.  When in a slave or background buffer, eval
+server requests will go to the associated slave, regardless of the global value
+of @hid[Current Eval Server].
+
+@defcom[com "Select Slave", bind (C-M-c)]
+This command changes the current buffer to the current eval server's
+interactive buffer.  If the current eval server is not a slave, then it beeps.
+If there is no current eval server, then this creates a slave (see section
+@ref[slave-creation]).  If a prefix argument is supplied, then this creates a
+new slave regardless of whether there is a current eval server.  This command
+is the standard way to create a slave.
+
+The slave buffer is a typescript (see page @pageref[typescripts]) the slave
+uses for its top-level @f[read-eval-print] loop.
+@enddefcom
+
+@defcom[com "Select Background", bind (C-M-C)]
+This command changes the current buffer to the current eval server's background
+buffer.  If there is no current eval server, then it beeps.
+@enddefcom
+
+
+@subsection[Slave Creation and Destruction]
+@label[slave-creation]
+When @hemlock first starts up, there is no current eval server.  If there is no
+a current eval server, commands that need to use the current eval server will
+create a slave as the current eval server.
+
+If an eval server's Lisp process terminates, then we say the eval server is
+dead.  @hemlock displays a message in the echo area, interactive, and
+background buffers whenever an eval server dies.  If the user deletes an
+interactive or background buffer, the associated eval server effectively
+becomes impotent, but @hemlock does not try to kill the process.  If a command
+attempts to use a dead eval server, then the command will beep and display a
+message.
+
+@defhvar[var "Confirm Slave Creation", val {t}]
+If this variable is true, then @hemlock always prompts the user for
+confirmation before creating a slave.
+@enddefhvar
+
+@defhvar[var "Ask About Old Servers", val {t}]
+If this variable is true, and some slave already exists, @hemlock prompts the
+user for the name of an existing server when there is no current server,
+instead of creating a new one.
+@enddefhvar
+
+@defcom[com "Editor Server Name"]
+This command echos the editor server's name, the machine and port of the
+editor, which is suitable for use with the Lisp processes -slave switch.
+See section @ref[slave-switch].
+@enddefcom
+
+@defcom[com "Accept Slave Connections"]
+This command cause @hemlock to accept slave connections, and it displays the
+editor server's name, which is suitable for use with the Lisp processes -slave
+switch.  See section @ref[slave-switch].  Supplying an argument causes this
+command to inhibit slave connections.
+@enddefcom
+
+@defhvar[var "Slave Utility", val {"/usr/misc/.lisp/bin/lisp"}]
+@defhvar1[var "Slave Utility Switches"]
+A slave is started by running the program @hid[Slave Utility Name] with
+arguments specified by the list of strings @hid[Slave Utility Switches].  This
+is useful primarily when running customized Lisp systems.  For example,
+setting @hid[Slave Utility Switches] to @f[("-core" "my.core")] will cause
+"@f[/usr/hqb/my.core]" to be used instead of the default core image.
+
+The @f[-slave] switch and the editor name are always supplied as arguments, and
+should remain unspecified in @hid[Slave Utility Switches].
+@enddefhvar
+
+@defcom[com "Kill Slave"]
+@defcom1[com "Kill Slave and Buffers"]
+@hid[Kill Slave] prompts for a slave name, aborts any operations in the slave,
+tells the slave to @f[quit], and shuts down the connection to the specified
+eval server.  This makes no attempt to assure the eval server actually dies.
+
+@hid[Kill Slave and Buffers] is the same as @hid[Kill Slave], but it also
+deletes the interactive and background buffers.
+@enddefcom
+
+
+@subsection[Eval Server Operations]
+
+@label[operations]
+@index[eval server operations]@index[operations, eval server]
+@hemlock handles requests for compilation or evaluation by queuing an
+@i[operation] on the current eval server.  Any number of operations may be
+queued, but each eval server can only service one operation at a time.
+Information about the progress of operations is displayed in the echo area.
+
+@defcom[com "Abort Operations", bind (C-c a)]
+This command aborts all operations on the current eval server, either queued or
+in progress.  Any operations already in the @f[Aborted] state will be flushed.
+@enddefcom
+
+@defcom[com "List Operations", bind (C-c l)]
+This command lists all operations which have not yet completed.  Along with a
+description of the operation, the state and eval server is displayed.  The
+following states are used:
+@begin[description]
+@f[Unsent]@\The operation is in local queue in the editor, and hasn't been sent
+yet.
+
+@f[Pending]@\The operation has been sent, but has not yet started execution.
+
+@f[Running]@\The operation is currently being processed.
+
+@f[Aborted]@\The operation has been aborted, but the eval server has not yet
+indicated termination.
+@end[description]
+@enddefcom
+
+
+@section[Typescripts]
+@label[typescripts]
+@index[typescripts]
+
+Both slave buffers and background buffers are typescripts.  The typescript
+protocol allows other processes to do stream-oriented interaction in a @hemlock
+buffer similar to that of a terminal.  When there is a typescript in a buffer,
+the @hid[Typescript] minor mode is present.  Some of the commands described in
+this section are also used by @hid[Eval] mode (page @pageref[eval-mode].)
+
+Typescripts are simple to use.  @hemlock inserts output from the process into
+the buffer.  To give the process input, use normal editing to insert the input
+at the end of the buffer, and then type @bf[Return] to confirm sending the
+input to the process.
+
+@defcom[com "Confirm Typescript Input", 
+        stuff (bound to @bf[Return] in @hid[Typescript] mode)]
+@defhvar1[var "Unwedge Interactive Input Confirm", val {t}]
+This command sends text that has been inserted at the end of the current buffer
+to the process reading on the buffer's typescript.  Before sending the text,
+@hemlock moves the point to the end of the buffer and inserts a newline.
+
+Input may be edited as much as is desired before it is confirmed; the result
+of editing input after it has been confirmed is unpredictable.  For this reason,
+it is desirable to postpone confirming of input until it is actually complete.
+The @hid[Indent New Line] command is often useful for inserting newlines
+without confirming the input.
+
+If the process reading on the buffer's typescript is not waiting for input,
+then the text is queued instead of being sent immediately.  Any number of
+inputs may be typed ahead in this fashion.  @hemlock makes sure that the inputs
+and outputs get interleaved correctly so that when all input has been read, the
+buffer looks the same as it would have if the input had not been typed ahead.
+
+If the buffer's point is before the start of the input area, then various
+actions can occur.  When set, @hid[Unwedge Interactive Input Confirm] causes
+@hemlock to ask the user if it should fix the input buffer which typically
+results in ignoring any current input and refreshing the input area at the end
+of the buffer.  This also has the effect of throwing the slave Lisp to top
+level, which aborts any pending operations or queued input.  This is the only
+way to be sure the user is cleanly set up again after messing up the input
+region.  When this is @nil, @hemlock simply beeps and tells the user in the
+@hid[Echo Area] that the input area is invalid.
+@enddefcom
+
+@defcom[com "Kill Interactive Input", 
+    stuff (bound to @bf[M-i] in @hid[Typescript] and @hid[Eval] modes)]
+This command kills any input that would have been confirmed by @bf[Return].
+@enddefcom
+
+@defcom[com "Next Interactive Input",  
+        stuff (bound to @bf[M-n] in @hid[Typescript] and @hid[Eval] modes)]
+@defcom1[com "Previous Interactive Input",
+        stuff (bound to @bf[M-p] in @hid[Typescript] and @hid[Eval] modes)]
+@defcom1[com "Search Previous Interactive Input",
+	stuff (bound to @bf[M-P] in @hid[Typescript] and @hid[Eval] modes)]
+@defhvar1[var "Interactive History Length", val {10}]
+@defhvar1[var "Minimum Interactive Input Length", val {2}]
+@index[history, typescript]
+@Hemlock maintains a history of interactive inputs.  @hid[Next Interactive
+Input] and @hid[Previous Interactive Input] step forward and backward in the
+history, inserting the current entry in the buffer.  The prefix argument is
+used as a repeat count.
+
+@hid[Search Previous Interactive Input] searches backward through the
+interactive history using the current input as a search string.  Consecutive
+invocations repeat the previous search.
+
+@hid[Interactive History Length] determines the number of entries with which
+@hemlock creates the buffer-specific histories.  @Hemlock only adds an input
+region to the history if its number of characters exceeds @hid[Minimum
+Interactive Input Length].
+@enddefcom
+
+@defcom[com "Reenter Interactive Input",
+	stuff (bound to @bf[C-Return] in @hid[Typescript] and @hid[Eval] modes)]
+ This copies to the end of the buffer the form to the left of the buffer's
+point.  When the current region is active, this copies it instead.  This is
+sometimes easier to use to get a previous input that is either so far back that
+it has fallen off the history or is visible and more readily @i[yanked] than
+gotten with successive invocations of the history commands.
+@enddefcom
+
+@defcom[com "Interactive Beginning of Line", 
+        stuff (bound to @bf[C-a] in @hid[Typescript] and @hid[Eval] modes)]
+This command is identical to @hid[Beginning of Line] unless there is no
+prefix argument and the point is on the same line as the start of the current
+input; then it moves to the beginning of the input.  This is useful since it
+skips over any prompt which may be present.
+@enddefcom
+
+@defhvar[var "Input Wait Alarm", val {:loud-message}]
+This variable determines what action is taken when a process goes into an input
+wait on a typescript that isn't currently displayed in any window.  These
+values are legal:
+@begin[description]
+@kwd[loud-message]@\Beep and display a message in the echo area indicating
+which buffer is waiting for input.
+
+@kwd[message]@\Display a message, but don't beep.
+
+@nil@\Don't do anything.
+@end[description]
+@enddefhvar
+
+@defcom[com "Typescript Slave BREAK", bind (Typescript: H-b)]
+@defcom1[com "Typescript Slave to Top Level", bind (Typescript: H-g)]
+Some typescripts have associated information which these commands access
+allowing @hemlock to control the process which uses the typescript.
+
+@hid[Typescript Slave BREAK] puts the current process in a break loop so that
+you can be debug it.  This is similar in effect to an interrupt signal (@f[^C]
+or @f[^\] in the editor process).
+
+@hid[Typescript Slave to Top Level] causes the current process to throw to the
+top-level @f[read-eval-print] loop.  This is similar in effect to a quit signal
+(@f[^\]).
+@enddefcom
+
+
+@section[The Current Package]
+@label[lisp-package]
+@index[package]
+The current package is the package which Lisp interaction commands use.  The
+current package is specified on a per-buffer basis, and defaults to "@f[USER]".
+If the current package does not exist in the eval server, then it is created.
+If evaluation is being done in the editor process and the current package
+doesn't exist, then the value of @f[*package*] is used.  The current package is
+displayed in the modeline (see section @ref[modelines].)  Normally the package
+for each file is specified using the @f[Package] file option (see page
+@pageref[file-options].)
+
+When in a slave buffer, the current package is controlled by the value of
+@var[package] in that Lisp process.  Modeline display of the current package
+is inhibited in this case.
+
+@defcom[com "Set Buffer Package"]
+This command prompts for the name of a package to make the local package in the
+current buffer.  If the current buffer is a slave, background, or eval buffer,
+then this sets the current package in the associated eval server or editor
+Lisp.  When in an interactive buffer, do not use @f[in-package]; use this
+command instead.
+@enddefcom
+
+
+@section[Compiling and Evaluating Lisp Code]
+
+@index[compilation]@index[evaluation]These commands can greatly speed up
+the edit/debug cycle since they enable incremental reevaluation or
+recompilation of changed code, avoiding the need to compile and load an
+entire file.  
+
+@defcom[com "Evaluate Expression", bind (M-Escape)]
+This command prompts for an expression and prints the result of its evaluation
+in the echo area.  If an error happens during evaluation, the evaluation is
+simply aborted, instead of going into the debugger.  This command doesn't
+return until the evaluation is complete.
+@enddefcom
+
+@defcom[com "Evaluate Defun", bind (C-x C-e)]
+@defcom1[com "Evaluate Region"]
+@defcom1[com "Evaluate Buffer"]
+These commands evaluate text out of the current buffer, reading the current
+defun, the region and the entire buffer, respectively.  The result of the
+evaluation of each form is displayed in the echo area.  If the region is
+active, then @hid[Evaluate Defun] evaluates the current region, just like 
+@hid[Evaluate Region].
+@enddefcom
+
+@defcom[com "Macroexpand Expression", bind (C-M)]
+This command shows the macroexpansion of the next expression in the null
+environment in a pop-up window.  With an argument, it uses @f[macroexpand]
+instead of @f[macroexpand-1].
+@enddefcom
+
+@defcom[com "Re-evaluate Defvar"]
+This command is similar to @hid[Evaluate Defun].  It is used for force the
+re-evaluation of a @f[defvar] init form.  If the current top-level form is a
+@f[defvar], then it does a @f[makunbound] on the variable, and evaluates the
+form.
+@enddefcom
+
+@defcom[com "Compile Defun", bind (C-x C-c)]
+@defcom1[com "Compile Region"]
+These commands compile the text in the current defun and the region,
+respectively.  If the region is active, then @hid[Compile Defun] compiles the
+current region, just like @hid[Compile Region].
+@enddefcom
+
+@defcom[com "Load File"]
+@defhvar1[var "Load Pathname Defaults", val {nil}]
+This command prompts for a file and loads it into the current eval server using
+@f[load].  @hid[Load Pathname Defaults] contains the default pathname for this
+command.  This variable is set to the file loaded; if it is @nil, then there is
+no default.  This command also uses the @hid[Remote Compile File] variable.
+@enddefcom
+
+
+@section[Compiling Files]
+These commands are used to compile source ("@f[.lisp]") files, producing binary
+("@f[.fasl]") output files.  Note that unlike the other compiling and evalating
+commands, this does not have the effect of placing the definitions in the
+environment; to do so, the binary file must be loaded.
+
+@defcom[com "Compile Buffer File", bind (C-x c)]
+@defhvar1[var "Compile Buffer File Confirm", val {t}]
+This command asks for confirmation, then saves the current buffer (when
+modified) and compiles the associated file.  The confirmation prompt indicates
+intent to save and compile or just compile.  If the buffer wasn't modified, and
+a comparison of the write dates for the source and corresponding binary
+("@f[.fasl]") file suggests that recompilation is unnecessary, the confirmation
+also indicates this.  A prefix argument overrides this test and forces
+recompilation.  Since there is a complete log of output in the background
+buffer, the creation of the normal error output ("@f[.err]") file is inhibited.
+
+Setting @hid[Compile Buffer File Confirm] to @nil inhibits confirmation, except
+when the binary is up to date and a prefix argument is not supplied.
+@enddefcom
+
+@defcom[com "Compile File"]
+This command prompts for a file and compiles that file, providing a convenient
+way to compile a file that isn't in any buffer.  Unlike 
+@hid[Compile Buffer File], this command doesn't do any consistency checks such
+as checking whether the source is in a modified buffer or the binary is up to
+date.
+@enddefcom
+
+@defcom[com "Compile Group"]
+@defcom1[com "List Compile Group"]
+@label[compile-group-command]@index[group, compilation]@hid[Compile Group] does
+a @hid[Save All Files] and then compiles every "@f[.lisp]" file for which the
+corresponding "@f[.fasl]" file is older or nonexistent.  The files are compiled
+in the order in which they appear in the group definition.  A prefix argument
+forces compilation of all "@f[.lisp]" files.
+
+@hid[List Compile Group] lists any files that would be compiled by
+@hid[Compile Group].  All Modified files are saved before checking to generate
+a consistent list.
+@enddefcom 
+
+@defcom[com "Set Compile Server"]
+@defcom1[com "Set Buffer Compile Server"]
+@defcom1[com "Current Compile Server"]
+These commands are analogous to @hid[Set Eval Server], @comref[Set Buffer Eval
+Server] and @hid[Current Eval Server], but they determine the eval server used
+for file compilation requests.  If the user specifies a compile server, then
+the file compilation commands send compilation requests to that server instead
+of the current eval server.
+
+Having a separate compile server makes it easy to do compilations in the
+background while continuing to interact with your eval server and editor.  The
+compile server can also run on a remote machine relieving your active
+development machine of the compilation effort.
+@enddefcom
+
+@defcom[com "Next Compiler Error", bind (H-n)]
+@defcom1[com "Previous Compiler Error", bind (H-p)]
+These commands provides a convenient way to inspect compiler errors.  First it
+splits the current window if there is only one window present.  @hemlock
+positions the current point in the first window at the erroneous source code
+for the next (or previous) error.  Then in the second window, it displays the
+error beginning at the top of the window.  Given an argument, this command
+skips that many errors.
+@enddefcom
+
+@defcom[com "Flush Compiler Error Information"]
+This command relieves the current eval server of all infomation about errors
+encountered while compiling.  This is convenient if you have been compiling a
+lot, but you were ignoring errors and warnings.  You don't want to step through
+all the old errors, so you can use this command immediately before compiling a
+file whose errors you intend to edit.
+@enddefcom
+
+
+@defhvar[var "Remote Compile File", val {nil}]
+When true, this variable causes file compilations to be done using the RFS
+remote file system mechanism by prepending "@f[/../]@i[host]" to the file being
+compiled.  This allows the compile server to be run on a different machine, but
+requires that the source be world readable.  If false, commands use source
+filenames directly.  Do NOT use this to compile files in AFS.
+@enddefhvar
+
+
+@section[Querying the Environment]
+@index[documentation, lisp]
+These commands are useful for obtaining various random information from the
+Lisp environment.
+
+@defcom[com "Describe Function Call", bind (C-M-A)]
+@defcom1[com "Describe Symbol", bind (C-M-S)]
+@hid[Describe Function Call] uses the current eval server to describe the
+symbol found at the head of the currently enclosing list, displaying the output
+in a pop-up window.  @hid[Describe Symbol] is the same except that it describes
+the symbol at or before the point.  These commands are primarily useful for
+finding the documentation for functions and variables.  If there is no
+currently valid eval server, then this command uses the editor Lisp's
+environment instead of trying to spawn a slave.
+@enddefcom
+
+
+@section[Editing Definitions]
+The Lisp compiler annotates each compiled function object with the source
+file that the function was originally defined from.  The definition editing
+commands use this information to locate and edit the source for functions
+defined in the environment.
+
+@defcom[com "Edit Definition"]
+@defcom1[com "Goto Definition", bind (C-M-F)]
+@defcom1[com "Edit Command Definition"]
+@hid[Edit Definition] prompts for the name of a function, and then uses the
+current eval server to find out in which file the function is defined.  If
+something other than @f[defun] or @f[defmacro] defined the function, then this
+simply reads in the file, without trying to find its definition point within
+the file.  If the function is uncompiled, then this looks for it in the current
+buffer.  If there is no currently valid eval server, then this command uses the
+editor Lisp's environment instead of trying to spawn a slave.
+
+@hid[Goto Definition] edits the definition of the symbol at the beginning of
+the current list.
+
+@hid[Edit Command Definition] edits the definition of a @hemlock command.  By
+default, this command does a keyword prompt for the command name (as in an
+extended command).  If a prefix argument is specified, then instead prompt for
+a key and edit the definition of the command bound to that key.
+@enddefcom
+
+@defcom[com "Add Definition Directory Translation"]
+@defcom1[com "Delete Definition Directory Translation"]
+The defining file is recorded as an absolute pathname.  The definition editing
+commands have a directory translation mechanism that allow the sources to be
+found when they are not in the location where compilation was originally done.
+@hid[Add Definition Directory Translation] prompts for two directory
+namestrings and causes the first to be mapped to the second.  Longer (more
+specific) directory specifications are matched before shorter (more general)
+ones.
+
+@hid[Delete Definition Directory Translation] prompts for a directory
+namestring and deletes it from the directory translation table.
+@enddefcom
+
+@defhvar[var "Editor Definition Info", val {nil}]
+When this variable is true, the editor Lisp is used to determine definition
+editing information, otherwise the current eval server is used.  This variable
+is true in @hid[Eval] and @hid[Editor] modes.
+@enddefhvar
+
+
+@section[Manipulating the Editor Process]
+When developing @hemlock customizations, it is useful to be able to manipulate
+the editor Lisp environment from @hemlock.
+
+@defcom[com "Editor Describe", bind (Home t, C-_ t)]
+This command prompts for an expression, and then evaluates and describes it
+in the editor process.
+@enddefcom
+
+@defcom[com "Room"]
+Call the @f[room] function in the editor process, displaying information
+about allocated storage in a pop-up window.
+@enddefcom
+
+@defcom[com "Editor Load File"]
+This command is analogous to @comref[Load File], but loads the file into the
+editor process.
+@enddefcom
+
+
+@subsection[Editor Mode]
+When @hid[Editor] mode is on, alternate versions of the Lisp interaction
+commands are bound in place of the eval server based commands.  These commands
+manipulate the editor process instead of the current eval server.  Turning on
+editor mode in a buffer allows incremental development of code within the
+running editor.
+
+@defcom[com "Editor Mode"]
+This command turns on @hid[Editor] minor mode in the current buffer.  If it is
+already on, it is turned off.  @hid[Editor] mode may also be turned on using
+the @f[Mode] file option (see page @pageref[file-options].)
+@enddefcom
+
+@defcom[com "Editor Compile Defun",
+	stuff (bound to @bf[C-x C-c] in @hid[Editor] mode)]
+@defcom1[com "Editor Compile Region"]
+@defcom1[com "Editor Evaluate Buffer"]
+@defcom1[com "Editor Evaluate Defun",
+	stuff (bound to @bf[C-x C-e] in @hid[Editor] mode)]
+@defcom1[com "Editor Evaluate Region"]
+@defcom1[com "Editor Macroexpand Expression", bind (Editor: C-M)]
+@defcom1[com "Editor Re-evaluate Defvar"]
+@defcom1[com "Editor Describe Function Call",
+	stuff (bound to @bf[C-M-A] in @hid[Editor] mode)]
+@defcom1[com "Editor Describe Symbol",
+	stuff (bound to @bf[C-M-S] in @hid[Editor] mode)]
+These commands are similar to the standard commands, but modify or examine the
+Lisp process that @hemlock is running in.  Terminal I/O is done on the
+initial window for the editor's Lisp process.  Output is directed to a pop-up
+window or the editor's window instead of to the background buffer.
+@enddefcom
+
+@defcom[com "Editor Compile Buffer File"]
+@defcom1[com "Editor Compile File"]
+@defcom1[com "Editor Compile Group"]
+In addition to compiling in the editor process, these commands differ from the
+eval server versions in that they direct output to the the 
+@hid[Compiler Warnings] buffer.
+@enddefcom
+
+@defcom[com "Editor Evaluate Expression",
+     stuff (bound to @bf[M-Escape] in @hid[Editor] mode and @bf[C-M-Escape])] 
+This command prompts for an expression and evaluates it in the editor process.
+The results of the evaluation are displayed in the echo area.
+@enddefcom
+
+
+@subsection[Eval Mode]
+@label[eval-mode]
+@index[modes, eval]@hid[Eval] mode is a minor mode that simulates a @f[read]
+@f[eval] @f[print] loop running within the editor process.  Since Lisp
+program development is usually done in a separate eval server process (see page
+@pageref[eval-servers]), @hid[Eval] mode is used primarily for debugging code
+that must run in the editor process.  @hid[Eval] mode shares some commands with
+@hid[Typescript] mode: see section @ref[typescripts].
+
+@hid[Eval] mode doesn't completely support terminal I/O: it binds
+@var[standard-output] to a stream that inserts into the buffer and
+@var[standard-input] to a stream that signals an error for all operations.
+@hemlock cannot correctly support the interactive evaluation of forms that read
+from the @hid[Eval] interactive buffer.
+
+@defcom[com "Select Eval Buffer"]
+This command changes to the @hid[Eval] buffer, creating one if it doesn't
+already exist.  The @hid[Eval] buffer is created with @hid[Lisp] as the major
+mode and @hid[Eval] and @hid[Editor] as minor modes. 
+@enddefcom
+
+@defcom[com "Confirm Eval Input",
+        stuff (bound to @bf[Return] in @hid[Eval] mode)]
+This command evaluates all the forms between the end of the last output and
+the end of the buffer, inserting the results of their evaluation in the buffer.
+This beeps if the form is incomplete.  Use @binding[Linefeed] to insert line
+breaks in the middle of a form.
+
+This command uses @hid[Unwedge Interactive Input Confirm] in the same way
+@hid[Confirm Interactive Input] does.
+@enddefcom
+
+@defcom[com "Abort Eval Input", 
+        stuff (bound to @bf[M-i] in @hid[Eval] mode)]
+This command moves the the end of the buffer and prompts, ignoring any
+input already typed in.
+@enddefcom
+
+
+@subsection[Error Handling]
+@index[error handling]
+When an error happens inside of @hemlock, @hemlock will trap the error and
+display the error message in the echo area, possibly along with the
+"@f[Internal error:]" prefix.  If you want to debug the error, type @bf[?].
+This causes the prompt "@f[Debug:]" to appear in the echo area.  The following
+commands are recognized:
+@begin[description]
+@bf[d]@\Enter a break-loop so that you can use the Lisp debugger.
+Proceeding with "@f[go]" will reenter @hemlock and give the "@f[Debug:]"
+prompt again.
+
+@bf[e]@\Display the original error message in a pop-up window.
+
+@bf[b]@\Show a stack backtrace in a pop-up window.
+
+@bf[q, Escape]@\Quit from this error to the nearest command loop.
+
+@bf[r]@\Display a list of the restart cases and prompt for the number of a
+@f[restart-case] with which to continue.  Restarting may result in prompting in
+the window in which Lisp started.
+@end[description]
+
+Only errors within the editor process are handled in this way.  Errors during
+eval server operations are handled using normal terminal I/O on a typescript in
+the eval server's slave buffer or background buffer (see page
+@pageref[operations]).  Errors due to interaction in a slave buffer will cause
+the debugger to be entered in the slave buffer.
+
+
+@section[Command Line Switches]
+@label[slave-switch]
+Two command line switches control the initialization of editor and eval servers
+for a Lisp process:
+@begin[description]
+@f<-edit>@\
+@label[edit-switch]
+This switch starts up @hemlock.  If there is a non-switch command line word
+immediately following the program name, then the system interprets it as a file
+to edit.  For example, given
+@Begin[ProgramExample]
+lisp file.txt -edit
+@End[ProgramExample]
+Lisp will go immediately into @hemlock finding the file @f[file.txt].
+
+@f<-slave [>@i[name]@f<]>@\
+ This switch causes the Lisp process to become a slave of the editor process
+@i[name].  An editor Lisp determines @i[name] when it allows connections from
+slaves.  Once the editor chooses a name, it keeps the same name until the
+editor's Lisp process terminates.  Since the editor can automatically create
+slaves on its own machine, this switch is useful primarily for creating slaves
+that run on a different machine.  @f[hqb]'s machine is @f[ME.CS.CMU.EDU], and
+he wants want to run a slave on @f[SLAVE.CS.CMU.EDU], then he should use the
+@hid[Accept Slave Connections] command, telnet to the machine, and invoke Lisp
+supplying @f[-slave] and the editor's name.  The command displays the editor's
+name.
+@end[description]
diff --git a/docs/hem/user/mail.mss b/docs/hem/user/mail.mss
new file mode 100644
index 000000000..a82c77368
--- /dev/null
+++ b/docs/hem/user/mail.mss
@@ -0,0 +1,1346 @@
+@comment{-*- Dictionary: bld:scribe/hem/hem; Mode: spell; Package: Hemlock -*-}
+@chap[The Hemlock Mail Interface]
+@section[Introduction to Mail in Hemlock]
+
+@index[MH interface]@label[introduction]
+@hemlock provides an electronic mail handling facility via an interface to the
+public domain @i[Rand MH Message Handling System].  This chapter assumes that
+the user is familiar with the basic features and operation of @mh, but it
+attempts to make allowances for beginners.  Later sections of this chapter
+discuss setting up @mh, profile components and special files for formatting
+outgoing mail headers, and backing up protected mail directories on a
+workstation.  For more information on @mh, see the @i[Rand MH Message Handling
+System Tutorial] and the @i[Rand MH Message Handling System Manual].
+
+The @hemlock interface to @mh provides a means for generating header (@f[scan])
+lines for messages and displaying these headers in a @hid[Headers] buffer.
+This allows the user to operate on the @i[current message] as indicated by the
+position of the cursor in the @hid[Headers] buffer.  The user can read, reply
+to, forward, refile, or perform various other operations on the current
+message.  A user typically generates a @hid[Headers] buffer with the commands
+@hid[Message Headers] or @hid[Incorporate and Read New Mail], and multiple such
+buffers may exist simultaneously.
+
+Reading a message places its text in a @hid[Message] buffer.  In a manner
+similar to a @hid[Headers] buffer, this allows the user to operate on that
+message.  Most @hid[Headers] buffer commands behave the same in a @hid[Message]
+buffer.  For example, the @hid[Reply to Message] command has the same effect in
+both @hid[Headers] mode and @hid[Message] mode.  It creates a @hid[Draft]
+buffer and makes it the current buffer so that the user may type a reply to the
+current message.
+
+The @hid[Send Message] command originates outgoing mail.  It generates a
+@hid[Draft] buffer in which the user composes a mail message.  Each @hid[Draft]
+buffer has an associated pathname, so the user can save the buffer to a file as
+necessary.  Invoking @hid[Send Message] in a @hid[Headers] or @hid[Message]
+buffer associates the @hid[Draft] buffer with a @hid[Message] buffer.  This
+allows the user to easily refer to the message being replied to with the
+command @hid[Goto Message Buffer].  After the user composes a draft message, he
+can deliver the message by invoking the @hid[Deliver Message] command in the
+@hid[Draft] buffer (which deletes both the this buffer and any associated
+@hid[Message] buffer), or he can delay this action.  Invoking @hid[Deliver
+Message] when not in a @hid[Draft] buffer causes it to prompt for a draft
+message ID, allowing previously composed and saved messages to be delivered
+(even across distinct Lisp invocations).
+
+@index[virtual message deletion]
+The @hemlock mail system provides a mechanism for @i[virtual message deletion].
+That is, the @hid[Delete Message] command does not immediately delete a message
+but merely flags the message for future deletion.  This allows the user to
+undelete the messages with the @hid[Undelete Message] command.  The
+@hid[Expunge Messages] command actually removes messages flagged for deletion.
+After expunging a deleted message, @hid[Undelete Messages] can no longer
+retrieve it.  Commands that read messages by sequencing through a @hid[Headers]
+buffer typically ignore those marked for deletion, which makes for more fluid
+reading if a first pass has been made to delete uninteresting messages.
+
+After handling messages in a @hid[Headers] buffer, there may be messages
+flagged for deletion and possibly multiple @hid[Message] buffers lying around.
+There is a variety of commands that help @i[terminate] a mail session.
+@hid[Expunge Messages] will flush the messages to be deleted, leaving the
+buffer in an updated state.  @hid[Delete Headers Buffer and Message Buffers]
+will delete the @hid[Headers] buffer and its corresponding @hid[Message]
+buffers.  @hid[Quit Headers] is a combination of these two commands in that it
+first expunges messages and then deletes all the appropriate buffers.
+
+One does not have to operate only on messages represented in a @hid[Headers]
+buffer.  This is merely the nominal mode of interaction.  There are commands
+that prompt for a folder, an @mh message specification (for example, "@f[1 3 6
+last]", "@f[1-3 5 6]", "@f[all]", "@f[unseen]"), and possibly a @f[pick]
+expression.  @f[Pick] expressions allow messages to be selected based on header
+field pattern matching, body text searching, and date comparisons; these can be
+specified using either a Unix shell-like/switch notation or a Lisp syntax,
+according to one's preference.  See section @ref[scanning] for more details.
+
+A @i[mail-drop] is a file where a Unix-based mail system stores all messages a
+user receives.  The user's mail handling program then fetches these from the
+mail-drop, allowing the user to operate on them.  Traditionally one locates his
+mail-drop and mail directory on a mainframe machine because the information on
+mainframes is backed up on magnetic tape at least once per day.  Since @hemlock
+only runs under CMU @clisp on workstations, and one's mail directory is not
+usually world writable, it is not possible to adhere to a standard arrangement.
+Since @mh provides for a remote mail-drop, and CMU's Remote File System has a
+feature allowing authentication across a local area network, one can use
+@hemlock to fetch his mail from a mainframe mail-drop (where it is backed up
+before @hemlock grabs it) and store it on his workstation.  Reading mail on a
+workstation is often much faster and more comfortable because typically it is a
+single user machine.  Section @ref[backing-up] describes how to back up one's
+mail directory from a workstation to a mainframe.
+
+
+@section[Constraints on MH to use Hemlock's Interface]
+
+@index[constraints for mail interface]@label[constraints]
+There are a couple constaints placed on the user of the @hemlock interface to
+@mh.  The first is that there must be a draft folder specified in one's @mh
+profile to use any command that sends mail.  Also, to read new mail, there must
+be an @f[Unseen-Sequence:] component in one's @mh profile.  The default @mh
+profile does not specify these components, so they must be added by the user.
+The next section of this chapter describes how to add these components.
+Another constraint is that @hemlock requires its own @f[scan] line format to
+display headers lines in a @hid[Headers] buffer.  See the description of the
+variable @hid[MH Scan Line Form] for details.
+
+
+@section[Setting up MH]
+
+@index[setting up the mail interface]@label[setting-up]
+@index[mail profile]@index[MH profile]
+Get an @mh default profile and mail directory by executing the @mh @f[folder]
+utility in a Unix shell.  When it asks if it should make the "@f[inbox]"
+folder, answer "@b[yes]".  This creates a file called "@f[.mh_profile]" in the
+user's home directory and a directory named "@f[Mail]".
+
+Edit the "@f[.mh_profile]" file inserting two additional lines.  To send mail
+in @hemlock, the user must indicate a draft folder by adding a
+@f[Draft-Folder:] line with a draft folder name @dash "@f[drafts]" is a common
+name:
+@begin[example]
+Draft-Folder: drafts
+@end[example]
+
+Since the mail-drop exists on a remote machine, the following line must
+also be added:
+@begin[example]
+MailDrop: /../<hostname>/usr/spool/mail/<username>
+@end[example]
+
+Since the user's mail-drop is on a separate machine from his mail directory
+(and where the user runs @hemlock), it is necessary to issue the following
+command from the Unix shell (on the workstation).  This only needs to be done
+once.
+@begin[programexample]
+/usr/cs/etc/rfslink -host <hostname> /usr/spool/mail/<username>
+@end[programexample]
+Note that @b[<hostname>] is not a full ARPANET domain-style name.  Use an
+abbreviated CMU host name (for example, "@b[spice]" not
+"@b[spice.cs.cmu.edu]").
+
+
+@section[Profile Components and Customized Files]
+
+@subsection[Profile Components]
+
+@label[Profile] 
+The following are short descriptions about profile components that are either
+necessary to using @hemlock's interface to @mh or convenient for using @mh in
+general:
+
+@begin[description]
+@f[Path:]@\
+This specifies the user's mail directory.  It can be either a full pathname or
+a pathname relative to the user's home directory.  This component is
+@i[necessary] for using @mh.
+
+@f[MailDrop:]@\
+This is used to specify one's remote mail-drop.  It is @i[necessary] for
+@hemlock only when using a mail-drop other than "@f[/usr/spool/mail/<user>]" on
+the local machine.
+
+@f[Folder-Protect:], @f[Msg-Protect:]@\
+These are set to 700 and 600 respectively to keep others from reading one's
+mail.  At one time the default values were set for public visibility of mail
+folders.  Though this is no longer true, these can be set for certainty.  The
+700 protection allows only user read, write, and execute (list access for
+directories), and 600 allows only user read and write.  These are not necessary
+for either @mh or the @hemlock interface.
+
+@f[Unseen-Sequence:]@\
+When mail is incorporated, new messages are added to this sequence, and as
+these messages are read they are removed from it.  This allows the user at any
+time to invoke an @mh program on all the unseen messges of a folder easily.  An
+example definition is:
+@begin[example]
+Unseen-Sequence: unseen
+@end[example]
+Specifying an unseen-sequence is @i[necessary] to use @hemlock's
+interface to @mh.
+
+@f[Alternate-Mailboxes:]@\
+This is not necessary for either @mh or the @hemlock interface.  This
+component tells @mh which addresses that it should recognize as the user.  This
+is used for @f[scan] output formatting when the mail was sent by the user.  It
+is also used by @f[repl] when it sets up headers to know who the user is for
+inclusion or exclusion from @b[cc]: lists.  This is case sensitive and takes
+wildcards.  One example is:
+@begin[example]
+Alternate-Mailboxes: *FRED*, *Fred*, *fred*
+@end[example]
+
+@f[Draft-Folder:]@\
+This makes multiple draft creation possible and trivial to use.  Just supply a
+folder name (for example, "@f[drafts]").  Specifying a draft-folder is
+@i[necessary] to use @hemlock's interface to @mh.
+
+@f[repl: -cc all -nocc me -fcc out-copy]@\
+This tells the @f[repl] utility to include everyone but the user in the
+@b[cc:] list when replying to mail.  It also makes @f[repl] keep an copy of the
+message the user sends.  This is mentioned because one probably wants to reply
+to everyone receiving a piece of mail except oneself.  Unlike other utilities
+that send mail, @f[repl] stores personal copies of outgoing mail based on a
+command line switch.  Other @mh utilities use different mechanisms.  This line
+is not necessary to use either @mh or the @hemlock interface.
+
+@f[rmmproc: /usr/cs/bin/rm]@\
+This is not necessary to use @hemlock's interface to @mh, but due to
+@hemlock's virtual message deletion feature, this causes messages to be deleted
+from folder directories in a cleaner fashion when they actually get removed.
+Note that setting this makes @f[rmm] more treacherous if used in the Unix
+shell.
+@end[description]
+@;
+
+
+@subsection[Components Files]
+@index[components]
+@label[components-files]
+@i[Components] files are templates for outgoing mail header fields that specify
+position and sometimes values for specified fields.  Example files are shown
+for each one discussed here.  These should exist in the user's mail directory.
+
+For originating mail there is a components file named "@f[components]", and it
+is used by the @mh utility @f[comp].  An example follows:
+@begin[example]
+   To: 
+   cc: 
+   fcc: out-copy
+   Subject: 
+   --------
+@end[example]
+This example file differs from the default by including the @f[fcc:] line.
+This causes @mh to keep a copy of the outgoing draft message.  Also, though it
+isn't visible here, the @f[To:], @f[cc:], and @f[Subject:] lines have a space
+at the end.
+
+@index[forwarding components]
+The "@f[forwcomps]" components file is a template for the header fields of any
+forwarded message.  Though it may be different, our example is the same as the
+previous one.  These are distinct files for @mh's purposes, and it is more
+flexible since the user might not want to keep copies of forwarded messages.
+
+@index[reply components]
+The "@f[replcomps]" components file is a template for the header fields of any
+draft message composed when replying to a message.  An example
+follows:
+@begin[example]
+   %(lit)%(formataddr %<{reply-to}%|%<{from}%|%{sender}%>%>)\
+   %<(nonnull)%(void(width))%(putaddr To: )\n%>\
+   %(lit)%(formataddr{to})%(formataddr{cc})%(formataddr(me))\
+   %(formataddr{resent-to})\
+   %<(nonnull)%(void(width))%(putaddr cc: )\n%>\
+   %<{fcc}Fcc: %{fcc}\n%>\
+   %<{subject}Subject: Re: %{subject}\n%>\
+   %<{date}In-reply-to: Your message of \
+   %<(nodate{date})%{date}%|%(tws{date})%>.%<{message-id}
+		%{message-id}%>\n%>\
+   --------
+@end[example]
+This example file differs from the default by including the @b[resent-to:]
+field (in addition to the @b[to:] and @b[cc:] fields) of the message being
+replied to in the @b[cc:] field of the draft.  This is necessary for replying
+to all recipients of a distributed message.  Keeping a copy of the outgoing
+draft message works a little differently with reply components.  @mh expects a
+switch which the user can put in his profile (see section @ref[Profile] of this
+chapter), and using the @mh formatting language, this file tests for the
+@f[fcc] value as does the standard file.
+
+
+@section[Backing up the Mail Directory]
+@index[backing up mail directories]
+@label[backing-up]
+The easiest method of backing up a protected mail directory is to copy it into
+an Andrew File System (AFS) directory since these are backed up daily as with
+mainframes.  The only problem with this is that the file servers may be down
+when one wants to copy his mail directory since, at the time of this writing,
+these servers are still under active development; however, they are becoming
+more robust daily.  One can read about the current AFS status in the file
+@f[/../fac/usr/gripe/doc/vice/status].
+
+Using AFS, one could keep his actual mail directory (not a copy thereof) in his
+AFS home directory which eliminates the issue of backing it up.  This is
+additionally beneficial if the user does not use the same workstation everyday
+(that is, he does not have his own but shares project owned machines).  Two
+problems with this arrangement result from the AFS being a distributed file
+system.  Besides the chance that the server will be down when the user wants to
+read mail, performance degrades since messages must always be referenced across
+the local area network.
+
+Facilities' official mechanism for backing up protected directories is called
+@f[sup].  This is awkward to use and hard to set up, but a subsection here
+describes a particular arrangement suitable for the user's mail directory.
+
+
+@subsection[Andrew File System]
+If the user choses to use AFS, he should get copies of @i[Getting Started with
+the Andrew File System] and @i[Protecting AFS files and directories].  To use
+AFS, send mail to Gripe requesting an account.  When Gripe replies with a
+password, change it to be the same as the account's password on the
+workstation.  This causes the user to be authenticated into AFS when he logs
+into his workstation (that is, he is automatically logged into his AFS
+account).  To change the password, first log into the AFS account:
+@begin[programexample]
+log <AFS userid>
+@end[programexample]
+Then issue the @f[vpasswd] command.
+
+All of the example command lines in this section assume the user has
+@f[/usr/misc/bin] on his Unix shell @f[PATH] environment variable.
+
+@paragraph[Copy into AFS:]
+
+Make an AFS directory to copy into:
+@begin[programexample]
+mkdir /afs/cs.cmu.edu/user/<AFS userid>/mail-backup
+@end[programexample]
+
+This will be readable by everyone, so protect it with the following:
+@begin[programexample]
+fs sa /afs/cs.cmu.edu/user/<AFSuserid>/mail-backup System:AnyUser none
+@end[programexample]
+
+Once the AFS account and directory to backup into have been established, the
+user needs a means to recursively copy his mail directory updating only those
+file that have changed and deleting those that no longer exist.  To do this,
+issue the following command:
+@begin[programexample]
+copy -2 -v -R <mail directory> <AFS backup directory>
+@end[programexample]
+Do not terminate either of these directory specifications with a @f[/].  The
+@f[-v] switch causes @f[copy] to output a line for copy and deletion, so this
+may be eliminated if the user desires.
+
+@paragraph[Mail Directory Lives in AFS:]
+
+Assuming the AFS account has been established, and the user has followed the
+directions in @ref[setting-up], now make an AFS directory to serve as the mail
+directory:
+@begin[programexample]
+mkdir /afs/cs.cmu.edu/user/<AFS userid>/Mail
+@end[programexample]
+
+This will be readable by everyone, so protect it with the following:
+@begin[programexample]
+fs sa /afs/cs.cmu.edu/user/<AFSuserid>/Mail System:AnyUser none
+@end[programexample]
+
+Tell @mh where the mail directory is by modifying the profile's
+"@f[.mh_profile]" (see section @ref[setting-up]) @f[Path:] component (see
+section @ref[Profile]):
+@begin[programexample]
+Path: /afs/cs.cmu.edu/user/<AFS userid>/Mail
+@end[programexample]
+
+
+@subsection[Sup to a Mainframe]
+To use @f[sup] the user must set up a directory named "@f[sup]" on the
+workstation in the user's home directory.  This contains different directories
+for the various trees that will be backed up, so there will be a "@f[Mail]"
+directory.  This directory will contain two files: "@f[crypt]" and "@f[list]".
+The "@f[crypt]" file contains one line, terminated with a new line, that
+contains a single word @dash an encryption key.  "@f[list]" contains one line,
+terminated with a new line, that contains two words @dash "@b[upgrade Mail]".
+
+On the user's mainframe, a file must be created that will be supplied to the
+@f[sup] program.  It should contain the following line to backup the mail
+directory:
+
+@begin[example]
+Mail delete host=<workstation> hostbase=/usr/<user> base=/usr/<user> \
+crypt=WordInCryptFile login=<user> password=LoginPasswordOnWorkstation
+@end[example]
+Warning: @i[This file contains the user's password and should be
+protected appropriately.] 
+
+The following Unix shell command issued on the mainframe will backup the
+mail directory:
+
+@begin[programexample]
+   sup <name of the sup file used in previous paragraph>
+@end[programexample]
+
+As a specific example, assume user "@f[fred]" has a workstation called
+"@f[fred]", and his mainframe is the "@f[gpa]" machine where he has another
+user account named "@f[fred]".  The password on his workstation is
+"@f[purple]".  On his workstation, he creates the directory
+"@f[/usr/fred/sup/Mail/]" with the two files "@f[crypt]" and "@f[list]".
+The file "@f[/usr/fred/sup/Mail/crypt]" contains only the encryption key:
+@programexample[steppenwolf]
+The file "@f[/usr/fred/sup/Mail/list]" contains the command to upgrade the
+"@f[Mail]" directory:
+@programexample[upgrade Mail]
+
+On the "@f[gpa]" machine, the file "@f[/usr/fred/supfile]" contains the
+following line:
+@begin[programexample]
+Mail delete host=fred hostbase=/usr/fred base=/usr/fred \
+crypt=steppenwolf login=fred password=purple
+@end[programexample]
+This file is protected on "@f[gpa]", so others cannot see @f[fred's] password
+on his workstation.
+
+On the gpa-vax, issuing
+@begin[programexample]
+   sup /usr/fred/supfile
+@end[programexample]
+to the Unix shell will update the @mh mail directory from @f[fred's]
+workstation deleting any files that exist on the gpa that do not exist on the
+workstation.
+
+For a more complete description of the features of @f[sup], see the @i[UNIX
+Workstation Owner's Guide] and @i[The SUP Software Upgrade Protocol].
+
+@section[Introduction to Commands and Variables]
+
+@index[mail commands]@index[mail variables]@label[mhcommands]
+Unless otherwise specified, any command which prompts for a folder name will
+offer the user a default.  Usually this is @mh's idea of the current folder,
+but sometimes it is the folder name associated with the current buffer if there
+is one.  When prompting for a message, any valid @mh message expression may be
+entered (for example, "@f[1 3 6]", "@f[1-3 5 6]", "@f[unseen]", "@f[all]").
+Unless otherwise specified, a default will be offered (usually the current
+message).
+
+Some commands mention specific @mh utilities, so the user knows how the
+@hemlock command affects the state of @mh and what profile components and
+special formatting files will be used.  @hemlock runs the @mh utility programs
+from a directory indicated by the following variable:
+
+@defhvar[var "MH Utility Pathname", val {"/usr/misc/.mh/bin/"}]
+@mh utility names are merged with this pathname to find the executable
+files. 
+@enddefhvar
+
+
+@section[Scanning and Picking Messages]
+@label[scanning]
+As pointed out in the introduction of this chapter, users typically generate
+headers or @f[scan] listings of messages with @hid[Message Headers], using
+commands that operate on the messages represented by the headers.  @hid[Pick
+Headers] (bound to @bf[h] in @hid[Headers] mode) can be used to narrow down (or
+further select over) the headers in the buffer.
+
+A @f[pick] expression may be entered using either a Lisp syntax or a Unix
+shell-like/switch notation as described in the @mh documentation.  The Lisp
+syntax is as follows:
+
+@begin[example]
+   <exp>       ::=  {(not <exp>) | (and <exp>*) | (or <exp>*)
+		    | (cc <pattern>) | (date <pattern>)
+		    | (from <pattern>) | (search <pattern>)
+		    | (subject <pattern>) | (to <pattern>)
+		    | (-- <component> <pattern>)
+		    | (before <date>) | (after <date>)
+		    | (datefield <field>)}
+
+   <pattern>   ::=  {<string> | <symbol>}
+
+   <component> ::=  {<string> | <symbol>}
+
+   <date>      ::=  {<string> | <symbol> | <number>}
+
+   <field>     ::=  <string>
+@end[example]
+
+Anywhere the user enters a @f[<symbol>], its symbol name is used as a string.
+Since @hemlock @f[read]s the expression without evaluating it, single quotes
+("@bf[']") are unnecessary.  From the @mh documentation,
+
+@begin[itemize]
+   A @f[<pattern>] is a Unix @f[ed] regular expression.  When using a string to
+   input these, remember that @f[\] is an escape character in Common Lisp.
+
+   A @f[<component>] is a header field name (for example, @b[reply-to] or
+   @b[resent-to]).
+
+   A @f[<date>] is an @i[822]-style specification, a day of the week,
+   "@b[today]", "@b[yesterday]", "@b[tomorrow]", or a number indicating @i[n]
+   days ago.  The @i[822] standard is basically:
+   @begin[example]
+   dd mmm yy hh:mm:ss zzz
+   @end[example]
+   which is a two digit day, three letter month (first letter capitalized), two
+   digit year, two digit hour (@f[00] through @f[23]), two digit minute, two
+   digit second (this is optional), and a three letter zone (all capitalized).
+   For
+   example:
+   @begin[example]
+   21 Mar 88 16:00 EST
+   @end[example]
+   
+   A @f[<field>] is an alternate @f[Date:] field to use with @f[(before
+   <date>)] and @f[(after <date>)] such as @f[BB-Posted:] or
+   @f[Delivery-Date:].
+
+   Using @f[(before <date>)] and @f[(after <date>)] causes date field parsing,
+   while @f[(date <pattern>)] does string pattern matching.
+@end[itemize]
+
+Since a @f[<pattern>] may be a symbol or string, it should be noted that the
+symbol name is probably all uppercase characters, and @mh will match these
+only against upper case.  @mh will match lowercase characters against lower
+and upper case.  Some examples are:
+@begin[example]
+   ;;; All messages to Gripe.
+   (to "gripe")
+
+   ;;; All messages to Gripe or about Hemlock.
+   (or (to "gripe") (subject "hemlock"))
+
+   ;;; All messages to Gripe with "Hemlock" in the body.
+   (and (to "gripe") (search "hemlock"))
+@end[example]
+
+Matching of @f[<component>] fields is case sensitive, so this example will
+@f[pick] over all messages that have been replied to.
+@example[(or (-- "replied" "") (-- "Replied" ""))]
+
+
+@defhvar[var "MH Scan Line Form", val {"/usr/misc/.lisp/lib/mh-scan"}]
+   This is a pathname of a file containing an @mh format expression used for
+   header lines.
+
+   The header line format must display the message ID as the first
+   non-whitespace item.  If the user uses the virtual message deletion feature
+   which is on by default, there must be a space three characters to the right
+   of the message ID.  This location is used on header lines to note that a
+   message is flagged for deletion.  The second space after the message ID is
+   used for notating answered or replied-to messages.
+@enddefhvar
+
+@defcom[com "Message Headers", bind (C-x r)]
+   This command prompts for a folder, message (defaulting to "@b[all]"), and an
+   optional @f[pick] expression.  Typically this will simply be used to
+   generate headers for an entire folder or sequence, and the @f[pick]
+   expression will not be used.  A new @hid[Headers] buffer is made, and the
+   output of @f[scan] on the messages indicated is inserted into the buffer.
+   The current window is used, the buffer's point is moved to the first header,
+   and the @hid[Headers] buffer becomes current.  The current value of the
+   @hemlock @hid[Fill Column] variable is supplied to @f[scan] as the
+   @f[-width] switch.  The buffer name is set to a string of the form
+   @w<"@f[Headers <folder> <msgs> <pick expression>]">, so the modeline will
+   show what is in the buffer.  If no @f[pick] expression was supplied, none
+   will be shown in the buffer's name.  As described in the introduction to
+   this section, the expression may be entered using either a Lisp syntax or a
+   Unix shell-like/switch notation.
+@enddefcom
+
+@defhvar[var "MH Lisp Expression", val {t}]
+   When this is set, @mh expression prompts are read in a Lisp syntax.
+   Otherwise, the input is of the form of a Unix shell-like/switch notation as
+   described in the @mh documentation.
+@enddefhvar
+
+@defcom[com "Pick Headers", stuff (bound to @bf[h] in @hid[Headers] mode) ]
+   This command is only valid in a @hid[Headers] buffer.  It prompts for a
+   @f[pick] expression, and the messages shown in the buffer are supplied to
+   @f[pick] with the expression.  The resulting messages are @f[scan]'ed,
+   deleting the previous contents of the buffer.  The current value of
+   @hid[Fill Column] is used for the @f[scan]'ing.  The buffer's point is moved
+   to the first header.  The buffer's name is set to a string of the form
+   @w<"@f[Headers <folder> <msgs picked over> <pick expression>]">, so the
+   modeline will show what is in the buffer.  As described in the introduction
+   to this section, the expression may be entered using either a Lisp syntax or
+   a Unix shell-like/switch notation.
+@enddefcom
+
+@defcom[com "Headers Help", bind (Headers: ?)]
+This command displays documentation on @hid[Headers] mode.
+@enddefcom
+
+
+@section[Reading New Mail]
+
+@index[reading new mail]@label[reading-new-mail]
+
+@defcom[com "Incorporate and Read New Mail", stuff (bound to @bf[C-x i] globally and @bf[i] in @hid[Headers] and @hid[Message] modes) ]
+   This command incorporates new mail into @hid[New Mail Folder] and creates a
+   @hid[Headers] buffer with the new messages.  An unseen-sequence must be
+   define in the user's @mh profile to use this.  Any headers generated due to
+   @hid[Unseen Headers Message Spec] are inserted as well.  The buffer's point
+   is positioned on the headers line representing the first unseen message of
+   the newly incorporated mail.
+@enddefcom
+
+@defcom[com "Incorporate New Mail" ]
+   This command incorporates new mail into @hid[New Mail Folder], displaying
+   @f[inc] output in a pop-up window.  This is similar to @hid[Incorporate and
+   Read New Mail] except that no @hid[Headers] buffer is generated.
+@enddefcom
+
+@defhvar[var "New Mail Folder", val {"+inbox"}]
+   This is the folder into which @mh incorporates new mail.
+@enddefhvar
+
+@defhvar[var "Unseen Headers Message Spec", val {nil}]
+   This is an @mh message specification that is suitable for any message
+   prompt.  When incorporating new mail and after expunging messages, @hemlock
+   uses this specification in addition to the unseen-sequence name that is
+   taken from the user's @mh profile to generate headers for the unseen
+   @hid[Headers] buffer.  This value is a string.
+@enddefhvar
+
+@defhvar[var "Incorporate New Mail Hook", val {nil}]
+   This is a list of functions which are invoked immediately after new mail is
+   incorporated.  The functions should take no arguments.
+@enddefhvar
+
+@defhvar[var "Store Password", val {nil}]
+   When this is set, the user is only prompted once for his password, and the
+   password is stored for future use.
+@enddefhvar
+
+@defhvar[var "Authenticate Incorporation", val {t}]
+@defhvar1[var "Authentication User Name", val {nil}]
+When @hid[Authenticate Incorporation] is set, incorporating new mail prompts
+for a password to access a remote mail-drop.
+
+When incorporating new mail accesses a remote mail-drop, @hid[Authentication
+User Name] is the user name supplied for authentication on the remote machine.
+If this is @nil, @hemlock uses the local name.
+@enddefhvar
+
+
+@section[Reading Messages]
+@index[reading messages]
+@label[reading-messages]
+This section describes basic commands that show the current, next, and previous
+messages, as well as a couple advanced commands.  @hid[Show Message] (bound to
+@bf[SPACE] in @hid[Headers] mode) will display the message represented by the
+@f[scan] line the @hemlock cursor is on.  Deleted messages are considered
+special, and the more conveniently bound commands for viewing the next and
+previous messages (@hid[Next Undeleted Message] bound to @bf[n] and
+@hid[Previous Undeleted Message] bound to @bf[p], both in @hid[Headers] and
+@hid[Message] modes) will ignore them.  @hid[Next Message] and @hid[Previous
+Message] (bound to @bf[M-n] and @bf[M-p] in @hid[Headers] and @hid[Message]
+modes) may be invoked if reading a message is desired regardless of whether it
+has been deleted.
+
+
+@defcom[com "Show Message", stuff (bound to @bf[SPACE] and @bf[.] in @hid[Headers] mode) ]
+ This command, when invoked in a @hid[Headers] buffer, displays the current
+message (the message the cursor is on), by replacing any previous message that
+has not been preserved with @hid[Keep Message].  The current message is also
+removed from the unseen sequence.  The @hid[Message] buffer becomes the current
+buffer using the current window.  The buffer's point will be moved to the
+beginning of the buffer, and the buffer's name will be set to a string of the
+form @w<"@f[Message <folder> <msg-id>]">.
+
+The @hid[Message] buffer is read-only and may not be modified.  The command
+@hid[Goto Headers Buffer] issued in the @hid[Message] buffer makes the
+associated @hid[Headers] buffer current.
+
+When not in a @hid[Headers] buffer, this command prompts for a folder and
+message.  A unique @hid[Message] buffer is obtained, and its name is set to a
+string of the form @w<"@f[Message <folder> <msg-id>]">.  The buffer's point is
+moved to the beginning of the buffer, and the current window is used to display
+the message.
+
+Specifying multiple messages inserts all the messages into the same buffer.  If
+the user wishes to show more than one message, it is expected that he will
+generate a @hid[headers] buffer with the intended messages, and then use the
+message sequencing commands described below.
+@enddefcom
+
+@defcom[com "Next Message", stuff (bound to @bf[M-n] in @hid[Headers] and @hid[Message] modes) ]
+ This command is only meaningful in a @hid[Headers] buffer or a @hid[Message]
+buffer associated with a @hid[Headers] buffer.  In a @hid[Headers] buffer, the
+point is moved to the next message, and if there is one, it is shown as
+described in the @hid[Show Message] command.
+
+In a @hid[Message] buffer, the message after the currently visible message is
+displayed.  This clobbers the buffer's contents.  Note, if the @hid[Message]
+buffer is associated with a @hid[Draft] buffer, invoking this command breaks
+that association.  Using @hid[Keep Message] preserves the @hid[Message] buffer
+and any association with a @hid[Draft] buffer.
+
+The @hid[Message] buffer's name is set as described in the @hid[Show Message]
+command.
+@enddefcom
+
+@defcom[com "Previous Message", stuff (bound to @bf[M-p] in @hid[Headers] and @hid[Message] modes) ]
+ This command is only meaningful in a @hid[Headers] buffer or a @hid[Message]
+buffer associated with a @hid[Headers] buffer.  In a @hid[Headers] buffer, the
+point is moved to the previous message, and if there is one, it is shown as
+described in the @hid[Show Message] command.
+
+In a @hid[Message] buffer, the message before the currently visible message is
+displayed.  This clobbers the buffer's contents.  Note, if the @hid[Message]
+buffer is associated with a @hid[Draft] buffer, invoking this command breaks
+that association.  Using @hid[Keep Message] preserves the @hid[Message] buffer
+and any association with a @hid[Draft] buffer.
+
+The @hid[Message] buffer's name is set as described in the @hid[Show Message]
+command.
+@enddefcom
+
+@defcom[com "Next Undeleted Message", stuff (bound to @bf[n] in @hid[Headers] and @hid[Message] modes) ]
+ This command is only meaningful in a @hid[Headers] buffer or a @hid[Message]
+buffer associated with a @hid[Headers] buffer.  In a @hid[Headers] buffer, the
+point is moved to the next undeleted message, and if there is one, it is shown
+as described in the @hid[Show Message] command.
+
+In a @hid[Message] buffer, the first undeleted message after the currently
+visible message is displayed.  This clobbers the buffer's contents.  Note, if
+the @hid[Message] buffer is associated with a @hid[Draft] buffer, invoking this
+command breaks that association.  The @hid[Keep Message] command preserves the
+@hid[Message] buffer and any association with a @hid[Draft] buffer.
+
+The @hid[Message] buffer's name is set as described in the @hid[Show Message]
+command.
+@enddefcom
+
+@defcom[com "Previous Undeleted Message", stuff (bound to @bf[p] in @hid[Headers] and @hid[Message] modes) ]
+ This command is only meaningful in a @hid[Headers] buffer or a @hid[Message]
+buffer associated with a @hid[Headers] buffer.  In a @hid[Headers] buffer, the
+point is moved to the previous undeleted message, and if there is one, it is
+shown as described in the @hid[Show Message] command.
+
+In a @hid[Message] buffer, the first undeleted message before the currently
+visible message is displayed.  This clobbers the buffer's contents.  Note, if
+the @hid[Message] buffer is associated with a @hid[Draft] buffer, invoking this
+command breaks that association.  The @hid[Keep Message] command preserves the
+@hid[Message] buffer and any association with a @hid[Draft] buffer.
+
+The @hid[Message] buffer's name is set as described in the @hid[Show Message]
+command.
+@enddefcom
+
+@defcom[com "Scroll Message", stuff (bound to @bf[SPACE] and @bf[C-v] in @hid[Message] mode) ]
+@defhvar1[var "Scroll Message Showing Next", val {t}]
+ This command scrolls the current window down through the current message.  If
+the end of the message is visible and @hid[Scroll Message Showing Next] is not
+@nil, then show the next undeleted message.
+@enddefcom
+
+@defcom[com "Keep Message" ]
+This command can only be invoked in a @hid[Message] buffer.  It causes the
+@hid[Message] buffer to continue to exist when the user invokes commands to
+view other messages either within the kept @hid[Message] buffer or its
+associated @hid[Headers] buffer.  This is useful for getting two messages into
+different buffers.  It is also useful for retaining @hid[Message] buffers which
+would otherwise be deleted when an associated draft message is delivered.
+@enddefcom
+
+@defcom[com "Message Help", bind (Message: ?)]
+This command displays documentation on @hid[Message] mode.
+@enddefcom
+
+
+@section[Sending Messages]
+@index[sending messages]
+@label[sending-messages]
+The most useful commands for sending mail are @hid[Send Message] (bound to
+@bf[m] and @bf[s] in @hid[Headers] and @hid[Message] modes), @hid[Reply to
+Message] (bound to @bf[r] in @hid[Headers] mode), and @hid[Reply to Message in
+Other Window] (bound to @bf[r] in @hid[Message] mode).  These commands set up a
+@hid[Draft] buffer and associate a @hid[Message] buffer with the draft when
+possible.  To actually deliver the message to its recipient(s), use
+@hid[Deliver Message] (bound to @bf[H-s] in @hid[Draft] mode).  To abort
+sending mail, use @hid[Delete Draft and Buffer] (bound to @bf[H-q] in
+@hid[Draft] mode).  If one wants to temporarily stop composing a draft with the
+intention of finishing it later, then the @hid[Save File] command (bound to
+@bf[C-x C-s]) will save the draft to the user's draft folder.
+
+@hid[Draft] buffers have a special @hemlock minor mode called @hid[Draft] mode.
+The major mode of a @hid[Draft] buffer is taken from the @hid[Default Modes]
+variable.  The user may wish to arrange that @hid[Text] mode (and possibly
+@hid[Fill] mode or @hid[Save] mode) be turned on whenever @hid[Draft] mode is
+set.  For a further description of how to manipulate modes in @hemlock see the
+@i[Hemlock Command Implementor's Manual].
+
+
+@defcom[com "Send Message", stuff (bound to @bf[s] and @bf[m] in @hid[Headers] and @hid[Message] modes and @bf[C-x m] globally) ]
+ This command, when invoked in a @hid[Headers] buffer, creates a unique
+@hid[Draft] buffer and a unique @hid[Message] buffer.  The current message is
+inserted in the @hid[Message] buffer, and the @hid[Draft] buffer is displayed
+in the current window.  The @hid[Draft] buffer's point is moved to the end of
+the line containing @f[To:] if it exists.  The name of the draft message file
+is used to produce the buffer's name.  A pathname is associated with the
+@hid[Draft] buffer so that @hid[Save File] can be used to incrementally save a
+composition before delivering it.  The @f[comp] utility will be used to
+allocate a draft message in the user's @mh draft folder and to insert the
+proper header components into the draft message.  Both the @hid[Draft] and
+@hid[Message] buffers are associated with the @hid[Headers] buffer, and the
+@hid[Draft] buffer is associated with the @hid[Message] buffer.
+
+When invoked in a @hid[Message] buffer, a unique @hid[Draft] buffer is created,
+and these two buffers are associated.  If the @hid[Message] buffer is
+associated with a @hid[Headers] buffer, this association is propagated to the
+@hid[Draft] buffer.  Showing other messages while in this @hid[Headers] buffer
+will not affect this @hid[Message] buffer.
+
+When not in a @hid[Headers] or @hid[Message] buffer, this command does the same
+thing as described in the previous two cases, but there are no @hid[Message] or
+@hid[Headers] buffer manipulations.
+
+@hid[Deliver Message] will deliver the draft to its intended recipient(s).
+
+The @hid[Goto Headers Buffer] command, when invoked in a @hid[Draft] or
+@hid[Message] buffer, makes the associated @hid[Headers] buffer current.  The
+@hid[Goto Message Buffer] command, when invoked in a @hid[Draft] buffer, makes
+the associated @hid[Message] buffer current.
+@enddefcom
+
+@defcom[com "Reply to Message", stuff (bound to @bf[r] in @hid[Headers] mode) ]
+@defcom1[com "Reply to Message in Other Window", stuff (bound to @bf[r] in @hid[Message] mode) ]
+@defhvar1[var "Reply to Message Prefix Action"]
+ @hid[Reply to Message], when invoked in a @hid[Headers] buffer, creates a
+unique @hid[Draft] buffer and a unique @hid[Message] buffer.  The current
+message is inserted in the @hid[Message] buffer, and the @hid[Draft] buffer is
+displayed in the current window.  The draft components are set up in reply to
+the message, and the @hid[Draft] buffer's point is moved to the end of the
+buffer.  The name of the draft message file is used to produce the buffer's
+name.  A pathname is associated with the @hid[Draft] buffer so that @hid[Save
+File] can be used to incrementally save a composition before delivering it.
+The @f[repl] utility will be used to allocate a draft message file in the
+user's @mh draft folder and to insert the proper header components into the
+draft message.  Both the @hid[Draft] and @hid[Message] buffers are associated
+with the @hid[Headers] buffer, and the @hid[Draft] buffer is associated with
+the @hid[Message] buffer.
+
+When invoked in a @hid[Message] buffer, a unique @hid[Draft] buffer is set up
+using the message in the buffer as the associated message.  Any previous
+association between the @hid[Message] buffer and a @hid[Draft] buffer is
+removed.  Any association of the @hid[Message] buffer with a @hid[Headers]
+buffer is propagated to the @hid[Draft] buffer.
+
+When not in a @hid[Headers] buffer or @hid[Message] buffer, this command
+prompts for a folder and message to reply to.  This message is inserted into a
+unique @hid[Message] buffer, and a unique @hid[Draft] buffer is created as in
+the previous two cases.  There is no association of either the @hid[Message]
+buffer or the @hid[Draft] buffer with a @hid[Headers] buffer.
+
+When a prefix argument is supplied, @hid[Reply to Message Prefix Action] is
+considered with respect to supplying carbon copy switches to @f[repl].  This
+variable's value is one of @b[:cc-all], :@b[no-cc-all], or @nil.  See section
+@ref[Styles] for examples of how to use this.
+
+@hid[Reply to Message in Other Window] is identical to @hid[Reply to Message],
+but the current window is split showing the @hid[Draft] buffer in the new
+window.  The split window displays the @hid[Message] buffer.
+
+@hid[Deliver Message] will deliver the draft to its intended recipient(s).
+
+The @hid[Goto Headers Buffer] commmand, when invoked in a @hid[Draft] or
+@hid[Message] buffer, makes the associated @hid[Headers] buffer current.  The
+@hid[Goto Message Buffer] command, when invoked in a @hid[Draft] buffer, makes
+the associated @hid[Message] buffer current.
+@enddefcom
+
+@defcom[com "Forward Message", stuff (bound to @bf[f] in @hid[Headers] and @hid[Message] modes) ]
+ This command, when invoked in a @hid[Headers] buffer, creates a unique
+@hid[Draft] buffer.  The current message is inserted in the draft by using the
+@f[forw] utility, and the @hid[Draft] buffer is shown in the current window.
+The name of the draft message file is used to produce the buffer's name.  A
+pathname is associated with the @hid[Draft] buffer so that @hid[Save File] can
+be used to incrementally save a composition before delivering it.  The
+@hid[Draft] buffer is associated with the @hid[Headers] buffer, but no
+@hid[Message] buffer is created since the message is already a part of the
+draft.
+
+When invoked in a @hid[Message] buffer, a unique @hid[Draft] buffer is set up
+inserting the message into the @hid[Draft] buffer.  The @hid[Message] buffer is
+not associated with the @hid[Draft] buffer because the message is already a
+part of the draft.  However, any association of the @hid[Message] buffer with a
+@hid[Headers] buffer is propagated to the @hid[Draft] buffer.
+
+When not in a @hid[Headers] buffer or @hid[Message] buffer, this command
+prompts for a folder and message to forward.  A @hid[Draft] buffer is created
+as described in the previous two cases.
+
+@hid[Deliver Message] will deliver the draft to its intended recipient(s).
+@enddefcom
+
+@defcom[com "Deliver Message", stuff (bound to @bf[H-s] and @bf[H-c] in @hid[Draft] mode) ]
+@defhvar1[var "Deliver Message Confirm", val {nil}]
+ This command, when invoked in a @hid[Draft] buffer, saves the file and uses
+the @mh @f[send] utility to deliver the draft.  If the draft is a reply to some
+message, then @f[anno] is used to annotate that message with a "@f[replied]"
+component.  Any @hid[Headers] buffers containing the replied-to message are
+updated with an "@b[A]" placed in the appropriate headers line two characters
+after the message ID.  Before doing any of this, confirmation is asked for
+based on @hid[Deliver Message Confirm].
+
+When not in a @hid[Draft] buffer, this prompts for a draft message ID and
+invokes @f[send] on that draft message to deliver it.  Sending a draft in this
+way severs any association that draft may have had with a message being replied
+to, so no annotation will occur.
+@enddefcom
+
+@defcom[com "Delete Draft and Buffer", stuff (bound to @bf[H-q] in @hid[Draft] mode) ]
+This command, when invoked in a @hid[Draft] buffer, deletes the draft message
+file and the buffer.  This also deletes any associated message buffer unless
+the user preserved it with @hid[Keep Message].
+@enddefcom
+
+@defcom[com "Remail Message", stuff (bound to @bf[H-r] in @hid[Headers] and @hid[Message] modes) ]
+ This command, when invoked in a @hid[Headers] or @hid[Message] buffer, prompts
+for resend @f[To:] and resend @f[Cc:] addresses, remailing the current message.
+When invoked in any other kind of buffer, this command prompts for a folder and
+message as well.  @mh's @f[dist] sets up a draft folder message which is then
+modified.  The above mentioned addresses are inserted on the @f[Resent-To:] and
+@f[Resent-Cc:] lines.  Then the message is delivered.
+
+There is no mechanism for annotating messages as having been remailed.
+@enddefcom
+
+@defcom[com "Draft Help", bind (Draft: H-?)]
+This command displays documentation on @hid[Draft] mode.
+@enddefcom
+
+
+@section[Convenience Commands for Message and Draft Buffers]
+@index[message buffer commands]
+@index[draft buffer commands]
+@index[convenience commands for mail interface]
+@label[convenience-coms] 
+This section describes how to switch from a @hid[Message] or @hid[Draft] buffer
+to its associated @hid[Headers] buffer, or from a @hid[Draft] buffer to its
+associated @hid[Message] buffer.  There are also commands for various styles of
+inserting text from a @hid[Message] buffer into a @hid[Draft] buffer.
+
+@defcom[com "Goto Headers Buffer", stuff (bound to @bf[^] in @hid[Message] mode and @bf[H-^] in @hid[Draft] mode) ] 
+   This command, when invoked in a @hid[Message] or @hid[Draft] buffer with an
+   associated @hid[Headers] buffer, places the associated @hid[Headers] buffer
+   in the current window.
+
+   The cursor is moved to the headers line of the associated message.
+@enddefcom
+
+@defcom[com "Goto Message Buffer", stuff (bound to @bf[H-m] in @hid[Draft] mode) ]
+   This command, when invoked in a @hid[Draft] buffer with an associated
+   @hid[Message] buffer, places the associated @hid[Message] buffer in the
+   current window.
+@enddefcom
+
+@defcom[com "Insert Message Region", stuff (bound to @bf[H-y] in @hid[Message] mode) ]
+@defhvar1[var "Message Insertion Prefix", val {"   "}]
+@defhvar1[var "Message Insertion Column", val {75}]
+   This command, when invoked in a @hid[Message] buffer that has an associated
+   @hid[Draft] buffer, copies the current active region into the @hid[Draft]
+   buffer.  It is filled using @hid[Message Insertion Prefix] (which defaults
+   to three spaces) and @hid[Message Insertion Column].  If an argument is
+   supplied, the filling is inhibited.
+@enddefcom
+
+@defcom[com "Insert Message Buffer", stuff (bound to @bf[H-y] in @hid[Draft] mode) ]
+@defhvar1[var "Message Buffer Insertion Prefix", val {"    "}]
+   This command, when invoked in a @hid[Draft] buffer with an associated
+   @hid[Message] buffer, or when in a @hid[Message] buffer that has an
+   associated @hid[Draft] buffer, inserts the @hid[Message] buffer into the
+   @hid[Draft] buffer.  Each inserted line is modified by prefixing it with
+   @hid[Message Buffer Insertion Prefix] (which defaults to four spaces) .  If
+   an argument is supplied, the prefixing is inhibited.
+@enddefcom
+
+@defcom[com "Edit Message Buffer", stuff (bound to @bf[e] in @hid[Message] mode) ]
+   This command puts the current @hid[Message] buffer in @hid[Text] mode and
+   makes it writable (@hid[Message] buffers are normally read-only).  The
+   pathname of the file which the message is in is associated with the buffer
+   making saving possible.  A recursive edit is entered, and the user is
+   allowed to make changes to the message.  When the recursive edit is exited,
+   if the buffer is modified, the user is asked if the changes should be saved.
+   The buffer is marked unmodified, and the pathname is disassociated from the
+   buffer.  The buffer otherwise returns to its previous state as a
+   @hid[Message] buffer.  If the recursive edit is aborted, the user is not
+   asked to save the file, and the buffer remains changed though it is marked
+   unmodified.
+@enddefcom
+
+
+@section[Deleting Messages]
+@index[deleting messages]
+@label[deleting]
+The main command described in this section is @hid[Headers Delete Message]
+(bound to @bf[k] in @hid[Headers] and @hid[Message] modes).  A useful command
+for reading new mail is @hid[Delete Message and Show Next] (bound to @bf[d] in
+@hid[Message] mode) which deletes the current message and shows the next
+undeleted message.
+
+Since messages are by default deleted using a virtual message deletion
+mechanism, @hid[Expunge Messages] (bound to @bf[!] in @hid[Headers] mode)
+should be mentioned here.  This is described in section @ref[terminating].
+
+
+@defhvar[var "Virtual Message Deletion", val {t}]
+When set, @hid[Delete Message] adds a message to the "@f[hemlockdeleted]"
+sequence; otherwise, @f[rmm] is invoked on the message immediately.
+@enddefhvar
+
+@defcom[com "Delete Message" ]
+This command prompts for a folder, messages, and an optional @f[pick]
+expression.  When invoked in a @hid[Headers] buffer of the specified folder,
+the prompt for a message specification will default to the those messages in
+that @hid[Headers] buffer.
+
+When the variable @hid[Virtual Message Deletion] is set, this command merely
+flags the messages for deletion by adding them to the "@f[hemlockdeleted]"
+sequence.  Then this updates any @hid[Headers] buffers representing the folder.
+It notates each headers line referring to a deleted message with a "@b[D]" in
+the third character position after the message ID.
+
+When @hid[Virtual Message Deletion] is not set, @f[rmm] is invoked on the
+message, and each headers line referring to the deleted message is deleted from
+its buffer
+@enddefcom
+
+@defcom[com "Headers Delete Message", stuff (bound to @bf[k] in @hid[Headers] and @hid[Message] modes) ]
+   This command, when invoked in a @hid[Headers] buffer, deletes the message on
+   the current line as described in @hid[Delete Message].
+
+   When invoked in a @hid[Message] buffer, the message displayed in it is
+   deleted as described in @hid[Delete Message].
+@enddefcom
+
+@defcom[com "Delete Message and Show Next", stuff (bound to @bf[k] in @hid[Headers] and @hid[Message] modes) ]
+   This command is only valid in a @hid[Headers] buffer or a @hid[Message]
+   buffer associated with some @hid[Headers] buffer.  The current message is
+   deleted as with the @hid[Delete Message] command.  Then the next message is
+   shown as with @hid[Next Undeleted Message].
+@enddefcom
+
+@defcom[com "Delete Message and Down Line", stuff (bound to @bf[d] in @hid[Headers mode])]
+   This command, when invoked in a @hid[Headers] buffer, deletes the message on
+   the current line.  Then the point is moved to the next non-blank line.
+@enddefcom
+
+@defcom[com "Undelete Message" ]
+   This command is only meaningful when @hid[Virtual Message Deletion] is set.
+   This prompts for a folder, messages, and an optional @f[pick] expression.  When
+   in a @hid[Headers] buffer of the specified folder, the messages prompt
+   defaults to those messages in the buffer.  All @hid[Headers] buffers
+   representing the folder are updated.  Each headers line referring to an
+   undeleted message is notated by replacing the "@b[D]" in the third character
+   position after the message ID with a space.
+@enddefcom
+
+@defcom[com "Headers Undelete Message", stuff (bound to @bf[u] in @hid[Headers] and @hid[Message] modes) ]
+   This command is only meaningful when @hid[Virtual Message Deletion] is set.
+   When invoked in a @hid[Headers] buffer, the message on the current line is
+   undeleted as described in @hid[Undelete Message].
+
+   When invoked in a @hid[Message] buffer, the message displayed in it is
+   undeleted as described in @hid[Undelete Message].
+@enddefcom
+
+
+@section[Folder Operations]
+
+@index[folder operations]@label[folder]
+@defcom[com "List Folders" ]
+   This command displays a list of all current mail folders in the user's
+   top-level mail directory in a @hemlock pop-up window.
+@enddefcom
+
+@defcom[com "Create Folder"]
+   This command prompts for and creates a folder.  If the folder already
+   exists, an error is signaled.
+@enddefcom
+
+@defcom[com "Delete Folder" ]
+   This command prompts for a folder and uses @f[rmf] to delete it.  Note that
+   no confirmation is asked for.
+@enddefcom
+
+
+@section[Refiling Messages]
+
+@index[refiling messages]@label[refiling]
+@defcom[com "Refile Message" ]
+   This command prompts for a folder, messages, an optional @f[pick]
+   expression, and a destination folder.  When invoked in a @hid[Headers]
+   buffer of the specified folder, the message prompt offers a default of those
+   messages in the buffer.  If the destination folder does not exist, the user
+   is asked to create it.  The resulting messages are refiled with the
+   @f[refile] utility.  All @hid[Headers] buffers for the folder are updated.
+   Each line referring to a refiled message is deleted from its buffer.
+@enddefcom
+
+@defcom[com "Headers Refile Message", stuff (bound to @bf[o] in @hid[Headers] and @hid[Message] modes) ]
+   This command, when invoked in a @hid[Headers] buffer, prompts for a
+   destination folder, refiling the message on the current line with
+   @f[refile].  If the destination folder does not exist, the user is asked to
+   create it.  Any @hid[Headers] buffers containing messages for that folder
+   are updated.  Each headers line referring to the refiled message is deleted
+   from its buffer.
+
+   When invoked in a @hid[Message] buffer, that message is refiled as described
+   above.
+@enddefcom
+
+
+@section[Marking Messages]
+@index[marking messages]
+@label[marking]
+@defcom[com "Mark Message" ]
+This command prompts for a folder, message, and sequence and adds (deletes) the
+message specification to (from) the sequence.  By default this adds the
+message, but if an argument is supplied, this deletes the message.  When
+invoked in a @hid[Headers] buffer or @hid[Message] buffer, this only prompts
+for a sequence and uses the current message.
+@enddefcom
+
+
+@section[Terminating Headers Buffers]
+@label[terminating]
+The user never actually @i[exits] the mailer.  He can leave mail buffers lying
+around while conducting other editing tasks, selecting them and continuing his
+mail handling whenever.  There still is a need for various methods of
+terminating or cleaning up @hid[Headers] buffers.  The two most useful commands
+in this section are @hid[Expunge Messages] and @hid[Quit Headers].
+
+
+@defhvar[var "Expunge Messages Confirm", val {t}]
+   When this is set, @hid[Quit Headers] and @hid[Expunge Messages] will ask for
+   confirmation before expunging messages and packing the folder's message ID's.
+@enddefhvar
+
+@defhvar[var "Temporary Draft Folder", val {nil}]
+   This is a folder name where @mh @f[fcc:] messages are kept with the
+   intention that this folder's messages will be deleted and expunged whenever
+   messages from any folder are expunged (for example, when @hid[Expunge
+   Messages] or @hid[Quit Headers] is invoked.
+@enddefhvar
+
+@defcom[com "Expunge Messages", stuff (bound to @bf[!] in @hid[Headers] mode) ]
+This command deletes messages @f[mark]'ed for deletion, and compacts the
+folder's message ID's.  If there are messages to expunge, ask the user for
+confirmation, displaying the folder name.  This can be inhibited by setting
+@hid[Expunge Messages Confirm] to @nil.  When @hid[Temporary Draft Folder] is
+not @nil, this command deletes and expunges that folder's messages regardless
+of the folder in which the user invokes it, and a negative response to the
+request for confirmation inhibits this.
+
+When invoked in a @hid[Headers] buffer, the messages in that folder's
+"@f[hemlockdeleted]" sequence are deleted by invoking @f[rmm].  Then the ID's
+of the folder's remaining messages are compacted using the @f[folder] utility.
+Since headers must be regenerated due to renumbering or reassigning message
+ID's, and because @hid[Headers] buffers become inconsistent after messages are
+deleted, @hemlock must regenerate all the headers for the folder.  Multiple
+@hid[Headers] buffers for the same folder are then collapsed into one buffer,
+deleting unnecessary duplicates.  Any @hid[Message] buffers associated with
+these @hid[Headers] buffers are deleted.
+
+If there is an unseen @hid[Headers] buffer for the folder, it is handled
+separately from the @hid[Headers] buffers described above.  @hemlock tries to
+update it by filling it only with remaining unseen message headers.
+Additionally, any headers generated due to @hid[Unseen Headers Message Spec]
+are inserted.  If there are no headers, unseen or otherwise, the buffer is left
+blank.
+
+Any @hid[Draft] buffer set up as a reply to a message in the folder is affected
+as well since the associated message has possibly been deleted.  When a draft
+of this type is delivered, no message will be annotated as having been replied
+to.
+
+When invoked in a @hid[Message] buffer, this uses its corresponding folder as
+the folder argument.  The same updating as described above occurs.
+
+In any other type of buffer, a folder is prompted for.
+@enddefcom
+
+@defcom[com "Quit Headers", stuff (bound to @bf[q] in @hid[Headers] and @hid[Message] modes) ]
+This command affects the current @hid[Headers] buffer.  When there are deleted
+messages, ask the user for confirmation on expunging the messages and packing
+the folder's message ID's.  This prompting can be inhibited by setting
+@hid[Expunge Messages Confirm] to @nil.  After deleting and packing, this
+deletes the buffer and all its associated @hid[Message] buffers.
+
+Other @hid[Headers] buffers regarding the same folder are handled as described
+in @hid[Expunge Messages], but the buffer this command is invoked in is always
+deleted.
+
+When @hid[Temporary Draft Folder] is not @nil, this folder's messages are
+deleted and expunged regardless of the folder in which the user invokes this
+command.  A negative response to the above mentioned request for confirmation
+inhibits this.
+@enddefcom
+
+@defcom[com "Delete Headers Buffer and Message Buffers" ]
+   This command prompts for a @hid[Headers] buffer to delete along with its
+   associated @hid[Message] buffers.  Any associated @hid[Draft] buffers are
+   left intact, but their corresponding @hid[Message] buffers will be deleted.
+   When invoked in a @hid[Headers] buffer or a @hid[Message] buffer associated
+   with a @hid[Headers] buffer, that @hid[Headers] buffer is offered as a
+   default.
+@enddefcom
+
+
+@section[Miscellaneous Commands]
+@label[miscellaneous mail commands]
+@label[miscellaneous]
+
+@defcom[com "List Mail Buffers", stuff (bound to @bf[l] in @hid[Headers] and @hid[Message] modes @bf[H-l] in @hid[Draft] mode) ]
+This command shows a list of all mail @hid[Message], @hid[Headers], and
+@hid[Draft] buffers.
+
+If a @hid[Message] buffer has an associated @hid[Headers] buffer, it is
+displayed to the right of the @hid[Message] buffer's name.
+
+If a @hid[Draft] buffer has an associated @hid[Message] buffer, it is displayed
+to the right of the @hid[Draft] buffer's name.  If a @hid[Draft] buffer has no
+associated @hid[Message] buffer, but it is associated with a @hid[Headers]
+buffer, then the name of the @hid[Headers] buffer is displayed to the right of
+the @hid[Draft] buffer.
+
+For each buffer listed, if it is modified, then an asterisk is displayed before
+the name of the buffer.
+@enddefcom
+
+
+@section[Styles of Usage]
+@index[styles of mail interface usage]
+@label[Styles]
+This section discusses some styles of usage or ways to make use of some of the
+features of @hemlock's interface to @mh that might not be obvious.  In each
+case, setting some variables and/or remembering an extra side effect of a
+command will lend greater flexibility and functionality to the user.
+
+@subsection[Unseen Headers Message Spec]
+The unseen @hid[Headers] buffer by default only shows unseen headers which is
+adequate for one folder, simple mail handling.  Some people use their @hid[New
+Mail Folder] only for incoming mail, refiling or otherwise dispatching a
+message immediately.  Under this mode it is easy to conceive of the user not
+having time to respond to a message, but he would like to leave it in this
+folder to remind him to take care of it.  Using the @hid[Unseen Headers Message
+Spec] variable, the user can cause all the messages the @hid[New Mail Folder] to
+be inserted into the unseen @hid[Headers] buffer whenever just unseen headers
+would be.  This way he sees all the messages that require immediate attention.
+
+To achieve the above effect, @hid[Unseen Headers Message Spec] should be set to
+the string @f["all"].  This variable can be set to any general @mh message
+specification (see section @ref[mhcommands] of this chapter), so the user can
+include headers of messages other than those that have not been seen without
+having to insert all of them.  For example, the user could set the variable to
+@f["flagged"] and use the @hid[Mark Message] command to add messages he's
+concerned about to the @f["flagged"] sequence.  Then the user would see new
+mail and interesting mail in his unseen @hid[Headers] buffer, but he doesn't
+have to see everything in his @hid[New Mail Folder].
+
+
+@subsection[Temporary Draft Folder]
+Section @ref[components-files] of this chapter discusses how to make @mh keep
+personal copies of outgoing mail.  The method described will cause a copy of
+every outgoing message to be saved forever and requires the user to go through
+his @f[Fcc:] folder, weeding out those he does not need.  The @hid[Temporary
+Draft Folder] variable can name a folder whose messages will be deleted and
+expunged whenever any folder's messages are expunged.  By naming this folder in
+the @mh profile and components files, copies of outgoing messages can be saved
+temporarily.  They will be cleaned up automatically, but the user still has a
+time frame in which he can permanently save a copy of an outgoing message.
+This folder can be visited with @hid[Message Headers], and messages can be
+refiled just like any other folder.
+
+
+@subsection[Reply to Message Prefix Action]
+Depending on the kinds of messages one tends to handle, the user may find
+himself usually replying to everyone who receives a certain message, or he may
+find that this is only desired occasionally.  In either case, the user
+can set up his @mh profile to do one thing by default, using the @hid[Reply
+to Message Prefix Action] variable in combination with a prefix argument to the
+@hid[Reply to Message] command to get the other effect.
+
+For example, the following line in one's @mh profile will cause @mh to reply to
+everyone receiving a certain message (except for the user himself since he
+saves personal copies with the @f[-fcc] switch):
+@begin[programexample]
+repl: -cc all -nocc me -fcc out-copy
+@end[programexample]
+This user can set @hid[Reply to Message Prefix Action] to be @f[:no-cc-all].
+Then whenever he invokes @hid[Reply to Message] with a prefix argument, instead
+of replying to everyone, the draft will be set up in reply only to the person
+who sent the mail.
+
+As an alternative example, not specifying anything in one's @mh profile and
+setting this variable to @f[:cc-all] will have a default effect of replying
+only to the sender of a piece of mail.  Then invoking @hid[Reply to Message]
+with a prefix argument will cause everyone who received the mail to get a copy
+of the reply.  If the user does not want a @f[cc:] copy, then he can add
+@f[-nocc me] as a default switch and value in his @mh profile.
+
+
+@newpage
+@section[Wallchart]
+
+@tabclear
+@tabdivide(3)
+
+@begin[format, spacing 1.5]
+
+@Begin[Center] @b[Global bindings:] @End[Center]
+
+@hid[Incorporate and Read New Mail]@\@\@bf[C-x i]
+@hid[Send Message]@\@\@bf[C-x m]
+@hid[Message Headers]@\@\@bf[C-x r]
+
+
+@Begin[Center] @b[Headers and Message modes bindings:] @End[Center]
+
+@hid[Next Undeleted Message]@\@\@bf[n]
+@hid[Previous Undeleted Message]@\@\@bf[p]
+@hid[Send Message]@\@\@bf[s], @bf[m]
+@hid[Forward Message]@\@\@bf[f]
+@hid[Headers Delete Message]@\@\@bf[k]
+@hid[Headers Undelete Message]@\@\@bf[u]
+@hid[Headers Refile Message]@\@\@bf[o]
+@hid[List Mail Buffers]@\@\@bf[l]
+@hid[Quit Headers]@\@\@bf[q]
+@hid[Incorporate and Read New Mail]@\@\@bf[i]
+@hid[Next Message]@\@\@bf[M-n]
+@hid[Previous Message]@\@\@bf[M-p]
+@hid[Beginning of Buffer]@\@\@bf[<]
+@hid[End of Buffer]@\@\@bf[>]
+
+
+@Begin[Center] @b[Headers mode bindings:] @End[Center]
+
+@hid[Delete Message and Down Line]@\@\@bf[d]
+@hid[Pick Headers]@\@\@bf[h]
+@hid[Show Message]@\@\@bf[space], @bf[.]
+@hid[Reply to Message]@\@\@bf[r]
+@hid[Expunge Messages]@\@\@bf[!]
+
+
+@Begin[Center] @b[Message mode bindings:] @End[Center]
+
+@hid[Delete Message and Show Next]@\@\@bf[d]
+@hid[Goto Headers Buffer]@\@\@bf[^]
+@hid[Scroll Message]@\@\@bf[space]
+@hid[Scroll Message]@\@\@bf[C-v]
+@hid[Scroll Window Up]@\@\@bf[backspace], @bf[delete]
+@hid[Reply to Message in Other Window]@\@bf[r]
+@hid[Edit Message Buffer]@\@\@bf[e]
+@hid[Insert Message Region]@\@\@bf[H-y]
+
+
+@Begin[Center] @b[Draft mode bindings:] @End[Center]
+
+@hid[Goto Headers Buffer]@\@\@bf[H-^]
+@hid[Goto Message Buffer]@\@\@bf[H-m]
+@hid[Deliver Message]@\@\@bf[H-s], @bf[H-c]
+@hid[Insert Message Buffer]@\@\@bf[H-y]
+@hid[Delete Draft and Buffer]@\@\@bf[H-q]
+@hid[List Mail Buffers]@\@\@bf[H-l]
+
+@end[format]
+@tabclear
diff --git a/docs/hem/user/special-modes.mss b/docs/hem/user/special-modes.mss
new file mode 100644
index 000000000..bbb30ed69
--- /dev/null
+++ b/docs/hem/user/special-modes.mss
@@ -0,0 +1,725 @@
+@comment{-*- Dictionary: bld:scribe/hem/hem; Mode: spell; Package: Hemlock -*-}
+@chap[Special Modes]
+
+@section[Dired Mode]
+@label[dired]
+@index[directory editing]
+
+@hemlock provides a directory editing mechanism.  The user can flag files and
+directories for deletion, undelete flagged files, and with a keystroke read in
+files and descend into directories.  In some implementations, it also supports
+copying, renaming, and a simple wildcard feature.
+
+
+@subsection[Inspecting Directories]
+@defcom[com "Dired", bind (C-x C-M-d)]
+This command prompts for a directory and fills a buffer with a verbose listing
+of that directory.  When the prefix argument is supplied, this includes Unix
+dot files.  If a dired buffer already exists for the directory, this switches
+to the buffer and makes sure it displays dot files if appropriate.
+@enddefcom
+
+@defcom[com "Dired with Pattern", bind (C-x C-M-d)]
+This command prompts for a directory and a pattern that may contain at most one
+wildcard, an asterisk, and it fills a buffer with a verbose listing of the
+files in the directory matching the pattern.  When the prefix argument is
+supplied, this includes Unix dot files.  If a dired buffer already exists for
+this directory, this switches to the buffer and makes sure it displays dot
+files if appropriate.
+@enddefcom
+
+@defcom[com "Dired from Buffer Pathname"]
+This command invokes @hid[Dired] on the directory name of the current buffer's
+pathname.
+@enddefcom
+
+@defcom[com "Dired Help", bind (Dired: ?)]
+This command pops up a help window listing the various @hid[Dired] commands.
+@enddefcom
+
+@defcom[com "Dired View File", bind (Dired: Space)]
+@defcom1[com "Dired Edit File", bind (Dired: e)]
+These command read in the file on the current line with the point.  If the line
+describes a directory instead of a file, then this command effectively invokes
+@hid[Dired] on the specification.  This associates the file's buffer with the
+@hid[Dired] buffer.
+
+@hid[Dired View File] reads in the file as if by @hid[View File], and
+@hid[Dired Edit File] as if by @hid[Find File].
+
+@hid[Dired View File] always reads into a newly created buffer, warning if the
+file already exists in some buffer.
+@enddefcom
+
+@defcom[com "Dired Up Directory", bind (Dired: ^)]
+This command invokes @hid[Dired] on the directory up one level from the current
+@hid[Dired] buffer.  This is useful for going backwards after repeatedly
+invoking @hid[Dired View File] and descending into a series of subdirectories.
+Remember, @hid[Dired] only generates directory listings when no buffer contains
+a dired for the specified directory.
+@enddefcom
+
+@defcom[com "Dired Update Buffer", bind (Dired: H-u)]
+This command is useful when the user knows the directory in the current
+@hid[Dired] buffer has changed.  @hemlock cannot know the directory structure
+has changed, but the user can explicitly update the buffer with this command
+instead of having to delete it and invoke @hid[Dired] again.
+@enddefcom
+
+@defcom[com "Dired Next File"]
+@defcom1[com "Dired Previous File"]
+These commands move to next or previous undeleted file.
+@enddefcom
+
+
+@subsection[Deleting Files]
+@defcom[com "Dired Delete File and Down Line", bind (Dired: d)]
+This command marks for deletion the file on the current line with the point and
+moves point down a line.
+@enddefcom
+
+@defcom[com "Dired Delete File with Pattern", bind (Dired: D)]
+This command prompts for a name pattern that may contain at most one wildcard,
+an asterisk, and marks for deletion all the names matching the pattern.
+@enddefcom
+
+@defcom[com "Dired Delete File", bind (Dired: C-d)]
+This command marks for deletion the file on the current line with the point
+without moving the point.
+@enddefcom
+
+
+@subsection[Undeleting Files]
+@defcom[com "Dired Undelete File and Down Line", bind (Dired: u)]
+This command unmarks for deletion the file on the current line with the point
+and moves point down a line.
+@enddefcom
+
+@defcom[com "Dired Undelete File with Pattern", bind (Dired: U)]
+This command prompts for a name pattern that may contain at most one wildcard,
+an asterisk, and unmarks for deletion all the names matching the pattern.
+@enddefcom
+
+@defcom[com "Dired Undelete File", bind (Dired: C-u)]
+This command unmarks for deletion the file on the current line with the point
+without moving the point.
+@enddefcom
+
+
+@subsection[Expunging and Quitting]
+@defcom[com "Dired Expunge Files", bind (Dired: !)]
+@defhvar1[var "Dired File Expunge Confirm", val {t}]
+@defhvar1[var "Dired Directory Expunge Confirm", val {t}]
+This command deletes files marked for deletion, asking the user for
+confirmation once for all the files flagged.  It recursively deletes any marked
+directories, asking the user for confirmation once for all those marked.
+@hid[Dired File Expunge Confirm] and @hid[Dired Directory Expunge Confirm] when
+set to @nil individually inhibit the confirmation prompting for the appropriate
+deleting.
+@enddefcom
+
+@defcom[com "Dired Quit", bind (Dired: q)]
+This command expunges any marked files or directories as if by @hid[Expunge
+Dired Files] before deleting the @hid[Dired] buffer.
+@enddefcom
+
+
+@subsection[Copying Files]
+@defcom[com "Dired Copy File", bind (Dired: c)]
+This command prompts for a destination specification and copies the file on the
+line with the point.  When prompting, the current line's specification is the
+default, which provides some convenience in supplying the destination.  The
+destination is either a directory specification or a file name, and when it is
+the former, the source is copied into the directory under its current file name
+and extension.
+@enddefcom
+
+@defcom[com "Dired Copy with Wildcard", bind (Dired: C)]
+This command prompts for a name pattern that may contain at most one wildcard,
+an asterisk, and copies all the names matching the pattern.  When prompting for
+a destination, this provides the @hid[Dired] buffer's directory as a default.
+The destination is either a directory specification or a file name with a
+wildcard.  When it is the former, all the source files are copied into the
+directory under their current file names and extensions.  When it is the later,
+each sources file's substitution for the wildcard causing it to match the first
+pattern replaces the wildcard in the destination pattern; for example, you
+might want to copy @f["*.txt"] to @f["*.text"].
+@enddefcom
+
+@defhvar[var "Dired Copy File Confirm", val {t}]
+@label[copy-confirm]
+This variable controls interaction with the user when it is not obvious what
+the copying process should do.  This takes one of the following values:
+@Begin[Description]
+@true@\
+When the destination specification exists, the copying process stops and asks
+the user if it should overwrite the destination.
+
+@nil@\
+The copying process always copies the source file to the destination
+specification without interacting with the user.
+
+@kwd[update]@\
+When the destination specification exists, and its write date is newer than
+the source's write date, then the copying process stops and asks the user if it
+should overwrite the destination.
+@End[Description]
+@enddefhvar
+
+
+@subsection[Renaming Files]
+@defcom[com "Dired Rename File", bind (Dired: r)]
+Rename the file or directory under the point
+@enddefcom
+
+@defcom[com "Dired Rename with Wildcard", bind (Dired: R)]
+Rename files that match a pattern containing ONE wildcard.
+@enddefcom
+
+@defhvar[var "Dired Rename File Confirm", val {t}]
+When non-nil, @hid[Dired] will query before clobbering an existing file.
+@enddefhvar
+
+
+@section[View Mode]
+@hid[View] mode provides for scrolling through a file read-only, terminating
+the buffer upon reaching the end.
+
+@defcom[com "View File"]
+This command reads a file into a new buffer as if by "Visit File", but
+read-only.  Bindings exist for scrolling and backing up in a single key stroke.
+@enddefcom
+
+@defcom[com "View Help", bind (View: ?)]
+This command shows a help message for @hid[View] mode.
+@enddefcom
+
+@defcom[com "View Edit File", bind (View: e)]
+This commands makes a buffer in @hid[View] mode a normal editing buffer,
+warning if the file exists in another buffer simultaneously.
+@enddefcom
+
+@defcom[com "View Scroll Down", bind (View: Space)]
+@defhvar1[var "View Scroll Deleting Buffer", val {t}]
+This command scrolls the current window down through its buffer.  If the end of
+the file is visible, then this deletes the buffer if @hid[View Scroll Deleting
+Buffer] is set.  If the buffer is associated with a @hid[Dired] buffer, this
+returns there instead of to the previous buffer.
+@enddefcom
+
+@defcom[com "View Return", bind (View: ^)]
+@defcom1[com "View Quit", bind (View: q)]
+These commands invoke a function that returns to the buffer that created the
+current buffer in @hid[View] mode.  Sometimes this function does nothing, but
+it is useful for returning to @hid[Dired] buffers and similar @hemlock
+features.
+
+After invoking the viewing return function if there is one, @hid[View Quit]
+deletes the buffer that is current when the user invokes it.
+@enddefcom
+
+Also, bound in @hid[View] mode are the following commands:
+@Begin[Description]
+@binding[backspace], @binding[delete]@\Scrolls the window up.
+
+@binding[<]@\Goes to the beginning of the buffer.
+
+@binding[>]@\Goes to the end of the buffer.
+@End[Description]
+
+
+@section[Process Mode]
+@Label[process]
+@Index[shells]
+@Index[processes]
+
+@hid[Process] mode allows the user to execute a Unix process within a @hemlock
+buffer.  These commands and default bindings cater to running Unix shells in
+buffers.  For example, @hid[Stop Buffer Subprocess] is bound to @binding[H-z]
+to stop the process you are running in the shell instead of binding @hid[Stop
+Main Process] to this key which would stop the shell itself.
+
+@defcom[com "Shell", bind (C-M-s)]
+@defhvar1[var "Shell Utility", val {"/bin/csh"}]
+@defhvar1[var "Shell Utility Switches", val {@nil}]
+@defhvar1[var "Current Shell"]
+@defhvar1[var "Ask about Old Shells"]
+This command executes the process determined by the values of @hid(Shell
+Utility) and @hid(Shell Utility Switches) in a new buffer named @f["Shell n"]
+where @f["n"] is some distinguishing integer.
+
+@hid[Current Shell] is a @hemlock variable that holds to the current shell
+buffer.  When @hid[Shell] is invoked, if there is a @hid[Current Shell], the
+command goes to that buffer.
+
+When there is no @hid[Current Shell], but shell buffers do exist, if @hid[Ask
+about Old Shells] is set, the @hid[Shell] command prompts for one of them,
+setting @hid[Current Shell] to the indicated shell, and goes to the buffer.
+
+Invoking @hid[Shell] with an argument forces the creation of a new shell
+buffer.
+
+@hid[Shell Utility] is the string name of the process to execute.
+
+@hid[Shell Utility Switches] is a string containing the default command line
+arguments to @hid[Shell Utility].  This is a string since the utility is
+typically @f["/bin/csh"], and this string can contain I/O redirection and other
+shell directives.
+@enddefcom
+
+@defcom[com "Shell Command Line in Buffer"]
+This command prompts for a buffer and a shell command line.  It then runs a
+shell, giving it the command line, in the buffer.
+@enddefcom
+
+@defcom[com "Stop Main Process"]
+This command stops the process running in the current buffer by sending a
+@f[:SIGTSTP] to that process.  With an argument, stops the process using
+@f[:SIGSTOP].
+@enddefcom
+
+@defcom[com "Continue Main Process"]
+If the process in the current buffer is stopped, this command continues it.
+@enddefcom
+
+@defcom[com "Kill Main Process"]
+This command kills the process running in the current buffer.
+@enddefcom
+
+@defcom[com "Stop Buffer Subprocess", stuff (bound to @bf[H-z] in @hid[Process] mode)]
+This command stops the foreground subprocess of the process in the current
+buffer, similar to the effect of @binding[C-Z] in a shell.
+@enddefcom
+
+@defcom[com "Interrupt Buffer Subprocess", stuff (bound to  @bf[H-c] in @hid[Process] mode)]
+This command interrupts the foreground subprocess of the process in the
+current buffer, similar to the effect of @binding[C-C] in a shell.
+@enddefcom
+
+@defcom[com "Quit Buffer Subprocess", stuff (bound to @bf[H-\] in @hid[Process] mode)]
+This command dumps the core of the foreground subprocess of the processs in
+the current buffer, similar to the effect of @binding[C-\] in a shell.
+@enddefcom
+
+@defcom[com "Send EOF to Process", stuff (bound to @bf[H-d] in @hid[Process] mode)]
+This command sends the end of file character to the process in the current
+buffer, similar to the effect of @binding[C-D] in a shell.
+@enddefcom
+
+@defcom[com "Confirm Process Input", stuff (bound to @bf[Return] in @hid[Process] mode)]
+This command sends the text the user has inserted at the end of a process
+buffer to the process in that buffer.  Resulting output is inserted at the end
+of the process buffer.
+@enddefcom
+
+The user may edit process input using commands that are shared with
+@hid[Typescript] mode, see section @ref[typescripts].
+
+
+@section[Bufed Mode]
+@hemlock provides a mechanism for managing buffers as an itemized list.
+@hid[Bufed] supports conveniently deleting several buffers at once, saving
+them, going to one, etc., all in a key stroke.
+
+@defcom[com "Bufed", bind (C-x C-M-b)]
+This command creates a list of buffers in a buffer supporting operations such
+as deletion, saving, and selection.  If there already is a @hid[Bufed] buffer,
+this just goes to it.
+@enddefcom
+
+@defcom[com "Bufed Help"]
+This command pops up a display of @hid[Bufed] help.
+@enddefcom
+
+@defcom[com "Bufed Delete", bind (Bufed: C-d, C-D, D, d)]
+@defhvar1[var "Virtual Buffer Deletion", val {t}]
+@defhvar1[var "Bufed Delete Confirm", val {t}]
+@hid[Bufed Delete] deletes the buffer on the current line.
+
+When @hid[Virtual Buffer Deletion] is set, this merely flags the buffer for
+deletion until @hid[Bufed Expunge] or @hid[Bufed Quit] executes.
+
+Whenever these commands actually delete a buffer, if @hid[Bufed Delete Confirm]
+is set, then @hemlock prompts the user for permission; if more than one buffer
+is flagged for deletion, this only prompts once.  For each modified buffer,
+@hemlock asks to save the buffer before deleting it.
+@enddefcom
+
+@defcom[com "Bufed Undelete", bind (Bufed: U, u)]
+This command undeletes the buffer on the current line.
+@enddefcom
+
+@defcom[com "Bufed Expunge", bind (Bufed: !)]
+This command expunges any buffers marked for deletion regarding @hid[Bufed
+Delete Confirm].
+@enddefcom
+
+@defcom[com "Bufed Quit", bind (Bufed: q)]
+This command kills the @hid[Bufed] buffer, expunging any buffers marked for
+deletion.
+@enddefcom
+
+@defcom[com "Bufed Goto", bind (Bufed: Space)]
+This command selects the buffer on the current line, switching to it.
+@enddefcom
+
+@defcom[com "Bufed Goto and Quit", bind (Bufed: S-leftdown)]
+This command goes to the buffer under the pointer, quitting @hid[Bufed].  It
+supplies a function for @hid[Generic Pointer Up] which is a no-op.
+@enddefcom
+
+@defcom[com "Bufed Save File", bind (Bufed: s)]
+This command saves the buffer on the current line.
+@enddefcom
+
+
+@section[Completion]
+This is a minor mode that saves words greater than three characters in length,
+allowing later completion of those words.  This is very useful for the often
+long identifiers used in Lisp programs.  As you type a word, such as a Lisp
+symbol when in @hid[Lisp] mode, and you progress to typing the third letter,
+@hemlock displays a possible completion in the status line.  You can then
+rotate through the possible completions or type some more letters to narrow
+down the possibilities.  If you choose a completion, you can also rotate
+through the possibilities in the buffer instead of in the status line.
+Choosing a completion or inserting a character that delimits words moves the
+word forward in the ring of possible completions, so the next time you enter
+its initial characters, @hemlock will prefer it over less recently used
+completions.
+
+@defcom[com "Completion Mode"]
+This command toggles @hid[Completion] mode in the current buffer.
+@enddefcom
+
+@defcom[com "Completion Self Insert"]
+This command is like @hid[Self Insert], but it also checks for possible
+completions displaying any result in the status line.  This is bound to most of
+the key-events with corresponding graphic characters.
+@enddefcom
+
+@defcom[com "Completion Complete Word", bind (Completion: End)]
+This command selects the currently displayed completion if there is one,
+guessing the case of the inserted text as with @hid[Query Replace].  Invoking
+this immediately in succession rotates through possible completions in the
+buffer.  If there is no currently displayed completion on a first invocation,
+this tries to find a completion from text immediately before the point and
+displays the completion if found.
+@enddefcom
+
+@defcom[com "Completion Rotate Completions", bind (Completion: M-End)]
+This command displays the next possible completion in the status line.  If
+there is no currently displayed completion, this tries to find a completion
+from text immediately before the point and displays the completion if found.
+@enddefcom
+
+@defcom[com "List Possible Completions"]
+This command lists all the possible completions for the text immediately before
+the point in a pop-up display.  Sometimes this is more useful than rotating
+through several completions to see if what you want is available.
+@enddefcom
+
+@defhvar[var "Completion Bucket Size", val {20}]
+Completions are stored in buckets determined by the first three letters of a
+word. This variable limits the number of completions saved for each combination
+of the first three letters of a word.  If you have many identifier in some
+module beginning with the same first three letters, you'll need increase this
+variable to accommodate all the names.
+@enddefhvar
+
+
+@defcom[com "Save Completions"]
+@defcom1[com "Read Completions"]
+@defhvar1[var "Completion Database Filename", val {nil}]
+@hid[Save Completions] writes the current completions to the file
+@hid[Completion Database Filename].  It writes them, so @hid[Read Completions]
+can read them back in preserving the most-recently-used order.  If the user
+supplies an argument, then this prompts for a pathname.
+
+@hid[Read Completions] reads completions saved in @hid[Completion Database
+Filename].  It moves any current completions to a less-recently-used status,
+and it removes any in a given bucket that exceed the limit @hid[Completion
+Bucket Size].
+@enddefcom
+
+@defcom[com "Parse Buffer for Completions"]
+This command passes over the current buffer putting each valid completion word
+into the database.  This is a good way of picking up many useful completions
+upon visiting a new file for which there are no saved completions.
+@enddefcom
+
+
+@section[CAPS-LOCK Mode]
+
+@hid[CAPS-LOCK] is a minor mode in which @hemlock that inserts all alphabetic
+characters as uppercase letters.
+
+@defcom[com "Caps Lock Mode"]
+This command toggles @hid[CAPS-LOCK] mode for the current buffer; it is most
+useful when bound to a key, so you can enter and leave @hid[CAPS-LOCK] mode
+casually.
+@enddefcom
+
+@defcom[com "Self Insert Caps Lock"]
+This command inserts the uppercase version of the character corresponding to
+the last key-event typed.
+@enddefcom
+
+
+
+@section[Overwrite Mode]
+
+@hid[Overwrite] mode is a minor mode which is useful for creating figures and
+tables out of text.  In this mode, typing a key-event with a corresponding
+graphic character replaces the character at the point instead of inserting the
+character.  @hid[Quoted Insert] can be used to insert characters normally.
+
+@defcom[com "Overwrite Mode"]
+This command turns on @hid[Overwrite] mode in the current buffer.  If it is
+already on, then it is turned off.  A positive argument turns @hid[Overwrite]
+mode on, while zero or a negative argument turns it off.
+@enddefcom
+
+@defcom[com "Self Overwrite"]
+This command replaces the next character with the character corresponding to
+the key-event used to invoke the command.  After replacing the character, this
+moves past it.  If the next character is a tab, this first expands the tab into
+the appropriate number of spaces, replacing just the next space character.
+At the end of the line, it inserts the
+character instead of clobbering the newline.
+
+This is bound to key-events with corresponding graphic characters in
+@hid[Overwrite] mode.
+@enddefcom
+
+@defcom[com "Overwrite Delete Previous Character",
+       stuff (bound to @bf[Delete] and @bf[Backspace] in @hid[Overwrite] mode)]
+This command replaces the previous character with a space and moves backwards.
+This deletes tabs and newlines.
+@enddefcom
+
+
+@section[Word Abbreviation]
+@index[word abbreviation]
+Word abbreviation provides a way to speed the typing of frequently used words
+and phrases.  When in @hid[Abbrev] mode, typing a word delimiter causes the
+previous word to be replaced with its @i[expansion] if there is one currently
+defined.  The expansion for an abbrev may be any string, so this mode can be
+used for abbreviating programming language constructs and other more obscure
+uses.  For example, @hid[Abbrev] mode can be used to automatically correct
+common spelling mistakes and to enforce consistent capitalization of
+identifiers in programs.
+
+@i[Abbrev] is an abbreviation for @i[abbreviation], which is used for
+historical reasons.  Obviously the original writer of @hid[Abbrev] mode hated
+to type long words and could hardly use @hid[Abbrev] mode while writing
+@hid[Abbrev] mode. 
+
+A word abbrev can be either global or local to a major mode.  A global word
+abbrev is defined no matter what the current major mode is, while a mode word
+abbrev is only defined when its mode is the major mode in the current buffer.
+Mode word abbrevs can be used to prevent abbrev expansion in inappropriate
+contexts.
+
+
+@subsection[Basic Commands]
+
+@defcom[com "Abbrev Mode"]
+This command turns on @hid[Abbrev] mode in the current buffer.  If @hid[Abbrev]
+mode is already on, it is turned off.  @hid[Abbrev] mode must be on for the
+automatic expansion of word abbrevs to occur, but the abbreviation commands are
+bound globally and may be used at any time.
+@enddefcom
+
+@defcom[com "Abbrev Expand Only", 
+        stuff (bound to word-delimiters in @hid[Abbrev] mode)]
+This is the word abbrev expansion command.  If the word before the point is a
+defined word abbrev, then it is replaced with its expansion.  The replacement
+is done using the same case-preserving heuristic as is used by
+@hid[Query Replace].  This command is globally bound to @binding[M-Space] so
+that abbrevs can be expanded when @hid[Abbrev] mode is off.  An undesirable
+expansion may be inhibited by using @binding[C-q] to insert the delimiter.
+@enddefcom
+
+@defcom[com "Inverse Add Global Word Abbrev", bind (C-x -)]
+@defcom1[com "Inverse Add Mode Word Abbrev", bind (C-x C-h, C-x Backspace)]
+@hid[Inverse Add Global Word Abbrev] prompts for a string and makes it the
+global word abbrev expansion for the word before the point.
+
+@hid[Inverse Add Mode Word Abbrev] is identical to 
+@hid[Inverse Add Global Word Abbrev] except that it defines an expansion which
+is local to the current major mode.
+@enddefcom
+
+@defcom[com "Make Word Abbrev"]
+This command defines an arbitrary word abbreviation.  It prompts for the mode,
+abbreviation and expansion.  If the mode @f["Global"] is specified, then it
+makes a global abbrev.
+@enddefcom
+
+@defcom[com "Add Global Word Abbrev", bind (C-x +)]
+@defcom1[com "Add Mode Word Abbrev", bind (C-x C-a)]
+@hid[Add Global Word Abbrev] prompts for a word and defines it to be a global
+word abbreviation.  The prefix argument determines which text is used as the
+expansion:
+@begin[description]
+@i[no prefix argument]@\The word before the point is used as the expansion of
+the abbreviation.
+
+@i[zero prefix argument]@\The text in the region is used as the expansion of the
+abbreviation.
+
+@i[positive prefix argument]@\That many words before the point are made the
+expansion of the abbreviation.
+
+@i[negative prefix argument]@\Do the same thing as 
+@hid[Delete Global Word Abbrev] instead of defining an abbreviation.
+@end[description]
+
+@hid[Add Mode Word Abbrev] is identical to @hid[Add Global Word Abbrev] except
+that it defines or deletes mode word abbrevs in the current major mode.
+@enddefcom
+
+@defcom[com "Word Abbrev Prefix Mark", bind (M-")]
+This command allows @hid[Abbrev Expand Only] to recognize abbreviations when
+they have prefixes attached.  First type the prefix, then use this command.  A
+hyphen (@f[-]) will be inserted in the buffer.  Now type the abbreviation and
+the word delimiter.  @hid[Abbrev Expand Only] will expand the abbreviation and
+remove the hyphen.
+
+Note that there is no need for a suffixing command, since 
+@hid[Abbrev Expand Only] may be used explicitly by typing @binding[M-Space].
+@enddefcom
+
+@defcom[com "Unexpand Last Word", bind (C-x u)]
+This command undoes the last word abbrev expansion.  If repeated, undoes its
+own effect.
+@enddefcom
+
+
+@subsection[Word Abbrev Files]
+A word abbrev file is a file which holds word abbrev definitions.  Word abbrev
+files allow abbrevs to be saved so that they may be used across many editing
+sessions.
+
+@defhvar[var "Abbrev Pathname Defaults", val {(pathname "abbrev.defns")}]
+This is sticky default for the following commands.  When they prompt for a file
+to write, they offer this and set it for the next time one of them executes.
+@enddefhvar
+
+@defcom[com "Read Word Abbrev File"]
+This command reads in a word abbrev file, adding all the definitions to those
+currently defined.  If a definition in the file is different from the current
+one, the current definition is replaced.
+@enddefcom
+
+@defcom[com "Write Word Abbrev File"]
+This command prompts for a file and writes all currently defined word abbrevs
+out to it.
+@enddefcom
+
+@defcom[com "Append to Word Abbrev File"]
+This command prompts for a word abbrev file and appends any new definitions to
+it.  An abbrev is new if it has been defined or redefined since the last use of
+this command.  Definitions made by reading word abbrev files are not
+considered.
+@enddefcom
+
+
+@subsection[Listing Word Abbrevs]
+@defcom[com "List Word Abbrevs"]
+@defcom1[com "Word Abbrev Apropos"]
+@hid[List Word Abbrevs] displays a list of each defined word abbrev, with its
+mode and expansion.
+
+@hid[Word Abbrev Apropos] is similar, except that it only displays abbrevs
+which contain a specified string, either in the definition, expansion or mode.
+@enddefcom
+
+@subsection[Editing Word Abbrevs]
+Word abbrev definition lists are edited by editing the text representation
+of the definitions.  Word abbrev files may be edited directly, like any other
+text file.  The set of abbrevs currently defined in @hemlock may be edited
+using the commands described in this section.
+
+The text representation of a word abbrev is fairly simple.  Each definition
+begins at the beginning of a line.  Each line has three fields which are
+separated by ASCII tab characters.  The fields are the abbreviation, the mode
+of the abbreviation and the expansion.  The mode is represented as the mode
+name inside of parentheses.  If the abbrev is global, then the mode field is
+empty.  The expansion is represented as a quoted string since it may contain
+any character.  The string is quoted with double-quotes (@f["]); double-quotes
+in the expansion are represented by doubled double-quotes.  The expansion may
+contain newline characters, in which case the definition will take up more than
+one line.
+
+@defcom[com "Edit Word Abbrevs"]
+This command inserts the current word abbrev definitions into the 
+@hid[Edit Word Abbrevs] buffer and then enters a recursive edit on the buffer.
+When the recursive edit is exited, the definitions in the buffer become the new
+current abbrev definitions.
+@enddefcom
+
+@defcom[com "Insert Word Abbrevs"]
+This command inserts at the point the text representation of the currently
+defined word abbrevs.
+@enddefcom
+
+@defcom[com "Define Word Abbrevs"]
+This command interprets the text of the current buffer as a word abbrev
+definition list, adding all the definitions to those currently defined.
+@enddefcom
+
+
+@subsection[Deleting Word Abbrevs]
+The user may delete word abbrevs either individually or collectively.
+Individual abbrev deletion neutralizes single abbrevs which have outlived their
+usefulness; collective deletion provides a clean slate from which to initiate
+abbrev definitions.
+
+@defcom[com "Delete All Word Abbrevs"]
+This command deletes all word abbrevs which are currently defined.
+@enddefcom
+
+@defcom[com "Delete Global Word Abbrev"]
+@defcom1[com "Delete Mode Word Abbrev"]
+@hid[Delete Global Word Abbrev] prompts for a word abbreviation and deletes its
+global definition.  If given a prefix argument, deletes all global abbrev
+definitions.
+
+@hid[Delete Mode Word Abbrev] is identical to @hid[Delete Global Word Abbrev]
+except that it deletes definitions in the current major mode.
+@enddefcom
+
+
+@section[Lisp Library]
+This is an implementation dependent feature.  The Lisp library is a collection
+of local hacks that users can submit and share that is maintained by the Lisp
+group.  These commands help peruse the catalog or description files and figure
+out how to load the entries.
+
+@defcom[com "Lisp Library"]
+This command finds all the library entries and lists them in a buffer.  The
+following commands describe and load those entries.
+@enddefcom
+
+@defcom[com "Describe Library Entry", bind (Lisp-Lib: space)]
+@defcom1[com "Describe Pointer Library Entry", bind (Lisp-Lib: leftdown)]
+@defcom1[com "Load Library Entry", bind (Lisp-Lib: rightdown)]
+@defcom1[com "Load Pointer Library Entry", bind (Lisp-Lib: l)]
+@defcom1[com "Editor Load Library Entry"]
+@defcom1[com "Editor Load Pointer Library Entry"]
+@hid[Load Library Entry] and @hid[Load Pointer Library Entry] load the library
+entry indicated by the line on which the point lies or where the user clicked
+the pointer, respectively.  These load the entry into the current slave Lisp.
+
+@hid[Editor Load Library Entry] and @hid[Editor Load Pointer Library Entry] are
+the same, but they load the entry into the editor Lisp.
+@enddefcom
+
+@defcom[com "Exit Lisp Library", bind (Lisp-Lib: q)]
+This command deletes the @hid[Lisp Library] buffer.
+@enddefcom
+
+@defcom[com "Lisp Library Help", bind (Lisp-Lib: ?)]
+This command pops up a help window listing @hid[Lisp-Lib] commands.
+@enddefcom
diff --git a/docs/hem/user/user.mss b/docs/hem/user/user.mss
new file mode 100644
index 000000000..37574d183
--- /dev/null
+++ b/docs/hem/user/user.mss
@@ -0,0 +1,1958 @@
+@make[Manual] @comment{-*- Dictionary: bld:scribe/hem/hem; Mode: spell; Package: Hemlock; Log: /usr/lisp/scribe/hem/hem-docs.log -*-}
+@Device[postscript]
+@Style(Spacing = 1.2 lines)
+@Style(StringMax = 5000)
+@Use(Database "/usr/lisp/scribe/database/")
+@Style(FontFamily=TimesRoman)
+@Style(Date="March 1952")
+@style(DOUBLESIDED)
+@Libraryfile[ArpaCredit]
+@libraryfile[hem]
+@Libraryfile[Spice]
+@Libraryfile[Uttir]
+
+@String(REPORTTITLE "Hemlock User's Manual")
+
+@comment<@begin[TitlePage]
+@begin[TitleBox]
+>
+@blankspace(1.3inches)
+@heading[Hemlock User's Manual]
+
+@center[@b<Bill Chiles>
+@b<Robert A. MacLachlan>
+
+
+@b<@value[date]>
+
+@b<CMU-CS-89-133-R1>
+]
+@comment<@end[TitleBox]>
+@blankspace(2lines)
+@begin[Center]
+School of Computer Science
+Carnegie Mellon University
+Pittsburgh, PA 15213
+@end[Center]
+@blankspace[2lines]
+
+@begin[Center]
+This is a revised version of Technical Report CMU-CS-87-158.
+@end[Center]
+
+@heading<Abstract>
+@begin(Text, indent 0)
+This document describes the @Hemlock text editor, version M3.2.  @Hemlock is a
+customizable, extensible text editor whose initial command set closely
+resembles that of ITS/TOPS-20 @Emacs.  @Hemlock is written in CMU Common Lisp
+and has been ported to other implementations.
+@end(Text)
+
+@begin[ResearchCredit]
+@ArpaCredit[Contract=Basic87-90]
+@end[ResearchCredit]
+@comment<@end[TitlePage]>
+
+
+@commandstring(mh = "@f1(MH)")
+@commandstring(dash = "@Y[M]")
+
+@comment[This tabclear is necessary since the definition macros don't
+	 take care of the own tabbing needs]
+@tabclear
+
+
+@comment[@chap (Introduction)]
+@include(intro)
+
+
+@comment[@chap (Basic Commands)]
+@include(commands)
+
+
+
+@chap[Files, Buffers, and Windows]
+
+@section[Introduction]
+
+@index[files]@index[buffers]@index[windows]@hemlock provides three
+different abstractions which are used in combination to solve the
+text-editing problem, while other editors tend to mash these ideas together
+into two or even one.
+@begin[description]
+File@\A file provides permanent storage of text.  @hemlock has commands
+to read files into buffers and write buffers out into files.
+
+Buffer@\A buffer provides temporary storage of text and a capability to
+edit it.  A buffer may or may not have a file associated with it; if it
+does, the text in the buffer need bear no particular relation to the text
+in the file.  In addition, text in a buffer may be displayed in any number
+of windows, or may not be displayed at all.
+
+Window@\A window displays some portion of a buffer on the screen.  There
+may be any number of windows on the screen, each of which may display any
+position in any buffer.  It is thus possible, and often useful, to have
+several windows displaying different places in the same buffer.
+@end[description]
+
+
+@section[Buffers]
+In addition to some text, a buffer has several other user-visible attributes:
+@begin[description]
+A name@\
+A buffer is identified by its name, which allows it to be selected, destroyed,
+or otherwise manipulated.
+
+A collection of modes@\
+The modes present in a buffer alter the set of commands available and
+otherwise alter the behavior of the editor.  For details see page
+@pageref[modes].
+
+A modification flag @\
+This flag is set whenever the text in a buffer is modified.  It is often
+useful to know whether a buffer has been changed, since if it has it should
+probably be saved in its associated file eventually.
+
+A write-protect flag @\
+If this flag is true, then any attempt to modify the buffer will result in an
+error.
+@end[description]
+
+@defcom[com "Select Buffer", bind (C-x b)]
+This command prompts for the name of a existing buffer and makes that buffer
+the @i[current buffer].  The newly selected buffer is displayed in the
+current window, and editing commands now edit the text in that buffer.
+Each buffer has its own point, thus the point will be in the place it was
+the last time the buffer was selected.  When prompting for the buffer, the
+default is the buffer that was selected before the current one.
+@enddefcom
+
+@defcom[com "Select Previous Buffer", bind (C-M-l)]
+@defcom1[com "Circulate Buffers", bind (C-M-L)]
+With no prefix argument, @hid[Select Previous Buffer] selects the buffer that
+has been selected most recently, similar to @binding[C-x b Return].  If given a
+prefix argument, then it does the same thing as @hid[Circulate Buffers].
+
+@hid[Circulate Buffers] moves back into successively earlier buffers in the
+buffer history.  If the previous command was not @hid[Circulate Buffers] or
+@hid[Select Previous Buffer], then it does the same thing as
+@hid[Select Previous Buffer], otherwise it moves to the next most recent
+buffer.  The original buffer at the start of the excursion is made the previous
+buffer, so @hid[Select Previous Buffer] will always take you back to where you
+started.
+
+These commands are generally used together.  Often @hid[Select Previous Buffer]
+will take you where you want to go.  If you don't end up there, then using
+@hid[Circulate Buffers] will do the trick.
+@enddefcom
+
+@defcom[com "Create Buffer", bind (C-x M-b)]
+This command is very similar to @hid[Select Buffer], but the buffer need not
+already exist.  If the buffer does not exist, a new empty buffer is created
+with the specified name.
+@enddefcom
+
+@defcom[com "Kill Buffer", bind (C-x k)]
+This command is used to make a buffer go away.  There is no way to restore
+a buffer that has been accidentally deleted, so the user is given a chance
+to save the hapless buffer if it has been modified.  This command is poorly
+named, since it has nothing to do with killing text.
+@enddefcom
+
+@defcom[com "List Buffers", bind (C-x C-b)]
+This command displays a list of all existing buffers in a pop-up window.  A
+"@f[*]" is displayed before the name of each modified buffer.  A buffer with no
+associated file is represented by the buffer name followed by the number of
+lines in the buffer.  A buffer with an associated file are is represented by
+the name and type of the file, a space, and the device and directory.  If the
+buffer name doesn't match the associated file, then the buffer name is also
+displayed.  When given a prefix argument, this command lists only the modified
+buffers.
+@enddefcom
+
+@defcom[com "Buffer Not Modified", bind (M-~)]
+This command resets the current buffer's modification flag @dash @i[it does not
+save any changes].  This is primarily useful in cases where a user accidentally
+modifies a buffer and then undoes the change.  Resetting the modified flag
+indicates that the buffer has no changes that need to be written out.
+@enddefcom
+
+@defcom[com "Check Buffer Modified", bind (C-x ~)]
+This command displays a message indicating whether the current buffer is modified.
+@enddefcom
+
+@defcom[com "Set Buffer Read-Only"]
+This command changes the flag that allows the current buffer to be modified.
+If a buffer is read-only, any attempt to modify it will result in an error.  The
+buffer may be made writable again by repeating this command.
+@enddefcom
+
+@defcom[com "Insert Buffer"]
+This command prompts for the name of a buffer and inserts its contents at the
+point, pushing a buffer mark before inserting.  The buffer inserted is
+unaffected.
+@enddefcom  
+
+@defcom[com "Rename Buffer"]
+This command prompts for a new name for the current buffer, which defaults
+to a name derived from the associated filename.
+@enddefcom
+
+
+@section[Files]
+@index[files]
+These commands either read a file into the current buffer or write it out to
+some file.  Various other bookkeeping operations are performed as well.
+
+@defcom[com "Find File", bind (C-x C-f)]
+This is the command normally used to get a file into @hemlock.  It prompts
+for the name of a file, and if that file has already been read in, selects
+that buffer; otherwise, it reads file into a new buffer whose name is
+derived from the name of the file.  If the file does not exist, then the
+buffer is left empty, and @w<"@f[(New File)]"> is displayed in the echo area;
+the file may then be created by saving the buffer.
+
+The buffer name created is in the form @w<"@i[name] @i[type] @i[directory]">.
+This means that the filename "@f[/sys/emacs/teco.mid]" has
+@w<"@f[Teco Mid /Sys/Emacs/]"> as its the corresponding buffer name.  The
+reason for rearranging the fields in this fashion is that it facilitates
+recognition since the components most likely to differ are placed first.  If
+the buffer cannot be created because it already exists, but has another file in
+it (an unlikely occurrence), then the user is prompted for the buffer to use,
+as by @hid[Create Buffer].
+
+@hid[Find File] takes special action if the file has been modified on disk
+since it was read into @hemlock.  This usually happens when several people are
+simultaneously editing a file, an unhealthy circumstance.  If the buffer is
+unmodified, @hid[Find File] just asks for confirmation before reading in the
+new version.  If the buffer is modified, then @hid[Find File] beeps and prompts
+for a single key-event to indicate what action to take.  It recognizes
+the following key-events:
+@begin[description]
+@binding[Return, Space, y]@\
+ Prompt for a file in which to save the current buffer and then read in the
+file found to be modified on disk.
+
+@binding[Delete, Backspace, n]@\
+ Forego reading the file.
+
+@binding[r]@\
+ Read the file found to be modified on disk into the buffer containing the
+earlier version with modifications.  This loses all changes you had in the
+buffer.
+@end[description]
+@enddefcom
+
+@defcom[com "Save File", bind (C-x C-s)]
+This command writes the current buffer out to its associated file and
+resets the buffer modification flag.  If there is no associated file, then
+the user is prompted for a file, which is made the associated file.  If
+the buffer is not modified, then the user is asked whether to actually
+write it or not.
+
+If the file has been modified on disk since the last time it was read,
+@hid[Save File] prompts for confirmation before overwriting the file.
+@enddefcom
+
+@defcom[com "Save All Files", bind (C-x C-m)]
+@defcom1[com "Save All Files and Exit", bind (C-x M-z)]
+@defhvar1[var "Save All Files Confirm", val {t}]
+@hid[Save All Files] does a @hid[Save File] on all buffers which have an
+associated file.  @hid[Save All Files and Exit] does the same thing and then
+exits @hemlock.
+
+When @hid[Save All Files Confirm] is true, these commands will ask for
+confirmation before saving a file.
+@enddefcom
+
+@defcom[com "Visit File", bind (C-x C-v)]
+This command prompts for a file and reads it into the current buffer,
+setting the associated filename.  Since the old contents of the buffer are
+destroyed, the user is given a chance to save the buffer if it is modified.
+As for @hid[Find File], the file need not actually exist.  This command warns
+if some other buffer also contains the file.
+@enddefcom
+
+@defcom[com "Write File", bind (C-x C-w)] This command prompts for a file
+and writes the current buffer out to it, changing the associated filename
+and resetting the modification flag.  When the buffer's associated file is
+specified this command does the same thing as @hid[Save File].  @enddefcom
+
+@defcom[com "Backup File"]
+This command is similar to @hid[Write File], but it neither sets the
+associated filename nor clears the modification flag.  This is useful for
+saving the current state somewhere else, perhaps on a reliable machine.
+
+Since @hid[Backup File] doesn't update the write date for the buffer,
+@hid[Find File] and @hid[Save File] will get all upset if you back up
+a buffer on any file that has been read into @hemlock.
+@enddefcom
+
+@defcom[com "Revert File"]
+@defhvar1[var "Revert File Confirm", val {t}]
+This command replaces the text in the current buffer with the contents of the
+associated file or the checkpoint file for that file, whichever is more recent.
+The point is put in approximately the same place that it was before the file
+was read.  If the original file is reverted to, then clear the modified flag,
+otherwise leave it set.  If a prefix argument is specified, then always revert
+to the original file, ignoring any checkpoint file.
+
+If the buffer is modified and @hid[Revert File Confirm] is true, then the user
+is asked for confirmation.
+@enddefcom
+
+@defcom[com "Insert File", bind (C-x C-r)]
+This command prompts for a file and inserts it at the point, pushing a buffer
+mark before inserting.
+@enddefcom
+
+@defcom[com "Write Region"]
+This command prompts for a file and writes the text in the region out to it.
+@enddefcom
+
+@defhvar[var "Add Newline at EOF on Writing File", val {:ask-user}]
+This variable controls whether some file writing commands add a newline at the
+end of the file if the last line is non-empty.
+@begin[description]
+@f[:ask-user]@\Ask the user whether to add a newline.
+
+@f[t]@\Automatically add a newline and inform the user.
+
+@nil@\Never add a newline and do not ask.
+@end[description]
+Some programs will lose the text on the last line or get an
+error when the last line does not have a newline at the end.
+@enddefhvar
+
+@defhvar[var "Keep Backup Files", val {nil}]
+Whenever a file is written by @hid[Save File] and similar commands, the old
+file is renamed by appending "@f[.BAK]" to the name, ensuring that some version
+of the file will survive a system crash during the write.  If set to true, this
+backup file will not deleted even when the write successfully completes.
+@enddefhvar
+
+
+@subsection[Auto Save Mode]
+
+@hid[Save] mode protects against loss of work in system crashes by periodically
+saving modified buffers in checkpoint files.
+
+@defcom[com "Auto Save Mode"]
+This command turns on @hid[Save] mode if it is not on, and turns off when it is
+on.  @hid[Save] mode is on by default.
+@enddefcom
+
+@defhvar[var "Auto Save Checkpoint Frequency", val {120}]
+@defhvar1[var "Auto Save Key Count Threshold", val {256}]
+These variables determine how often modified buffers in @hid[Save] mode will be
+checkpointed.  Checkpointing is done after
+@hid[Auto Save Checkpoint Frequency] seconds, or after
+@hid[Auto Save Key Count Threshold] keystrokes that modify the buffer
+(whichever comes first).  Either kind of checkpointing may be disabled by
+setting the corresponding variable to @nil.
+@enddefhvar
+
+@defhvar[var "Auto Save Cleanup Checkpoints", val {t}]
+If this variable is true, then any checkpoint file for a buffer will be deleted
+when the buffer is successfully saved in its associated file.
+@enddefhvar
+
+@defhvar[var "Auto Save Filename Pattern", val {"~A~A.CKP"}]
+@defhvar1[var "Auto Save Pathname Hook", val {make-unique-save-pathname}]
+These variables determine the naming of checkpoint files.
+@hid[Auto Save Filename Pattern] is a format string used to name the checkpoint
+files for buffers with associated files.  Format is called with two arguments:
+the directory and file namestrings of the associated file.
+
+@hid[Auto Save Pathname Hook] is a function called by @hid[Save] mode to get a
+checkpoint pathname when there is no pathname associated with a buffer.  It
+should take a buffer as its argument and return either a pathname or @nil.  If
+a pathname is returned, then it is used as the name of the checkpoint file.  If
+the function returns @nil, or if the hook variable is @nil, then @hid[Save]
+mode is turned off in the buffer.  The default value for this variable returns
+a pathname in the default directory of the form "@w<@f[save-]@i[number]>",
+where @i[number] is a number used to make the file unique.
+@enddefhvar
+
+
+@subsection[Filename Defaulting and Merging]
+@index[merging, filename]
+@index[defaulting, filename]
+@index[filename defaulting]
+@label[merging]
+@index[pathnames]
+When @hemlock prompts for the name of a file, it always offers a default.
+Except for a few commands that have their own defaults, filename defaults are
+computed in a standard way.  If it exists, the associated file for the current
+buffer is used as the default, otherwise a more complex mechanism creates a
+default.
+
+@defhvar[var "Pathname Defaults", val {(pathname "gazonk.del")}]
+@defhvar1[var "Last Resort Pathname Defaults Function"]
+@defhvar1[var "Last Resort Pathname Defaults", val {(pathname "gazonk")}]
+These variables control the computation of default filename defaults when the
+current buffer has no associated file.
+
+@hid[Pathname Defaults] holds a "sticky" filename default.  Commands that
+prompt for files set this to the file specified, and the value is used as a
+basis for filename defaults.  It is undesirable to offer the unmodified value
+as a default, since it is usually the name of an existing file that we don't
+want to overwrite.  If the current buffer's name is all alphanumeric, then the
+default is computed by substituting the buffer name for the the name portion of
+@hid[Pathname Defaults].  Otherwise, the default is computed by calling
+@hid[Last Resort Pathname Defaults Function] with the buffer as an argument.
+
+The default value of @hid[Last Resort Pathname Defaults Function] merges 
+@hid[Last Resort Pathname Defaults] with @hid[Pathname Defaults].
+Unlike @hid[Pathname Defaults], @hid[Last Resort Pathname Defaults] is not
+modified by file commands, so setting it to a silly name ensures that real
+files aren't inappropriately offered as defaults.
+@enddefhvar
+
+When a default is present in the prompt for a file, @hemlock @i[merges] the
+given input with the default filename.  The semantics of merging, described in
+the Common Lisp manual, is somewhat involved, but @hemlock has a few rules it
+uses:
+@begin[enumerate]
+If @hemlock can find the user's input as a file on the @f["default:"] search
+list, then it forgoes merging with the displayed default.  Basically, the
+system favors the files in your current working directory over those found by
+merging with the defaults offered in the prompt.
+
+Merging comes in two flavors, just merge with the displayed default's directory
+or just merge with the displayed default's @f[file-namestring].  If the user
+only responds with a directory specification, without any name or type
+information, then @hemlock merges the default's @f[file-namestring].  If the
+user responds with any name or type information, then @hemlock only merges with
+the default's directory.  Specifying relative directories in this second
+situation coordinates with the displayed defaults, not the current working
+directory.
+@end[enumerate]
+
+
+@subsection[Type Hooks and File Options]
+@index[mode comment]
+@index[type hooks]
+When a file is read either by @hid[Find File] or @hid[Visit File], @hemlock
+attempts to guess the correct mode in which to put the buffer, based on the
+file's @i[type] (the part of the filename after the last dot).  Any default
+action may be overridden by specifying the mode in the file's @i[file
+options].@index[modes]@index[package]
+
+@label[file-options]@index[file options] 
+The user specifies file options with a special syntax on the first line of a
+file.  If the first line contains the string "@f[-*-]", then @hemlock
+interprets the text between the first such occurrence and the second, which
+must be contained in one line , as a list of @w{"@f<@i[option]: @i[value]>"}
+pairs separated by semicolons.  The following is a typical example:
+@begin[programexample]
+;;; -*- Mode: Lisp, Editor; Package: Hemlock -*-
+@end[programexample]
+
+These options are currently defined:
+@begin[description]
+Dictionary@\The argument is the filename of a spelling dictionary associated
+with this file.  The handler for this option merges the argument with the
+name of this file.  See @comref[Set Buffer Spelling Dictionary].
+
+Log@\The argument is the name of the change log file associated with this file
+(see page @pageref[log-files]).  The handler for this option merges the
+argument with the name of this file.
+
+Mode@\The argument is a comma-separated list of the names of modes to turn on
+in the buffer that the file is read into.
+
+Package@\The argument is the name of the package to be used for reading code in
+the file.  This is only meaningful for @llisp code (see page
+@pageref[lisp-package].)
+
+Editor@\The handler for this option ignores its argument and turns on
+@hid[Editor] mode (see @comref[Editor Mode]).
+
+@end[description]
+If the option list contains no "@f[:]" then the entire string is used as
+the name of the major mode for the buffer.
+
+@defcom[com "Process File Options"]
+This command processes the file options in the current buffer as described
+above.  This is useful when the options have been changed or when a file is
+created.
+@enddefcom
+
+@section[Windows]
+
+@index[windows]When running under @windows, each @hemlock window is a
+separate window, so window manager commands can be used to move and reshape
+windows.
+
+@defcom[com "New Window", bind (C-x C-n)]
+@defcom1[com "Split Window", bind (C-x 2)]
+@defcom1[com "Stack Window"]
+@hid[New Window] creates a new window on the screen that displays the current
+window.  The dimensions of the window are determined by asking the user.
+
+@hid[Split Window] is the same as @hid[New Window] except that it creates the
+new window by splitting the current window in half.  If the current window is
+too small to be reasonably split, the command may fail; however, on some
+devices, @hemlock will make a window the same size as the current window,
+placing it on the screen shifted downward vertically a small amount.
+
+@hid[Stack Window] is the same as @i[New Window], except that it makes a window
+exactly superimposed on the current window.  This is not supported on on all
+devices.
+@enddefcom
+
+@defcom[com "Next Window", bind (C-x n)]
+@defcom1[com "Previous Window", bind (C-x p)]
+These commands make the next or previous window the new current window, often
+changing the current buffer in the process.  When a window is created, it is
+arbitrarily made the next window of the current window.  The location of the
+next window is, in general, unrelated to that of the current window.
+@enddefcom
+
+@defcom[com "Delete Window", bind (C-x C-d, C-x d)]
+@defcom1[com "Delete Next Window", bind (C-x 1)]
+@hid[Delete Window] makes the current window go away, making the next window
+current.  @hid[Delete Next Window] deletes the next window, leaving the current
+window unaffected.
+@enddefcom
+
+@defcom[com "Line to Top of Window", bind (M-!)]
+@defcom1[com "Line to Center of Window", bind (M-#)]
+@index[scrolling]@hid[Line to Top of Window] scrolls the current window up
+until the current line is at the top of the screen.
+
+@hid[Line to Center of Window] attempts to scroll the current window so that
+the current line is vertically centered.
+@enddefcom
+
+@defcom[com "Scroll Next Window Down", bind (C-M-v)]
+@defcom1[com "Scroll Next Window Up", bind (C-M-V)]
+These commands are the same as @hid[Scroll Window Up] and
+@hid[Scroll Window Down] except that they operate on the next window.
+@enddefcom
+
+@defcom[com "Refresh Screen", bind {C-l}]
+This command refreshes all windows, which is useful if the screen got trashed,
+centering the current window about the current line.  When the user supplies a
+positive argument, it scrolls that line to the top of the window.  When the
+argument is negative, the line that far from the bottom of the window is moved
+to the bottom of the window.  In either case when an argument is supplied, this
+command only refreshes the current window.
+@enddefcom
+
+
+@chap[Editing Documents]
+@index[documents, editing]
+Although @hemlock is not dedicated to editing documents as word processing
+systems are, it provides a number of commands for this purpose.  If @hemlock is
+used in conjunction with a text-formatting program, then its lack of complex
+formatting commands is no liability.
+
+
+@defcom[com "Text Mode"]
+This commands puts the current buffer into "Text" mode.
+@enddefcom
+
+
+@section[Sentence Commands]
+@index[sentence commands]
+A sentence is defined as a sequence of characters ending with a period,
+question mark or exclamation point, followed by either two spaces or a newline.
+A sentence may also be terminated by the end of a paragraph.  Any number of
+closing delimiters, such as brackets or quotes, may be between the punctuation
+and the whitespace.  This somewhat complex definition of a sentence is used so
+that periods in abbreviations are not misinterpreted as sentence ends.
+
+@defcom[com "Forward Sentence", bind {M-a}]
+@defcom1[com "Backward Sentence", bind {M-e}]
+@index[motion, sentence]@hid[Forward Sentence] moves the point forward
+past the next sentence end. @hid[Backward Sentence] moves to the beginning
+of the current sentence. A prefix argument may be used as a repeat count.
+@enddefcom
+
+@defcom[com "Forward Kill Sentence", bind {M-k}]
+@defcom1[com "Backward Kill Sentence", bind (C-x Delete, C-x Backspace)]
+@index[killing, sentence]@hid[Forward Kill Sentence] kills text from the
+point through to the end of the current sentence.  @hid[Backward Kill Sentence]
+kills from the point to the beginning of the current sentence.  A
+prefix argument may be used as a repeat count.
+@enddefcom
+
+@defcom[com "Mark Sentence"]
+This command puts the point at the beginning and the mark at the end of the
+next or current sentence.
+@enddefcom
+
+
+@section[Paragraph Commands]
+
+@index[paragraph commands]A paragraph may be delimited by a blank line or a
+line beginning with "@f[']" or "@f[.]", in which case the delimiting line is
+not part of the paragraph.  Other characters may be paragraph delimiters in
+some modes.  A line with at least one leading whitespace character may also
+introduce a paragraph and is considered to be part of the paragraph.  Any
+fill-prefix which is present on a line is disregarded for the purpose of
+locating a paragraph boundary.
+
+@defcom[com "Forward Paragraph", bind (@bf<M-]>)]
+@defcom1[com "Backward Paragraph", bind (M-[)]
+@index[motion, paragraph]@index[paragraph, motion]@hid[Forward Paragraph]
+moves to the end of the current or next paragraph. @hid[Backward Paragraph]
+moves to the beginning of the current or previous paragraph.  A prefix
+argument may be used as a repeat count.
+@enddefcom
+
+@defcom[com "Mark Paragraph", bind {M-h}]
+This command puts the point at the beginning and the mark at the end of the
+current paragraph.
+@enddefcom
+
+@defhvar[var "Paragraph Delimiter Function", val {default-para-delim-function}]
+This variable holds a function that takes a mark as its argument and returns
+true when the line it points to should break the paragraph.
+@enddefhvar
+
+@section[Filling]
+
+@index[filling]@index[formatting]Filling is a coarse text-formatting
+process which attempts to make all the lines roughly the same length, but
+doesn't vary the amount of space between words.  Editing text may leave
+lines with all sorts of strange lengths; filling this text will return it
+to a moderately aesthetic form.
+
+@defcom[com "Set Fill Column", bind (C-x f)]
+This command sets the fill column to the column that the point is currently at,
+or the one specified by the absolute value of prefix argument, if it is
+supplied.  The fill column is the column past which no text is permitted to
+extend.
+@enddefcom
+
+@defcom[com "Set Fill Prefix", bind (C-x .)]
+This command sets the fill prefix to the text from the beginning of the
+current line to the point.  The fill-prefix is a string which filling commands
+leave at the beginning of every line filled.  This feature is useful for
+filling indented text or comments.
+@enddefcom
+
+@defhvar[var "Fill Column", val {75}]
+@defhvar1[var "Fill Prefix", val {nil}]
+These variables hold the value of the fill prefix and fill column, thus
+setting these variables will change the way filling is done.  If
+@hid[Fill Prefix] is @nil, then there is no fill prefix.
+@enddefcom
+
+@defcom[com "Fill Paragraph", bind {M-q}]
+@index[paragraph, filling]This command fills the text in the current or next
+paragraph.  The point is not moved.
+@enddefcom
+
+@defcom[com "Fill Region", bind {M-g}]
+@index[region, filling]This command fills the text in the region.  Since
+filling can mangle a large quantity of text, this command asks for confirmation
+before filling a large region (see @hid[Region Query Size].)
+@enddefcom
+
+
+@defcom[com "Auto Fill Mode"]
+@index[modes, auto fill]This command turns on or off the @hid[Fill]
+minor mode in the current buffer.  When in @hid[Fill] mode, @bf[Space],
+@bf[Return] and @bf[Linefeed] are rebound to commands that check whether
+the point is past the fill column and fill the current line if it is.
+This enables typing text without having to break the lines manually.
+
+If a prefix argument is supplied, then instead of toggling, the sign
+determines whether @hid[Fill] mode is turned off; a positive argument
+argument turns in on, and a negative one turns it off.
+@enddefcom
+
+@defcom[com "Auto Fill Linefeed", stuff (bound to @bf[Linefeed] in @hid[Fill] mode)]
+@defcom1[com "Auto Fill Return", stuff (bound to @bf[Return] in @hid[Fill] mode)]
+@hid[Auto Fill Linefeed] fills the current line if it needs it and then goes to
+a new line and inserts the fill prefix.  @hid[Auto Fill Return] is similar, but
+does not insert the fill prefix on the new line.
+@enddefcom
+
+@defcom[com "Auto Fill Space", stuff (bound to @bf[Space] in @hid[Fill] mode)]
+If no prefix argument is supplied, this command inserts a space and
+fills the current line if it extends past the fill column.  If the argument is
+zero, then it fills the line if needed, but does not insert a space.  If the
+argument is positive, then that many spaces are inserted without filling.
+@enddefcom
+
+@defhvar[var "Auto Fill Space Indent", val {nil}]
+This variable determines how lines are broken by the auto fill commands.  If it
+is true, new lines are created using the @hid[Indent New Comment Line] command,
+otherwise the @hid[New Line] command is used.  Language modes should define
+this variable to be true so that auto fill mode can be used on code.
+@enddefhvar
+
+
+@section[Scribe Mode]
+
+@hid[Scribe] mode provides a number of facilities useful for editing Scribe
+documents.  It is also sufficiently parameterizable to be adapted to other
+similar syntaxes.
+
+@defcom[com "Scribe Mode"]
+@index[modes, scribe]This command puts the current buffer in @hid[Scribe] mode.
+Except for special Scribe commands, the only difference between @hid[Scribe]
+mode and @hid[Text] mode is that the rules for determining paragraph breaks are
+different.  In @hid[Scribe] mode, paragraphs delimited by Scribe commands are
+normally placed on their own line, in addition to the normal paragraph breaks.
+The main reason for doing this is that it prevents @hid[Fill Paragraph] from
+mashing these commands into the body of a paragraph.
+@enddefcom
+
+@defcom[com "Insert Scribe Directive", stuff (@bf[C-h] in @hid[Scribe] mode)]
+This command prompts for a key-event to determine which Scribe directive to
+insert.  Directives are inserted differently depending on their kind:
+@begin[description]
+@i[environment]@\
+The current or next paragraph is enclosed in a begin-end pair:
+@f<@@begin[@i{directive}]> @i[paragraph] @f<@@end[@i{directive}]>.  If the
+current region is active, then this command encloses the region instead of the
+paragraph it would otherwise chose.
+
+@i[command]@\
+The previous word is enclosed by @f<@@@i[directive][@i[word]]>.  If the
+previous word is already enclosed by a use of the same command, then the
+beginning of the command is extended backward by one word.
+@end[description]
+
+Typing @bf[Home] or @bf[C-_] to this command's prompt will display a list of
+all the defined key-events on which it dispatches.
+@enddefcom
+
+@defcom[com "Add Scribe Directive"]
+This command adds to the database of directives recognized by the 
+@hid[Insert Scribe Directive] command.  It prompts for the directive's name,
+the kind of directive (environment or command) and the key-event on which to
+dispatch.
+@enddefcom
+
+@defcom[com "Add Scribe Paragraph Delimiter"]
+@defcom1[com "List Scribe Paragraph Delimiters"]
+@hid[Add Scribe Paragraph Delimiter] prompts for a string to add to the list of
+formatting commands that delimit paragraphs in @hid[Scribe] mode.  If the user
+supplies a prefix argument, then this command removes the string as a
+delimiter.
+
+@hid[List Scribe Paragraph Delimiters] displays in a pop-up window the Scribe
+commands that delimit paragraphs.
+@enddefcom
+
+@defhvar[var "Escape Character", val {#\@@}]
+@defhvar1[var "Close Paren Character", val {#\]}]
+@defhvar1[var "Open Paren Character", val {#\[}]
+These variables determine the characters used when a Scribe directive is
+inserted.
+@enddefhvar
+
+@defcom[com "Scribe Insert Bracket"]
+@defhvar1[var "Scribe Bracket Table"]
+@hid[Scribe Insert Bracket] inserts a bracket (@bf[>], @bf[}], @bf[)], or
+@bf<]>), that caused its invocation, and then shows the matching bracket.
+
+@hid[Scribe Bracket Table] holds a @f[simple-vector] indexed by character
+codes.  If a character is a bracket, then the entry for its @f[char-code]
+should be the opposite bracket.  If a character is not a bracket, then the
+entry should be @nil.
+@enddefcom
+
+
+@section[Spelling Correction]
+@index[spelling correction]
+@hemlock has a spelling correction facility based on the dictionary for the ITS
+spell program.  This dictionary is fairly small, having only 45,000 word or so,
+which means it fits on your disk, but it also means that many reasonably common
+words are not in the dictionary.  A correct spelling for a misspelled word will
+be found if the word is in the dictionary and is only erroneous in that it has
+a wrong character, a missing character, an extra character or a transposition
+of two characters.
+
+
+@defcom[com "Check Word Spelling", bind (M-$)]
+This command looks up the previous or current word in the dictionary and
+attempts to correct the spelling if it is misspelled.  There are four possible
+results of invoking this command:
+@begin[enumerate]
+This command displays the message "@f[Found it.]" in the echo area.  This means
+it found the word in the dictionary exactly as given.
+
+This command displays the message "@f[Found it because of @i[word].]", where
+@i[word] is some other word with the same root but a different ending.  The
+word is no less correct than if the first message is given, but an additional
+piece of useless information is supplied to make you feel like you are using a
+computer.
+
+The command prompts with "@f[Correction choice:]" in the echo area and lists
+possible correct spellings associated with numbers in a pop-up display.  Typing
+a number selects the corresponding correction, and the command replaces the
+erroneous word, preserving case as though by @hid[Query Replace].  Typing
+anything else rejects all the choices.
+
+This commands displays the message "@f[Word not found.]".  The word is not in
+the dictionary and possibly spelled correctly anyway.  Furthermore, no
+similarly spelled words were found to offer as possible corrections.  If this
+happens, it is worth trying some alternate spellings since one of them might
+be close enough to some known words that this command could display.
+@end[enumerate]
+@enddefcom
+
+@defcom[com "Correct Buffer Spelling"]
+This command scans the entire buffer looking for misspelled words and offers to
+correct them.  It creates a window into the @hid[Spell Corrections] buffer, and
+in this buffer it maintains a log of any actions taken by the user.  When this
+finds an unknown word, it prompts for a key-event.  The user has the following
+options:
+@begin[description]
+@bf[a]@\
+ Ignore this word.  If the command finds the word again, it will prompt again.
+
+@bf[i]@\
+ Insert this word in the dictionary.
+
+@bf[c]@\
+ Choose one of the corrections displayed in the @hid[Spell Corrections] window
+by specifying the correction number.  If the same misspelling is encountered
+again, then the command will make the same correction automatically, leaving a
+note in the log window.
+
+@bf[r]@\
+ Prompt for a word to use instead of the misspelled one, remembering the
+correction as with @bf[c].
+
+@binding[C-r]@\
+ Go into a recursive edit at the current position, and resume checking when the
+recursive edit is exited.
+@end[description]
+After this command completes, it deletes the log window leaving the buffer
+around for future reference.
+@enddefcom
+
+@defhvar[var "Spell Ignore Uppercase", val {nil}]
+@index[case sensitivity]
+If this variable is true, then @hid[Auto Check Word Spelling] and @hid[Correct
+Buffer Spelling] will ignore unknown words that are all uppercase.  This is
+useful for acronyms and cryptic formatter directives.
+@enddefhvar
+
+@defcom[com "Add Word to Spelling Dictionary", bind (C-x $)]
+This command adds the previous or current word to the spelling dictionary.
+@enddefcom
+
+@defcom[com "Remove Word from Spelling Dictionary"]
+This command prompts for a word to remove from the spelling dictionary.  Due to
+the dictionary representation, removal of a word in the initial spelling
+dictionary will remove all words with the same root.  The user is asked for
+confirmation before removing a root word with valid suffix flags.
+@enddefcom
+
+@defcom[com "List Incremental Spelling Insertions"]
+This command displays the incremental spelling insertions for the current
+buffer's associated spelling dictionary file.
+@enddefcom
+
+@defcom[com "Read Spelling Dictionary"]
+This command adds some words from a file to the spelling dictionary.  The
+format of the file is a list of words, one on each line.
+@enddefcom
+
+@defcom[com "Save Incremental Spelling Insertions"]
+This command appends incremental dictionary insertions to a file.  Any words
+added to the dictionary since the last time this was done will be appended to
+the file.  Except for @hid[Augment Spelling Dictionary], all the commands that
+add words to the dictionary put their insertions in this list.  The file is
+prompted for unless @hid[Set Buffer Spelling Dictionary] has been executed in
+the buffer.
+@enddefcom
+
+@defcom[com "Set Buffer Spelling Dictionary"]
+This command Prompts for the dictionary file to associate with the current
+buffer.  If the specified dictionary file has not been read for any other
+buffer, then it is read.  Incremental spelling insertions from this buffer
+can be appended to this file with @hid[Save Incremental Spelling
+Insertions].  If a buffer has an associated spelling dictionary, then
+saving the buffer's associated file also saves any incremental dictionary
+insertions.  The @w<"@f[Dictionary: ]@i[file]"> file option may also be
+used to specify the dictionary for a buffer (see section
+@ref[file-options]).
+@enddefcom
+
+@defhvar[var "Default User Spelling Dictionary", val {nil}]
+This variable holds the pathname of a dictionary to read the first time
+@hid[Spell] mode is entered in a given editing session.  When
+@hid[Set Buffer Spelling Dictionary] or the "@f[dictionary]" file option is
+used to specify a dictionary, this default one is read also.  It defaults to
+nil.
+@enddefhvar
+
+
+@subsection[Auto Spell Mode]
+@hid[Auto Spell Mode] checks the spelling of each word as it is typed.
+When an unknown word is typed the user is notified and allowed to take a
+number of actions to correct the word.
+
+@defcom[com "Auto Spell Mode"]
+This command turns @hid[Spell] mode on or off in the current buffer.
+@enddefcom
+
+@defcom[com "Auto Check Word Spelling",
+	stuff (bound to word delimiters in @hid[Spell] mode)]
+@defhvar1[var "Check Word Spelling Beep", val {t}]
+@defhvar1[var "Correct Unique Spelling Immediately", val {t}]
+This command checks the spelling of the word before the point, doing nothing if
+the word is in the dictionary.  If the word is misspelled but has a known
+correction previously supplied by the user, then this command corrects the
+spelling.  If there is no correction, then this displays a message in the echo
+area indicating the word is unknown.  An unknown word detected by this command
+may be corrected using the @hid[Correct Last Misspelled Word] command.  This
+command executes in addition to others bound to the same key; for example, if
+@hid[Fill] mode is on, any of its commands bound to the same keys as this
+command also run.
+
+If @hid[Check Word Spelling Beep] is true, then this command will beep when an
+unknown word is found.  If @hid[Correct Unique Spelling Immediately] is true,
+then this command will immediately attempt to correct any unknown word,
+automatically making the correction if there is only one possible.
+@enddefhvar
+
+@defcom[com "Undo Last Spelling Correction", bind (C-x a)]
+@defhvar1[var "Spelling Un-Correct Prompt for Insert", val {nil}]
+@hid[Undo Last Spelling Correction] undoes the last incremental spelling
+correction.  The "correction" is replaced with the old word, and the old word
+is inserted in the dictionary.  Any automatic replacement for the old word is
+eliminated.  When @hid[Spelling Un-Correct Prompt for Insert] is true, the user
+is asked to confirm the insertion into the dictionary.
+@enddefcom
+
+@defcom[com "Correct Last Misspelled Word", bind (M-:)]
+This command places the cursor after the last misspelled word detected by the
+@hid[Auto Check Word Spelling] command and then prompts for a key-event on
+which it dispatches:
+@begin[description]
+@bf[c]@\
+ Display possible corrections in a pop-up window, and prompt for the one to
+make according to the corresponding displayed digit or letter.
+
+@i[any digit]@\
+ Similar to @bf[c] @i[digit], but immediately makes the correction, dispensing
+with display of the possible corrections.  This is shorter, but only works when
+there are less than ten corrections.
+
+@bf[i]@\
+ Insert the word in the dictionary.
+
+@bf[r]@\
+ Replace the word with another.
+
+@binding[Backspace, Delete, n]@\
+ Skip this word and try again on the next most recently misspelled word.
+
+@binding[C-r]@\
+ Enter a recursive edit at the word, exiting the command when the recursive
+edit is exited.
+
+@binding[Escape]@\
+ Exit and forget about this word.
+@end[description]
+As in @hid[Correct Buffer Spelling], the @bf[c] and @bf[r] commands add the
+correction to the known corrections.
+@enddefcom
+
+
+
+@chap[Managing Large Systems]
+
+@hemlock provides three tools which help to manage large systems:
+@begin[enumerate]
+File groups, which provide several commands that operate on all the files
+in a possibly large collection, instead of merely on a single buffer.
+
+A source comparison facility with semi-automatic merging, which can be used
+to compare and merge divergent versions of a source file.
+
+A change log facility, which maintains a single file containing a record of the
+edits done on a system.
+@end[enumerate]
+
+
+@section[File Groups]
+
+@index[file groups]@index[searching, group]@index[replacing, group]
+A file group is a set of files, upon which various editing operations can be
+performed.  The files in a group are specified by a file in the following
+format:
+@begin[itemize]
+Any line which begins with one "@f[@@]" is ignored.
+
+Any line which does not begin with an "@f[@@]" is the name of a file in the
+group.
+
+A line which begins with "@f[@@@@]" specifies another file having this
+syntax, which is recursively examined to find more files in the group.
+@end[itemize]
+This syntax is used for historical reasons.  Although any number of file groups
+may be read into @hemlock, there is only one @i[active group], which is the
+file group implicitly used by all of the file group commands.  
+Page @pageref[compile-group-command] describes the @hid[Compile Group] command.
+
+@defcom[com "Select Group"]
+This command prompts for the name of a file group to make the active group.
+If the name entered is not the name of a group whose definition has been
+read, then the user is prompted for the name of a file to read the group
+definition from.  The name of the default pathname is the name of the
+group, and the type is "@f[upd]".
+@enddefcom
+
+@defcom[com "Group Query Replace"]
+This command prompts for target and replacement strings and then executes an
+interactive string replace on each file in the active group.  This reads in
+each file as if @hid[Find File] were used and processes it as if @hid[Query
+Replace] were executing.
+@enddefcom
+
+@defcom[com "Group Replace"]
+This is like @hid[Group Query Replace] except that it executes a
+non-interactive replacement, similar to @hid[Replace String].
+@enddefcom
+
+@defcom[com "Group Search"]
+This command prompts for a string and then searches for it in each file in the
+active group.  This reads in each file as if @hid[Find File] were used.  When
+it finds an occurrence, it prompts the user for a key-event indicating what
+action to take.  The following commands are defined:
+@begin[description]
+@binding[Escape, Space, y]@\
+ Exit @hid[Group Search].
+
+@binding[Delete, Backspace, n]@\
+ Continue searching for the next occurrence of the string.
+
+@binding[!]@\
+ Continue the search at the beginning of the next file, skipping the remainder
+of the current file.
+
+@binding[C-r]@\
+ Go into a recursive edit at the current location, and continue the search when
+it is exited.
+@end[description]
+@enddefcom
+
+@defhvar[var "Group Find File", val {nil}]
+The group searching and replacing commands read each file into its own buffer
+using @hid[Find File].  Since this may result in large amounts of memory being
+consumed by unwanted buffers, this variable controls whether to delete the
+buffer after processing it.  When this variable is false, the default, the
+commands delete the buffer if it did not previously exist; however, regardless
+of this variable, if the user leaves the buffer modified, the commands will not
+delete it.
+@enddefhvar
+
+@defhvar[var "Group Save File Confirm", val {t}]
+If this variable is true, the group searching and replacing commands ask for
+confirmation before saving any modified file.  The commands attempt to save
+each file processed before going on to the next one in the group.
+@enddefhvar
+
+
+@section[Source Comparison]
+@index[buffer, merging]
+@index[buffer, comparison]
+@index[source comparison]
+
+These commands can be used to find exactly how the text in two buffers differs,
+and to generate a new version that combines features of both versions.
+
+@defhvar[var "Source Compare Default Destination", val {"Differences"}]
+This is a sticky default buffer name to offer when comparison commands prompt
+for a buffer in which to insert the results.
+@enddefhvar
+
+@defcom[com "Compare Buffers"]
+This command prompts for three buffers and then does a buffer comparison.
+The first two buffers must exist, as they are the buffers to be compared.
+The last buffer, which is created if it does not exist, is the buffer to
+which output is directed.  The output buffer is selected during the
+comparison so that its progress can be monitored.  There are various variables
+that control exactly how the comparison is done.
+
+If a prefix argument is specified, then only only the lines in the the regions
+of the two buffers are compared.
+@enddefcom
+
+@defcom[com "Buffer Changes"]
+This command compares the contents of the current buffer with the disk version
+of the associated file.  It reads the file into the buffer 
+@hid[Buffer Changes File], and generates the comparison in the buffer
+@hid[Buffer Changes Result].  As with @hid[Compare Buffers], the output buffer
+is displayed in the current window.
+@enddefcom
+
+@defcom[com "Merge Buffers"]
+This command functions in a very similar fashion to @hid[Compare Buffers], the
+difference being that a version which is a combination of the two buffers being
+compared is generated in the output buffer.  This copies text that is identical
+in the two comparison buffers to the output buffer.  When it encounters a
+difference, it displays the two differing sections in the output buffer and
+prompts the user for a key-event indicating what action to take.  The following
+commands are defined:
+@begin[description]
+@bf[1]@\
+ Use the first version of the text.
+
+@bf[2]@\
+ Use the second version.
+
+@bf[b]@\
+ Insert the string @w<"@f[**** MERGE LOSSAGE ****]"> followed by both versions.
+This is useful if the differing sections are too complex, or it is unclear
+which is the correct version.  If you cannot make the decision conveniently at
+this point, you can later search for the marking string above.
+
+@binding[C-r]@\
+ Do a recursive edit and ask again when the edit is exited.
+@end[description]
+@enddefcom
+
+
+@defhvar[var "Source Compare Ignore Case", val {nil}]
+@index[case sensitivity]
+If this variable is non-@nil, @hid[Compare Buffers] and @hid[Merge Buffers]
+will do comparisons case-insensitively.
+@enddefhvar
+
+@defhvar[var "Source Compare Ignore Indentation", val {nil}] 
+If this variable is non-@nil, @hid[Compare Buffers] and @hid[Merge Buffers]
+ignore initial whitespace when comparing lines.
+@enddefhvar
+
+@defhvar[var "Source Compare Ignore Extra Newlines", val {t}]
+If this variable is true, @hid[Compare Buffers] and @hid[Merge Buffers]
+will treat all groups of newlines as if they were a single newline.
+@enddefhvar
+
+@defhvar[var "Source Compare Number of Lines", val {3}]
+This variable controls the number of lines @hid[Compare Buffers] and
+@hid[Merge Buffers] will compare when resynchronizing after a difference
+has been encountered.
+@enddefhvar
+
+
+@section[Change Logs]
+@label[log-files]
+@index[edit history]
+@index[change log]
+
+The @hemlock change log facility encourages the recording of changes to a
+system by making it easy to do so.  The change log is kept in a separate file
+so that it doesn't clutter up the source code.  The name of the log for a file
+is specified by the @f[Log] file option (see page @pageref[file-options].)
+
+@defcom[com "Log Change"]
+@defhvar1[var "Log Entry Template"]
+@hid[Log Change] makes a new entry in the change log associated with the file.
+Any changes in the current buffer are saved, and the associated log file is
+read into its own buffer.  The name of the log file is determined by merging
+the name specified in the @f[Log] option with the current buffer's file name,
+so it is not usually necessary to put the full name there.  After inserting a
+template for the log entry at the beginning of the buffer, the command enters a
+recursive edit (see page @pageref[recursive-edits]) so that the text of the
+entry may be filled in.  When the user exits the recursive edit, the log file
+is saved.
+
+The variable @hid[Log Entry Template] determines the format of the change log
+entry.  Its value is a @clisp @f[format] control string.  The format string is
+passed three string arguments: the full name of the file, the creation date for
+the file and the name of the file author.  If the creation date is not
+available, the current date is used.  If the author is not available then @nil
+is passed.  If there is an @f[@@] in the template, then it is deleted and the
+point is left at that position.
+@enddefcom
+
+
+
+@comment[@chap (Special Modes)]
+@include(special-modes)
+
+
+
+@chap[Editing Programs]
+
+
+@section[Comment Manipulation]
+@index[comment manipulation]
+@hemlock has commenting commands which can be used in almost any language.  The
+behavior of these commands is determined by several @hemlock variables which
+language modes should define appropriately.
+
+@defcom[com "Indent for Comment", bind (M-;)]
+@index[indentation, comment]@label[comment-indentation]
+This is the most basic commenting command.  If there is already a comment on
+the current line, then this moves the point to the start of the comment.  If
+there no comment, this creates an empty one.
+
+This command normally indents the comment to start at @hid[Comment Column].
+The comment indents differently in the following cases:
+@begin[enumerate]
+If the comment currently starts at the beginning of the line, or if the last
+character in the @hid[Comment Start] appears three times, then the comment
+remains unmoved.
+
+If the last character in the @hid[Comment Start] appears two times, then the
+comment is indented like a line of code.
+
+If text on the line prevents the comment occurring in the desired position,
+this places the comment at the end of the line, separated from the text by a
+space.
+@end[enumerate]
+Although the rules about replication in the comment start are oriented toward
+Lisp commenting styles, you can exploit these properties in other languages.
+
+When given a prefix argument, this command indents any existing comment on that
+many consecutive lines.  This is useful for fixing up the indentation of a
+group of comments.
+@enddefcom
+
+@defcom[com "Indent New Comment Line", bind {M-j, M-Linefeed}]
+This commend ends the current comment and starts a new comment on a blank line,
+indenting the comment the same way that @hid[Indent for Comment] does.
+When not in a comment, this command is the same as @hid[Indent New Line].
+@enddefcom
+
+@defcom[com "Up Comment Line", bind {M-p}]
+@defcom1[com "Down Comment Line", bind {M-n}]
+These commands are similar to @hid[Previous Line] or @hid[Next Line]
+followed by @hid[Indent for Comment].  Any empty comment on the current line is
+deleted before moving to the new line.
+@enddefcom
+
+@defcom[com "Kill Comment", bind (C-M-;)]
+This command kills any comment on the current line.  When given a prefix
+argument, it kills comments on that many consecutive lines.  @hid[Undo] will
+restore the unmodified text.
+@enddefcom
+
+@defcom[com "Set Comment Column", bind (C-x ;)]
+This command sets the comment column to its prefix argument.  If used without a
+prefix argument, it sets the comment column to the column the point is at.
+@enddefcom
+
+@defhvar[var "Comment Start", val {nil}]
+@defhvar1[var "Comment End", val {nil}]
+@defhvar1[var "Comment Begin", val {nil}]
+@defhvar1[var "Comment Column", val {0}]
+These variables determine the behavior of the comment commands.
+@begin[description]
+@hid[Comment Start]@\The string which indicates the start of a comment.  If
+this is @nil, then there is no defined comment syntax.
+
+@hid[Comment End]@\The string which ends a comment.  If this is @nil, then
+the comment is terminated by the end of the line.
+
+@hid[Comment Begin]@\The string inserted to begin a new comment.
+
+@hid[Comment Column]@\The column that normal comments start at.
+@end[description]
+@enddefcom
+
+
+@section[Indentation]
+@label[indentation]
+@index[indentation]
+Nearly all programming languages have conventions for indentation or leading
+whitespace at the beginning of lines.  The @hemlock indentation facility is
+integrated into the command set so that it interacts well with other features
+such as filling and commenting.
+
+@defcom[com "Indent", bind (Tab, C-i)]
+This command indents the current line.  With a prefix argument, indents that
+many lines and moves down.  Exactly what constitutes indentation depends on the
+current mode (see @hid[Indent Function]).
+@enddefcom
+
+@defcom[com "Indent New Line", bind (Linefeed)]
+This command starts a new indented line.  Deletes any whitespace before the
+point and inserts indentation on a blank line.  The effect of this is similar
+to @binding[Return] followed by @binding[Tab].  The prefix argument is passed
+to @hid[New Line], which is used to insert the blank line.
+@enddefcom
+
+@defcom[com "Indent Region", bind (C-M-\)]
+This command indents every line in the region.  It may be undone with
+@hid[Undo].
+@enddefcom
+
+@defcom[com "Back to Indentation", bind {M-m, C-M-m}]
+@index[motion, indentation]
+This command moves point to the first non-whitespace character on the current
+line.
+@enddefcom
+
+@defcom[com "Delete Indentation", bind (M-^, C-M-^)]
+@hid[Delete Indentation] joins the current line with the previous one, deleting
+excess whitespace.  This operation is the inverse of the @bf[Linefeed] command
+in most modes.  Usually this leaves one space between the two joined lines, but
+there are several exceptions.
+
+The non-whitespace immediately surrounding the deleted line break determine the
+amount of space inserted.
+@begin[enumerate]
+If the preceding character is an "@f[(]" or the following character is a
+"@f[)]", then this inserts no space.
+
+If the preceding character is a newline, then this inserts no space.  This will
+happen if the previous line was blank.
+
+If the preceding character is a sentence terminator, then this inserts two
+spaces.
+@end[enumerate]
+
+When given a prefix argument, this command joins the current and next lines,
+rather than the previous and current lines.
+@enddefcom
+
+@defcom[com "Quote Tab", bind (M-Tab)]
+This command inserts a tab character.
+@enddefcom
+
+@defcom[com "Indent Rigidly", bind (C-x Tab, C-x C-i)]
+This command changes the indentation of all the lines in the region.  Each
+line is moved to the right by the number of spaces specified by the prefix
+argument, which defaults to eight.  A negative prefix argument moves lines
+left.
+@enddefcom
+
+@defcom[com "Center Line"]
+This indents the current line so that it is centered between the left margin
+and @hvarref[Fill Column].  If a prefix argument is supplied, then it is used
+as the width instead of @hid[Fill Column].
+@enddefcom
+
+@defhvar[var "Indent Function", val {tab-to-tab-stop}]
+The value of this variable determines how indentation is done, and it is a
+function which is passed a mark as its argument.  The function should indent
+the line which the mark points to.  The function may move the mark around on
+the line.  The mark will be @f[:left-inserting].  The default simply inserts a
+tab character at the mark.
+@enddefhvar
+
+@defhvar[var "Indent with Tabs", val {indent-using-tabs}]
+@defhvar1[var "Spaces per Tab", val {8}]
+@hid[Indent with Tabs] holds a function that takes a mark and a number of
+spaces.  The function will insert a maximum number of tabs and a minimum number
+of spaces at mark to move the specified number of columns.  The default
+definition uses @hid[Spaces per Tab] to determine the size of a tab.  @i[Note,]
+@hid[Spaces per Tab] @i[is not used everywhere in @hemlock yet, so changing
+this variable could have unexpected results.]
+@enddefhvar
+
+
+@section[Language Modes]
+
+@hemlock@comment{}'s language modes are currently fairly crude, but probably
+provide better programming support than most non-extensible editors.
+
+@defcom[com "Pascal Mode"]
+@index[indentation, pascal]@index[modes, pascal]This command sets the current
+buffer's major mode to @hid[Pascal].  @hid[Pascal] mode borrows parenthesis
+matching from Scribe mode and indents lines under the previous line.
+@enddefcom
+
+
+@chap[Editing Lisp]
+@index[lisp, editing]
+@hemlock provides a large number of powerful commands for editing @llisp code.
+It is possible for a text editor to provide a much higher level of support for
+editing @llisp than ordinary programming languages, since its syntax is much
+simpler.
+
+
+@section[Lisp Mode]
+@index[lisp mode]
+@index[modes, lisp]
+@hid[Lisp] mode is a major mode used for editing @llisp code.  Although most
+@llisp specific commands are globally bound, @hid[Lisp] mode is necessary to
+enable @llisp indentation, commenting, and parenthesis-matching.  Whenever the
+user or some @hemlock mechanism turns on @hid[Lisp] mode, the mode's setup
+includes locally setting @hid[Current Package] (see section @ref[lisp-package])
+in that buffer if its value is non-existent there; the value used is
+@f["USER"].
+
+@defcom[com "Lisp Mode"]
+This command sets the major mode of the current buffer to @hid[Lisp].
+@enddefcom
+
+
+@section[Form Manipulation]
+@index[form manipulation]
+These commands manipulate @llisp forms, the printed representations of @llisp
+objects.  A form is either an expression balanced with respect to parentheses
+or an atom such as a symbol or string.
+
+@defcom[com "Forward Form", bind (C-M-f)]
+@defcom1[com "Backward Form", bind (C-M-b)]
+@index[motion, form]@hid[Forward Form] moves to the end of the current or
+next form, while @hid[Backward Form] moves to the beginning of the current
+or previous form.  A prefix argument is treated as a repeat count.
+@enddefcom
+
+@defcom[com "Forward Kill Form", bind (C-M-k)]
+@defcom1[com "Backward Kill Form", bind (C-M-Delete, C-M-Backspace)]
+@index[killing, form]@hid[Forward Kill Form] kills text from the point to
+the end of the current form.  If at the end of a list, but inside the close
+parenthesis, then kill the close parenthesis.  @hid[Backward Kill Form] is
+the same, except it goes in the other direction.  A prefix argument is
+treated as a repeat count.
+@enddefcom
+
+@defcom[com "Mark Form", bind (C-M-@@)]
+This command sets the mark at the end of the current or next form.
+@enddefcom
+
+@defcom[com "Transpose Forms", bind (C-M-t)]
+This command transposes the forms before and after the point and moves
+forward.  A prefix argument is treated as a repeat count.  If the prefix
+argument is negative, then the point is moved backward after the
+transposition is done, reversing the effect of the equivalent positive
+argument.
+@enddefcom
+
+@defcom[com "Insert ()", bind {M-(}]
+This command inserts an open and a close parenthesis, leaving the point
+inside the open parenthesis.  If a prefix argument is supplied, then the
+close parenthesis is put at the end of the form that many forms from the
+point.
+@enddefcom
+
+@defcom[com "Extract Form"]
+This command replaces the current containing list with the next form.  The
+entire affected area is pushed onto the kill ring.  If an argument is supplied,
+that many upward levels of list nesting is replaced by the next form.  This is
+similar to @hid[Extract List], but this command is more generally useful since
+it works on any kind of form; it is also more intuitive since it operates on
+the next form as many @hid[Lisp] mode commands do.
+@enddefcom
+
+
+@section[List Manipulation]
+
+@index[list manipulation]List commands are similar to form commands, but
+they only pay attention to lists, ignoring any atomic objects that may
+appear.  These commands are useful because they can skip over many symbols
+and move up and down in the list structure.
+
+@defcom[com "Forward List", bind (C-M-n)]
+@defcom1[com "Backward List", bind (C-M-p)]
+@index[motion, list]@hid[Forward List] moves the point to immediately
+after the end of the next list at the current level of list structure.  If
+there is not another list at the current level, then it moves up past
+the end of the containing list.
+@hid[Backward List] is identical, except that it moves backward and leaves
+the point at the beginning of the list.  The prefix argument is used as a
+repeat count.
+@enddefcom
+
+@defcom[com "Forward Up List", bind {C-M-@bf<)>}]
+@defcom1[com "Backward Up List", bind (C-M-@bf<(>, C-M-u)]
+@hid[Forward Up List] moves to after the end of the enclosing list.
+@hid[Backward Up List] moves to the beginning.  The prefix argument is used
+as a repeat count.
+@enddefcom
+
+@defcom[com "Down List", bind (C-M-d)]
+This command moves to just after the beginning of the next list.  The
+prefix argument is used as a repeat count.
+@enddefcom
+
+@defcom[com "Extract List", bind (C-M-x)]
+This command "extracts" the current list from the list which contains it.
+The outer list is deleted, leaving behind the current list.  The entire
+affected area is pushed on the kill ring, so that this possibly catastrophic
+operation can be undone.  The prefix argument is used as a repeat count.
+@enddefcom
+
+
+
+@section[Defun Manipulation]
+
+@index[defun manipulation]A @i[defun] is a list whose open parenthesis is
+against the left margin.  It is called this because an occurrence of the
+@f[defun] top level form usually satisfies this definition, but
+other top level forms such as a @f[defstruct] and @f[defmacro] work just as
+well.
+
+@defcom[com "End of Defun", bind (@bf<C-M-e, C-M-]>)]
+@defcom1[com "Beginning of Defun", bind (C-M-a, C-M-[)]
+@index[motion, defun]@hid[End of Defun] moves to the end of the current
+or next defun. @hid[Beginning of Defun] moves to the beginning of the
+current or previous defun.  @hid[End of Defun] will not work if the
+parentheses are not balanced.
+@enddefcom
+
+@defcom[com "Mark Defun", bind (C-M-h)]
+This command puts the point at the beginning and the mark at the end of the
+current or next defun.
+@enddefcom
+
+@section[Indentation]
+
+@index[indentation, lisp]One of the most important features provided by
+@hid[Lisp] mode is automatic indentation of @llisp code, since unindented
+@llisp is unreadable, poorly indented @llisp is ugly, and inconsistently
+indented @llisp is subtly misleading.  See section @ref[indentation] for a
+description of the general-purpose indentation commands.  These are the
+indentation rules used:
+@begin[itemize]
+If in a semicolon (@f[;]) comment, then the standard comment indentation rules
+are used.  See page @pageref[comment-indentation].
+
+If in a quoted string, copy the indentation from the previous line.
+
+If there is no enclosing list, then use no indentation.
+
+If enclosing list resembles a call to a known macro or special-form, then the
+first few arguments are given greater indentation and the first body form is
+indented two spaces.  If the first special argument is on the same line as the
+beginning of the form, then following special arguments will be indented to the
+start of the first special argument, otherwise all special arguments are
+indented four spaces.
+
+If the previous form starts on its own line, then the indentation is copied
+from that form.  This rule allows the default indentation to be overridden:
+once a form has been manually indented to the user's satisfaction, subsequent
+forms will be indented in the same way.
+
+If the enclosing list has some arguments on the same line as the form start,
+then subsequent arguments will be indented to the start of the first argument.
+
+If the enclosing list has no argument on the same line as the form start, then
+arguments will be indented one space.
+@end[itemize]
+
+
+@defcom[com "Indent Form", bind (C-M-q)]
+This command indents all the lines in the current form, leaving the point
+unmoved.  This is undo-able.
+@enddefcom
+
+@defcom[com "Defindent", bind (C-M-#)]
+This command prompts for the number of special arguments to associate with
+the symbol at the beginning of the current or containing list.
+@enddefcom
+
+@defhvar[var "Indent Defanything", val {2}]
+This is the number of special arguments implicitly assumed to be supplied in
+calls to functions whose names begin with "@f[def]".  If set to @nil, this
+feature is disabled.
+@enddefhvar
+
+@defcom[com "Move Over )", bind {M-)}]
+This command moves past the next close parenthesis and then does the equivalent
+of @hid[Indent New Line].
+@enddefcom       
+
+
+@section[Parenthesis Matching]
+
+@index[parenthesis matching]Another very important facility provided by
+@hid[Lisp] mode is @i[parenthesis matching].  Two different styles of
+parenthesis matching are supported: highlighting and pausing.
+
+@defhvar[var "Highlight Open Parens", val {t}]
+@defhvar1[var "Open Paren Highlighting Font", val {nil}]
+When @hid[Highlight Open Parens] is true, and a close paren is immediately
+before the point, then @hemlock displays the matching open paren in @hid[Open
+Paren Highlighting Font].
+
+@hid[Open Paren Highlighting Font] is the string name of the font used for
+paren highlighting.  Only the "@f[(]" character is used in this font.  If null,
+then a reasonable default is chosen.  The highlighting font is read at
+initialization time, so this variable must be set before the editor is first
+entered to have any effect.
+@enddefhvar
+
+@defcom[com "Lisp Insert )", stuff <bound to @bf[)] in @hid[Lisp] mode>]
+@defhvar1[var "Paren Pause Period", val {0.5}]
+This command inserts a close parenthesis and then attempts to display the
+matching open parenthesis by placing the cursor on top of it for
+@hid[Paren Pause Period] seconds.  If there is no matching parenthesis then
+beep.  If the matching parenthesis is off the top of the screen, then the line
+on which it appears is displayed in the echo area.  Paren pausing may be
+disabled by setting @hid[Paren Pause Period] to @nil. 
+@enddefcom
+
+The initial values shown for @hid[Highlight Open Parens] and @hid[Paren Pause
+Period] are only approximately correct.  Since paren highlighting is only
+meaningful in @llisp mode, @hid[Highlight Open Parens] is false globally, and
+has a mode-local value of @true in @llisp mode.  It it redundant to do both
+kinds of paren matching, so there is also a binding of @hid[Paren Pause Period]
+to @false in @llisp mode.
+
+Paren highlighting is only supported under @windows, so the above defaults are
+conditional on the device type.  If @hemlock is started on a terminal, the
+initialization code makes @llisp mode bindings of @false and @f[0.5] for
+@hid[Highlight Open Parens] and @hid[Paren Pause Period].  Since these
+alternate default bindings are made at initialization time, the only way to
+affect them is to use the @f[after-editor-initializations] macro.
+
+
+@section[Parsing Lisp]
+@llisp mode has a fairly complete knowledge of @llisp syntax, but since it does
+not use the reader, and must work incrementally, it can be confused by legal
+constructs.  @llisp mode totally ignores the read-table, so user-defined read
+macros have no effect on the editor.  In some cases, the values the @hid[Lisp
+Syntax] character attribute can be changed to get a similar effect.
+
+@llisp commands consistently treat semicolon (@f[;]) style comments as
+whitespace when parsing, so a @llisp command used in a comment will affect the
+next (or previous) form outside of the comment.  Since @f[#| ... |#] comments
+are not recognized, they can used to comment out code, while still allowing
+@llisp editing commands to be used.
+
+Strings are parsed similarly to symbols.  When within a string, the next form
+is after the end of the string, and the previous form is the beginning of the
+string.
+
+
+@defhvar[var "Defun Parse Goal", val {2}]
+@defhvar1[var "Maximum Lines Parsed", val {500}]
+@defhvar1[var "Minimum Lines Parsed", val {50}]
+In order to save time, @llisp mode does not parse the entire buffer every time
+a @llisp command is used.  Instead, it uses a heuristic to guess the region of
+the buffer that is likely to be interesting.  These variables control the
+heuristic.
+
+Normally, parsing begins and ends on defun boundaries (an open parenthesis at
+the beginning of a line).  @hid[Defun Parse Goal] specifies the number of
+defuns before and after the point to parse.  If this parses fewer lines than
+@hid[Minimum Lines Parsed], then parsing continues until this lower limit is
+reached.  If we cannot find enough defuns within @hid[Maximum Lines Parsed]
+lines then we stop on the farthest defun found, or at the point where we
+stopped if no defuns were found.
+
+When the heuristic fails, and does not parse enough of the buffer, then
+commands usually act as though a syntax error was detected.  If the parse
+starts in a bad place (such as in the middle of a string), then @llisp commands
+will be totally confused.  Such problems can usually be eliminated by
+increasing the values of some of these variables.
+@enddefhvar
+
+@defhvar[var "Parse Start Function", val {start-of-parse-block}]
+@defhvar1[var "Parse End Function", val {end-of-parse-block}]
+These variables determine the region of the buffer parsed.  The values are
+functions that take a mark and move it to the start or end of the parse region.
+The default values implement the heuristic described above.
+@enddefhvar
+
+
+
+@comment[@chap(Interacting With Lisp)]
+@include(lisp)
+
+
+@comment[@chap(Mail Interface)]
+@include(mail)
+
+
+
+@chap[System Interface]
+
+@hemlock provides a number of commands that access operating system resources
+such as the filesystem and print servers.  These commands offer an alternative
+to leaving the editor and using the normal operating system command language
+(such as the Unix shell), but they are implementation dependent.  Therefore,
+they might not even exist in some implementations.
+
+
+@section[File Utility Commands]
+This section describes some general file operation commands and quick directory
+commands. 
+
+See section @ref[dired] for a description @hemlock's directory editing
+mechanism, @hid[Dired] mode.
+
+@defcom[com "Copy File"]
+This command copies a file, allowing one wildcard in the filename.  It prompts
+for source and destination specifications.
+
+If these are both directories, then the copying process is recursive on the
+source, and if the destination is in the subdirectory structure of the source,
+the recursion excludes this portion of the directory tree.  Use
+@f[dir-spec-1/*] to copy only the files in a source directory without
+recursively descending into subdirectories.
+
+If the destination specification is a directory, and the source is a file, then
+it is copied into the destination with the same filename.
+
+The copying process copies files maintaining the source's write date.
+
+See the description of @hid[Dired Copy File Confirm], page
+@pageref[copy-confirm], for controlling user interaction when the destination
+exists.
+@enddefcom
+
+@defcom[com "Rename File"]
+This command renames a file, allowing one wildcard in the filename.  It prompts
+for source and destination specifications.
+
+If the destination is a directory, then the renaming process moves file(s)
+indicated by the source into the directory with their original filenames.
+
+For Unix-based implementations, if you want to rename a directory, do not
+specify the trailing slash in the source specification.
+@enddefcom
+
+@defcom[com "Delete File"]
+This command prompts for the name of a file and deletes it.
+@enddefcom
+
+@defcom[com "Directory", bind (C-x C-d)]
+@defcom1[com "Verbose Directory", bind (C-x C-D)]
+These commands prompt for a pathname (which may contain wildcards), and display
+a directory listing in a pop-up window.  If a prefix argument is supplied, then
+normally hidden files such as Unix dot-files will also be displayed.  
+@hid[Directory] uses a compact, multiple-column format; 
+@hid[Verbose Directory] displays one file on a line, with information about
+protection, size, etc.
+@enddefcom
+
+
+@section[Printing]
+
+@defcom[com "Print Region"]
+@defcom1[com "Print Buffer"]
+@defcom1[com "Print File"]
+@hid[Print Region] and @hid[Print Buffer] print the contents of the current
+region and the current buffer, respectively.  @hid[Print File] prompts for a
+the name of a file and prints that file.  Any error messages will be displayed
+in the echo area.
+@enddefcom
+
+@defhvar[var "Print Utility", val {"/usr/cs/bin/lpr"}]
+@defhvar1[var "Print Utility Switches", val {()}]
+@hid[Print Utility] is the program the print commands use to send files to the
+printer.  The program should act like @f[lpr]: if a filename is given as an
+argument, it should print that file, and if no name appears, standard input
+should be assumed.  @hid[Print Utility Switches] is a list of strings
+specifying the options to pass to the program.
+@enddefhvar
+
+
+@section[Scribe]
+@defcom[com "Scribe Buffer File",
+	stuff (bound to @bf[C-x c] in @hid[Scribe] mode)]
+@defhvar1[var "Scribe Buffer File Confirm", val {t}]
+@defcom1[com "Scribe File"]
+@hid[Scribe Buffer File] invokes @hid[Scribe Utility] on the file associated
+with the current buffer.  That process's default directory is the directory of
+the file.  The process sends its output to the @hid[Scribe Warnings] buffer.
+Before doing anything, this asks the user to confirm saving and formatting the
+file.  This prompting can be inhibited with "Scribe Buffer File Confirm".
+
+@hid[Scribe File] invokes @hid[Scribe Utility] on a file supplied by the user
+in the same manner as describe above.
+@enddefcom
+
+@defhvar[var "Scribe Utility", val {"/usr/misc/bin/scribe"}]
+@defhvar1[var "Scribe Utility Switches"]
+@hid[Scribe Utility] is the program the Scribe commands use to compile the text
+formatting.  @hid[Scribe Utility Switches] is a list of strings whose contents
+would be contiguous characters, other than space, had the user invoked this
+program on a command line outside of @hemlock.  Do not include the name of the
+file to compile in this variable; the Scribe commands supply this.
+@enddefhvar
+
+@defcom[com "Select Scribe Warnings", bind (Scribe: C-M-C)]
+This command makes the @hid[Scribe Warnings] buffer current if it exists.
+@enddefcom
+
+
+@section[Unix Filtering]
+
+@defcom[com "Unix Filter Region"]
+This command prompts for a UNIX program and then passes the current region to
+the program as standard input.  The standard output from the program is used to
+replace the region.  This command is undoable.
+@enddefcom
+
+
+
+@chap[Simple Customization]
+
+@index[customization]@hemlock can be customized and extended to a very
+large degree, but in order to do much of this a knowledge of @llisp is
+required.  These advanced aspects of customization are discussed in the
+@i[Hemlock Command Implementor's Manual], while simpler methods of
+customization are discussed here.
+
+
+@section[Keyboard Macros]
+@index[keyboard macros]
+Keyboard macros provide a facility to turn a sequence of commands into one
+command.
+
+@defcom[com "Define Keyboard Macro", bind {C-x (}]
+@defcom1[com "End Keyboard Macro", bind {C-x )}]
+@hid[Define Keyboard Macro] starts the definition of a keyboard macro.  The
+commands which are invoked up until @hid[End Keyboard Macro] is invoked
+become the definition for the keyboard macro, thus replaying the keyboard
+macro is synonymous with invoking that sequence of commands.
+@enddefcom
+
+@defcom[com "Last Keyboard Macro", bind (C-x e)]
+This command is the keyboard macro most recently defined; invoking it will
+replay the keyboard macro.  The prefix argument is used as a repeat count.
+@enddefcom
+
+@defcom[com "Define Keyboard Macro Key", bind (C-x M-(; )]
+@defhvar1[var "Define Keyboard Macro Key Confirm", val {t}]
+This command prompts for a key before going into a mode for defining keyboard
+macros.  After defining the macro @hemlock binds it to the key.  If the key is
+already bound, @hemlock asks for confirmation before clobbering the binding;
+this prompting can be inhibited by setting @hid[Define Keyboard Macro Key
+Confirm] to @nil.
+@enddefcom
+
+@defcom[com "Keyboard Macro Query", bind (C-x q)]
+This command conditionalizes the execution of a keyboard macro.  When invoked
+during the definition of a macro, it does nothing.  When the macro replays, it
+prompts the user for a key-event indicating what action to take.  The following
+commands are defined:
+@begin[description]
+@binding[Escape]@\
+ Exit all repetitions of this keyboard macro.  More than one may have been
+specified using a prefix argument.
+
+@binding[Space, y]@\
+ Proceed with the execution of the keyboard macro.
+
+@binding[Delete, Backspace, n]@\
+ Skip the remainder of the keyboard macro and go on to the next repetition, if
+any.
+
+@binding[!]@\
+ Do all remaining repetitions of the keyboard macro without prompting.
+
+@binding[.]@\
+ Complete this repetition of the macro and then exit without doing any of the
+remaining repetitions.
+
+@binding[C-r]@\
+ Do a recursive edit and then prompt again.
+@end[description]
+@enddefcom
+
+@defcom[com "Name Keyboard Macro"]
+This command prompts for the name of a command and then makes the
+definition for that command the same as @hid[Last Keyboard Macro]'s current
+definition.  The command which results is not clobbered when another
+keyboard macro is defined, so it is possible to keep several keyboard
+macros around at once.  The resulting command may also be bound to a key
+using @hid[Bind Key], in the same way any other command is.
+@enddefcom
+
+Many keyboard macros are not for customization, but rather for one-shot
+use, a typical example being performing some operation on each line of a file.
+To add "@f[del ]" to the beginning and "@f[.*]" to the end of every line in
+in a buffer, one could do this:
+@begin[programexample]
+C-x ( d e l Space C-e . * C-n C-a C-x ) C-u 9 9 9 C-x e
+@end[programexample]
+First a keyboard macro is defined which performs the desired operation on
+one line, and then the keyboard macro is invoked with a large prefix
+argument.  The keyboard macro will not actually execute that many times;
+when the end of the buffer is reached the @binding[C-n] will get an error
+and abort the execution.
+
+
+@section[Binding Keys]
+@index[key bindings]
+@label[binding-keys]
+
+@defcom[com "Bind Key"]
+This command prompts for a command, a key and a kind of binding to make,
+and then makes the specified binding.  The following kinds of bindings are
+allowed:
+@begin[description]
+@i[buffer]@\Prompts for a buffer and then makes a key binding which is
+only present when that buffer is the current buffer.
+
+@i[mode]@\Prompts for the name of a mode and then makes a key binding which
+is only in present when that mode is active in the current buffer.
+
+@i[global]@\Makes a global key binding which is in effect when there is
+no applicable mode or buffer key binding.  This is the default.
+@end[description]
+@enddefcom
+
+@defcom[com "Delete Key Binding"]
+This command prompts for a key binding the same way that @hid[Bind Key]
+does and makes the specified binding go away.
+@enddefcom
+
+@section[Hemlock Variables]
+
+@label[vars]@index[variables, hemlock]@index[hemlock variables]A number
+of commands use @hemlock variables as flags to control their behavior.  Often
+you can get a command to do what you want by setting a variable.  Generally the
+default value for a variable is chosen to be the safest value for novice users.
+
+@defcom[com "Set Variable"]
+This command prompts for the name of a @hemlock variable and an expression,
+then sets the current value of the variable to the result of the evaluation of
+the expression.
+@enddefcom
+
+
+@defcom[com "Defhvar"]
+Like @hid[Set Variable], this command prompts for the name of a @hemlock
+variable and an expression.  Like @hid[Bind Key], this command prompts for a
+place: mode, buffer or local.  The result of evaluating the expression is
+defined to be the value of the named variable in the specified place.
+
+This command is most useful for making mode or buffer local bindings of
+variables.  Redefining a variable in a mode or buffer will create a
+customization that takes effect only when in that mode or buffer.
+
+Unlike @hid[Set Variable], the variable name need not be the name of an
+existing variable: new variables may be defined.  If the variable is already
+defined in the current environment, @hemlock copies the documentation and hooks
+to the new definition.
+@enddefcom
+
+
+@section[Init Files]
+@index[init files]
+@hemlock customizations are normally put in @hemlock's initialization file,
+"@f[hemlock-init.lisp]", or when compiled "@f[hemlock-init.fasl]".  When
+starting up Lisp, use the @f[-hinit] switch to indicate a particular file.  The
+contents of the init file must be @llisp code, but there is a fairly
+straightforward correspondence between the basic customization commands and the
+equivalent @llisp code.  Rather than describe these functions in depth here, a
+brief example follows:
+@begin[programexample]
+;;; -*- Mode: Lisp; Package: Hemlock -*-
+
+;;; It is necessary to specify that the customizations go in
+;;; the hemlock package.
+(in-package 'hemlock)
+
+;;; Bind @hid[Kill Previous Word] to @binding[M-h].
+(bind-key "Kill Previous Word" '#(#\m-h))
+;;;
+;;; Bind @hid[Extract List] to @binding[C-M-?] when in @hid[Lisp] mode.
+(bind-key "Extract List" '#(#\c-m-?) :mode "Lisp")
+
+;;; Make @binding[C-w] globally unbound.
+(delete-key-binding '#(#\c-w))
+
+;;; Make string searches case-sensitive.
+(setv string-search-ignore-case nil)
+;;;
+;;; Make "Query Replace" replace strings literally.
+(setv case-replace nil)
+@end[programexample]
+For a detailed description of these functions, see the @i[Hemlock Command
+Implementor's Manual].
diff --git a/docs/rtguts.mss b/docs/rtguts.mss
new file mode 100644
index 000000000..38f08e396
--- /dev/null
+++ b/docs/rtguts.mss
@@ -0,0 +1,4150 @@
+@make [Manual]
+@device [PostScript]
+@use (database "/usr/lisp/scribe/database/")
+@libraryfile [Mathematics10]
+@libraryfile [ArpaCredit]
+@libraryfile [table]
+@libraryfile [spice] 
+@style(FontFamily=TimesRoman)
+@style(Date="March 1952")
+
+@commandstring(pusharrow = "@jsym<L>")
+@define(f, facecode f)
+
+@commandstring(InstrSection = "@tabclear@tabset[.5 in, 3.0 in]")
+@form(Instr = "@*@\@Parm[name]@\")
+@form(BInstr ="@*@\@Parm[name]@+[*]@\")
+@string(DinkyMachine = "IBM RT PC")
+@begin[TitlePage]
+@begin[TitleBox]
+@blankspace(0.25in)
+@heading[Internal Design of CMU Common Lisp 
+on the IBM RT PC]
+@begin[Center]
+@b{David B. McDonald
+Scott E. Fahlman
+Skef Wholey
+
+@value[Date]
+
+CMU-CS-87-157
+}
+@end[Center]
+@end[TitleBox]
+@center[@b<Abstract>]
+@begin[Text]
+CMU Common Lisp is an implementation of Common Lisp that currently runs on
+the IBM RT PC under Mach, a Berkeley Unix 4.3 binary compatible operating
+system.  This document describes low level
+details of the implementation.  In particular, it describes the data
+formats used for all Lisp objects, the assembler language routines
+(miscops) used to support compiled code, the function call and return
+mechanism, and other design information necessary to understand the
+underlying structure of the CMU Common Lisp implementation on the IBM RT PC
+under the Mach operating system.
+@end[Text]
+
+@begin[ResearchCredit]
+@ArpaCredit[Contract=Strategic87-90]
+@end[ResearchCredit]
+@end[TitlePage]
+
+@heading [Acknowledgments]
+
+This document is based heavily on the document @i[Revised Internal Design
+of Spice Lisp] by Skef Wholey, Scott Fahlman, and Joseph Ginder.
+
+The FASL file format was designed by Guy L. Steele Jr. and Walter van
+Roggen, and the appendix on this subject is their document with very few
+modifications.
+
+@chapter [Introduction]
+
+@section [Scope and Purpose]
+
+This document describes a new implementation of CMU Common Lisp (nee Spice
+Lisp) as it is implemented on the @value(DinkyMachine) running Mach, a
+Berkeley Unix 4.3 binary compatible operating system.  This design is
+undergoing rapid change, and for the present is not guaranteed to
+accurately describe any past, present, or future implementation of CMU
+Common Lisp.  All questions and comments on this material should be
+directed to David B. McDonald (David.McDonald@@CS.CMU.EDU).
+
+This document specifies the hand-coded assembler routines (miscops) and
+virtual memory architecture of the @value(DinkyMachine) CMU Common Lisp system.
+This is a working document, and it will change frequently as the system is
+developed and maintained.  If some detail of the system does not agree with
+what is specified here, it is to be considered a bug.
+
+@section [Notational Conventions]
+@index [Bit numbering]
+@index [Byte numbering]
+CMU Common Lisp objects are 32 bits long.  The high-order bit of each word is
+numbered 0; the low-order bit is numbered 31.  If a word is broken into smaller
+units, these are packed into the word from left to right.  For example, if we
+break a word into bytes, byte 0 would occupy bits 0-7, byte 1 would occupy
+8-15, byte 2 would occupy 16-23, and byte 3 would occupy 24-31.
+
+All CMU Common Lisp documentation uses decimal as the default radix; other
+radices will be indicated by a subscript (as in 77@-[8]) or by a clear
+statement of what radix is in use.
+
+@chapter [Data Types and Object Formats]
+
+@section [Lisp Objects]
+@index [Lisp objects]
+
+Lisp objects are 32 bits long.	They come in 32 basic types, divided into three
+classes: immediate data types, pointer types, and forwarding pointer types.
+The storage formats are as follows:
+
+@index [Immediate object format]
+@index [Pointer object format]
+@begin [verbatim, group]
+
+@b[Immediate Data Types:]
+ 0	       4 5						     31
+------------------------------------------------------------------------
+| Type Code (5) |	       Immediate Data (27)		       |
+------------------------------------------------------------------------
+
+@b[Pointer and Forwarding Types:]
+ 0	       4 5	        6 7			29	     31
+------------------------------------------------------------------------
+| Type Code (5) | Space Code (2) |    Pointer (23)	  | Unused (2) |
+------------------------------------------------------------------------
+@end [verbatim]
+
+@section [Table of Type Codes]
+@index [Type codes]
+
+@begin [verbatim, group]
+
+Code	Type		Class		Explanation
+----	----		-----		-----------
+0	+ Fixnum	Immediate	Positive fixnum, miscop code, etc.
+1	GC-Forward	Pointer 	GC forward pointer, used during GC.
+4	Bignum		Pointer 	Bignum.
+5	Ratio		Pointer 	Two words: numerator, denominator.
+6	+ Short Float	Immediate	Positive short flonum.
+7	- Short Float	Immediate	Negative short flonum.
+8	Single Float	Pointer 	Single precision float.
+9	Double Float	Pointer 	Double precision float (?).
+9	Long Float	Pointer 	Long float.
+10	Complex 	Pointer 	Two words: real, imaginary parts.
+11	String		Pointer 	Character string.
+12	Bit-Vector	Pointer 	Vector of bits
+13	Integer-Vector	Pointer 	Vector of integers
+14	General-Vector	Pointer 	Vector of Lisp objects.
+15	Array		Pointer 	Array header.
+16	Function	Pointer 	Compiled function header.
+17	Symbol		Pointer 	Symbol.
+18	List		Pointer 	Cons cell.
+20	C. S. Pointer	Pointer 	Pointer into control stack.
+21	B. S. Pointer	Pointer 	Pointer into binding stack.
+26	Interruptible	Immediate	Marks a miscop as interruptible.
+27	Character	Immediate	Character object.
+28	Values-Marker	Immediate	Multiple values marker.
+29	Catch-All	Immediate	Catch-All object.
+30	Trap		Immediate	Illegal object trap.
+31	- Fixnum	Immediate	Negative fixnum.
+@end [verbatim]
+
+@section [Table of Space Codes]
+@index [Space codes]
+
+@begin [verbatim, group]
+
+Code	Space		Explanation
+----	-----		-----------
+0	Dynamic-0	Storage normally garbage collected, space 0.
+1	Dynamic-1	Storage normally garbage collected, space 1.
+2	Static		Permanent objects, never moved or reclaimed.
+3	Read-Only	Objects never moved, reclaimed, or altered.
+@end [verbatim]
+
+@section [Immediate Data Type Descriptions]
+
+@begin [description]
+
+@index [Fixnum format]
+Fixnum@\A 28-bit two's complement integer.  The sign bit is stored redundantly
+in the top 5 bits of the word.
+
+@index [Short float format]
+Short-Float@\The sign bit is stored as part of the type code,
+allowing a 28 bit signed short float format.  The format of short floating
+point numbers is:
+@begin [verbatim]
+ 0	       3     4	    5           12 13		    31
+---------------------------------------------------------------
+| Type code (4) | Sign (1) | Exponent (8) |   Mantissa (19)   |
+---------------------------------------------------------------
+@end [verbatim]
+The floating point number is the same format as the @value(DinkyMachine)
+supports for single precision numbers, except it has been shifted right
+by four bits for the type code.  The result of any operation is therefore
+truncated.  Long floating point numbers are also available if you need
+more accuracy and better error propagation properties.
+
+@index [Character object]
+Character@\A character object holding a character code, control bits, and font
+in the following format:
+@begin [verbatim, group]
+ 0	       4 6	   7  8       15 16	 23 24	    31
+---------------------------------------------------------------
+| Type code (5) | Unused (3) | Font (8) | Bits (8) | Code (8) |
+---------------------------------------------------------------
+@end [verbatim]
+
+@index [Values-Marker]
+Values-Marker@\Used to mark the presence of multiple values on the stack.  The
+low 16 bits indicate how many values are being returned.  Note that only 65535
+values can be returned from a multiple-values producing form.  These are pushed
+onto the stack in order, and the Values-Marker is returned in register A0.
+
+@index [Catch-All object]
+Catch-All@\Object used as the catch tag for unwind-protects.  Special things
+happen when a catch frame with this as its tag is encountered during a throw.
+See section @ref[Catch] for details.
+
+@index[Trap]
+@index[Illegal object trap]
+Trap@\Illegal object trap.  This value is used in symbols to signify an
+undefined value or definition.
+
+@index[Interruptible Marker]
+Interruptible-Marker@\Object used to mark a miscop as interruptible.  This
+object is put in one of the registers and signals to the interrupt handler
+that the miscop can be interrupted safely.  Only miscops that can take a long
+time (e.g., length when passed a circular list, system call miscops that
+may wait indefinitely) are marked this way.
+@end [description]
+
+@section [Pointer-Type Objects and Spaces]
+@index [Pointer object format]
+@index [Virtual memory]
+
+Each of the pointer-type lisp objects points into a different space in virtual
+memory.  There are separate spaces for Bit-Vectors, Symbols, Lists, and so on.
+The 5-bit type-code provides the high-order virtual address bits for the
+object, followed by the 2-bit space code, followed by the 25-bit pointer
+address.  This gives a 30-bit virtual address to a 32-bit word; since the
+@value(DinkyMachine) is a byte-addressed machine, the two low-order
+bits are 0.  In effect we have carved a 30-bit space into a fixed set
+of 23-bit subspaces, not all of which are used.
+
+@index [Space codes]
+The space code divides each of the type spaces into four sub-spaces,
+as shown in the table above.  At any given time, one of the dynamic
+spaces is considered newspace, while the other is oldspace.
+During a stop and copy garbage collection, a ``flip'' can be done, turning the
+old newspace into the new oldspace.  All type-spaces are flipped at once.
+Allocation of new dynamic objects always occurs in newspace.
+
+@index [Static space]
+@index [Read-only space]
+Optionally, the user (or system functions) may allocate objects in
+static or read-only space.  Such objects are never reclaimed once they
+are allocated -- they occupy the space in which they were initially
+allocated for the lifetime of the Lisp process.  The advantage of
+static allocation is that the GC never has to move these objects,
+thereby saving a significant amount of work, especially if the objects
+are large.  Objects in read-only space are static, in that they are
+never moved or reclaimed; in addition, they cannot be altered once
+they are set up.  Pointers in read-only space may only point to
+read-only or static space, never to dynamic space.  This saves even
+more work, since read-only space does not need to be scavenged, and
+pages of read-only material do not need to be written back onto the
+disk during paging.
+
+Objects in a particular type-space will contain either pointers to
+garbage-collectible objects or words of raw non-garbage-collectible bits, but
+not both.  Similarly, a space will contain either fixed-length objects or
+variable-length objects, but not both.	A variable-length object always
+contains a 24-bit length field right-justified in the first word, with
+the positive fixnum type-code in the high-order five bits.  The remaining three
+bits can be used for sub-type information.  The length field gives the
+size of the object in 32-bit words, including the header word.	The
+garbage collector needs this information when the object is moved, and
+it is also useful for bounds checking.
+
+The format of objects in each space are as follows:
+
+@begin [description]
+@index [Symbol]
+@index [Value cell]
+@index [Definition cell]
+@index [Property list cell]
+@index [Plist cell]
+@index [Print name cell]
+@index [Pname cell]
+@index [Package cell]
+Symbol@\Each symbol is represented as a
+fixed-length block of boxed Lisp cells.  The number of cells
+per symbol is 5, in the following order:
+@begin [verbatim, group]
+0  Value cell for shallow binding.
+1  Definition cell: a function or list.
+2  Property list: a list of attribute-value pairs.
+3  Print name: a string.
+4  Package: the obarray holding this symbol.
+@end [verbatim]
+
+@index [List cell]
+List@\A fixed-length block of two boxed Lisp cells, the CAR and the CDR.
+
+@index [General-Vector format]
+@index [G-Vector format]
+@index [Vector format]
+General-Vector@\Vector of lisp objects, any length.  The first word is a fixnum
+giving the number of words allocated for the vector (up to 24 bits).  The
+highest legal index is this number minus 2.  The second word is vector entry 0,
+and additional entries are allocated contiguously in virtual memory.  General
+vectors are sometimes called G-Vectors.  (See section @ref[Vectors] for further
+details.)
+
+@index [Integer-Vector format]
+@index [I-Vector format]
+@index [Vector format]
+Integer-Vector@\Vector of integers, any length.  The 24 low bits of the first
+word give the allocated length in 32-bit words.  The low-order 28 bits of the
+second word gives the length of the vector in entries, whatever the length of
+the individual entries may be.	The high-order 4 bits of the second word
+contain access-type information that yields, among other things, the number of
+bits per entry.  Entry 0 is left-justified in the third word of the vector.
+Bits per entry will normally be powers of 2, so they will fit neatly into
+32-bit words, but if necessary some empty space may be left at the low-order
+end of each word.  Integer vectors are sometimes called I-Vectors.  (See
+section @ref[Vectors] for details.)
+
+@index [Bit-Vector format]
+@index [Vector format]
+Bit-Vector@\Vector of bits, any length.  Bit-Vectors are represented in a form
+identical to I-Vectors, but live in a different space for efficiency reasons.
+
+@index [Bignum format]
+@label [Bignums]
+Bignum@\Bignums are infinite-precision integers, represented in a format
+identical to G-Vectors.  Each bignum is stored as a series of 32-bit words,
+with the low-order word stored first.  The representation is two's complement,
+but the sign of the number is redundantly encoded in the type field of the
+fixnum in the header word.  If this fixnum is non-negative, then so is the
+bignum, if it is negative, so is the bignum.
+
+@index [Flonum format]
+@index [Flonum formats]
+@index [Floating point formats]
+Floats@\Floats are stored as two or more consecutive words of bits, in the
+following format:
+@begin [verbatim, group]
+---------------------------------------------------------------
+|  Header word, used only for GC forward pointers.	      |
+---------------------------------------------------------------
+|  Appropriate number of 32-bit words in machine format	      |
+---------------------------------------------------------------
+@end [verbatim]
+The number of words used to represent a floating point number is one plus the
+size of the floating point number being stored.  The floating point numbers
+will be represented in whatever format the @value(DinkyMachine) expects.  The
+extra header word is needed so that a valid floating point number is not
+mistaken for a gc-forward pointer during a garbage collection.
+
+@index [Ratio format]
+Ratio@\Ratios are stored as two consecutive words of Lisp objects, which should
+both be integers.
+
+@index [Complex number format]
+Complex@\Complex numbers are stored as two consecutive words of Lisp objects,
+which should both be numbers.
+
+@index [Array format]
+Array@\This is actually a header which holds the accessing and
+other information about the array.  The actual array contents are held in a
+vector (either an I-Vector or G-Vector) pointed to by an entry in
+the header.  The header is identical in format to a G-Vector.  For
+details on what the array header contains, see section @ref[Arrays].
+
+@index [String format]
+String@\A vector of bytes.  Identical in form to I-Vectors with the access type
+always 8-Bit.  However, instead of accepting and returning fixnums, string
+accesses accept and return character objects.  Only the 8-bit code field is
+actually stored, and the returned character object always has bit and font
+values of 0.
+
+@index [Function object format]
+Function @\A compiled CMU Common Lisp function consists of both lisp
+objects and raw bits for the code.  The Lisp objects are stored in
+the Function space in a format identical to that used for general
+vectors, with a 24-bit length field in the first word.  This object
+contains assorted parameters needed by the calling machinery, a
+pointer to an 8-bit I-Vector containing the compiled code, a number
+of pointers to symbols used as special variables within the function,
+and a number of lisp objects used as constants by the function.
+@end [description]
+
+@section [Forwarding Pointers]
+@index [Forwarding pointers]
+
+@begin [description]
+@index [GC-Forward pointer]
+GC-Forward@\When a data structure is transported into newspace, a GC-Forward
+pointer is left behind in the first word of the oldspace object.  This points
+to the same type-space in which it is found.  For example, a GC-Forward in
+G-Vector space points to a structure in the G-Vector newspace.	GC-Forward
+pointers are only found in oldspace.
+@end [description]
+
+@section [System and Stack Spaces]
+@index [System table space]
+@index [Stack spaces]
+@index [Control stack space]
+@index [Binding stack space]
+@index [Special binding stack space]
+
+The virtual addresses below 08000000@-[16] are not occupied by Lisp objects,
+since Lisp objects with type code 0 are positive fixnums.  Some of this space
+is used for other purposes by Lisp.  A couple of pages (4096 byte pages)
+at address 00100000@-[16] contain tables that Lisp needs to access
+frequently.  These include the allocation table, the active-catch-frame,
+information to link to C routines, etc.  Memory at location 00200000@-[16]
+contains code for various miscops.  Also, any C code loaded into a running
+Lisp process is loaded after the miscops.  The format of the allocation
+table is described in chapter @ref[Alloc-Chapter].
+
+The control stack grows upward (toward higher addresses) in memory,
+and is a framed stack.  It contains only general Lisp objects (with
+some random things encoded as fixnums).  Every object
+pointed to by an entry on this stack is kept alive.  The frame for a
+function call contains an area for the function's arguments, an area
+for local variables, a pointer to the caller's frame, and a pointer
+into the binding stack.  The frame for a Catch form contains similar
+information.  The precise stack format can be found in chapter
+@ref[Runtime].
+
+The special binding stack grows downward.  This stack is used to hold
+previous values of special variables that have been bound.  It grows and
+shrinks with the depth of the binding environment, as reflected in the
+control stack.	This stack contains symbol-value pairs, with only boxed
+Lisp objects present.
+
+All Lisp objects are allocated on word boundaries, since the
+@value(DinkyMachine) can only access words on word boundaries.
+
+@section [Vectors and Arrays]
+@label [Vectors]
+@index [Vectors]
+
+Common Lisp arrays can be represented in a few different ways in CMU Common
+Lisp -- different representations have different performance advantages.
+Simple general vectors, simple vectors of integers, and simple strings are
+basic CMU Common Lisp data types, and access to these structures is quicker
+than access to non-simple (or ``complex'') arrays.  However, all
+multi-dimensional arrays in CMU Common Lisp are complex arrays, so
+references to these are always through a header structure.
+
+@subsection [General Vectors]
+@index [General-Vector format]
+
+G-Vectors contain Lisp objects.  The format is as follows:
+
+@begin [verbatim, group]
+------------------------------------------------------------------
+|  Fixnum code (5) | Subtype (3) |   Allocated length (24)	 |
+------------------------------------------------------------------
+|  Vector entry 0   (Additional entries in subsequent words)	 |
+------------------------------------------------------------------
+@end [verbatim]
+
+The first word of the vector is
+a header indicating its length; the remaining words hold the boxed entries of
+the vector, one entry per 32-bit word.	The header word is of type fixnum.  It
+contains a 3-bit subtype field, which is used to indicate several special types
+of general vectors.  At present, the following subtype codes are defined:
+
+@index [DEFSTRUCT]
+@index [Hash tables]
+@begin [itemize, spread 0, spacing 1]
+0 Normal.  Used for assorted things.
+
+1 Named structure created by DEFSTRUCT, with type name in entry 0.
+
+2 EQ Hash Table, last rehashed in dynamic-0 space.
+
+3 EQ Hash Table, last rehashed in dynamic-1 space.
+
+4 EQ Hash Table, must be rehashed.
+@end [itemize]
+
+Following the subtype is a 24-bit field indicating how many 32-bit words are
+allocated for this vector, including the header word.  Legal indices into the
+vector range from zero to the number in the allocated length field minus 2,
+inclusive.  Normally, the index is checked on every access to the vector.
+Entry 0 is stored in the second word of the vector, and subsequent entries
+follow contiguously in virtual memory.
+
+Once a vector has been allocated, it is possible to reduce its length by using
+the Shrink-Vector miscop, but never to increase its length, even back to
+the original size, since the space freed by the reduction may have been
+reclaimed.  This reduction simply stores a new smaller value in the length
+field of the header word.
+
+It is not an error to create a vector of length 0, though it will always be an
+out-of-bounds error to access such an object.  The maximum possible length for
+a general vector is 2@+[24]-2 entries, and that can't fit in the available
+space.	The maximum length is 2@+[23]-2 entries, and that is only possible if
+no other general vectors are present in the space.
+
+@index [Bignum Format]
+Bignums are identical in format to G-Vectors although each entry is a 32-bit
+integer, and thus only assembler routines should ever access an entry.
+
+@index [Function object format]
+@index [Array format]
+Objects of type Function and Array are identical in format to
+general vectors, though they have their own spaces.
+
+@subsection [Integer Vectors]
+@index [Integer-Vector format]
+
+I-Vectors contain unboxed items of data, and their format is more complex.  The
+data items come in a variety of lengths, but are of constant length within a
+given vector.  Data going to and from an I-Vector are passed as Fixnums, right
+justified.  Internally these integers are stored in packed form, filling 32-bit
+words without any type-codes or other overhead.  The format is as follows:
+
+@begin [verbatim, group]
+----------------------------------------------------------------
+| Fixnum code (5) | Subtype (3) |  Allocated length (24)       |
+----------------------------------------------------------------
+| Access type (4) | Number of entries (28)		       |
+----------------------------------------------------------------
+| Entry 0 left justified				       |
+----------------------------------------------------------------
+@end [verbatim]
+
+The first word of an I-Vector
+contains the Fixnum type-code in the top 5 bits, a 3-bit subtype code in the
+next three bits, and the total allocated length of the vector (in 32-bit words)
+in the low-order 24 bits.  At present, the following subtype codes are defined:
+@begin [itemize, spread 0, spacing 1]
+0 Normal.  Used for assorted things.
+
+1 Code.  This is the code-vector for a function object.
+@end [itemize]
+
+The second word of the vector is the one that is looked at every
+time the vector is accessed.  The low-order 28 bits of this word
+contain the number of valid entries in the vector, regardless of how
+long each entry is.  The lowest legal index into the vector is always
+0; the highest legal index is one less than this number-of-entries
+field from the second word.  These bounds are checked on every access.
+Once a vector is allocated, it can be reduced in size but not increased.
+The Shrink-Vector miscop changes both the allocated length field
+and the number-of-entries field of an integer vector.
+
+@index [Access-type codes]
+The high-order 4 bits of the second word contain an access-type code
+which indicates how many bits are occupied by each item (and therefore
+how many items are packed into a 32-bit word).	The encoding is as follows:
+@begin [verbatim, group]
+0   1-Bit			8   Unused
+1   2-Bit			9   Unused
+2   4-Bit			10  Unused
+3   8-Bit			11  Unused
+4   16-Bit			12  Unused
+5   32-Bit			13  Unused
+6   Unused			14  Unused
+7   Unused			15  Unused
+@end [verbatim]
+
+In I-Vectors, the data items are packed into the third and subsequent
+words of the vector.  Item 0 is left justified in the third word,
+item 1 is to its right, and so on until the allocated number of items
+has been accommodated.  All of the currently-defined access types
+happen to pack neatly into 32-bit words, but if this should not be
+the case, some unused bits would remain at the right side of each
+word.  No attempt will be made to split items between words to use up
+these odd bits.  When allocated, an I-Vector is initialized to all
+0's.
+
+As with G-Vectors, it is not an error to create an I-Vector of length
+0, but it will always be an error to access such a vector.  The
+maximum possible length of an I-Vector is 2@+[28]-1 entries or
+2@+[23]-3 words, whichever is smaller.
+
+@index [String format]
+Objects of type String are identical in format to I-Vectors, though they have
+their own space.  Strings always have subtype 0 and access-type 3 (8-Bit).
+Strings differ from normal I-Vectors in that the accessing miscops accept
+and return objects of type Character rather than Fixnum.
+
+@subsection [Arrays]
+@label [Arrays]
+@index [Arrays]
+
+An array header is identical in form to a G-Vector.  Like any G-Vector, its
+first word contains a fixnum type-code, a 3-bit subtype code, and a 24-bit
+total length field (this is the length of the array header, not of the vector
+that holds the data).  At present, the subtype code is always 0.  The entries
+in the header-vector are interpreted as follows:
+
+@index [Array header format]
+@begin [description]
+0 Data Vector @\This is a pointer to the I-Vector, G-Vector, or string that
+contains the actual data of the array.	In a multi-dimensional array, the
+supplied indices are converted into a single 1-D index which is used to access
+the data vector in the usual way.
+
+1 Number of Elements @\This is a fixnum indicating the number of elements for
+which there is space in the data vector.
+
+2 Fill Pointer @\This is a fixnum indicating how many elements of the data
+vector are actually considered to be in use.  Normally this is initialized to
+the same value as the Number of Elements field, but in some array applications
+it will be given a smaller value.  Any access beyond the fill pointer is
+illegal.
+
+3 Displacement @\This fixnum value is added to the final code-vector index
+after the index arithmetic is done but before the access occurs.  Used for
+mapping a portion of one array into another.  For most arrays, this is 0.
+
+4 Range of First Index @\This is the number of index values along the first
+dimension, or one greater than the largest legal value of this index (since the
+arrays are always zero-based).	A fixnum in the range 0 to 2@+[24]-1.  If any
+of the indices has a range of 0, the array is legal but will contain no data
+and accesses to it will always be out of range.  In a 0-dimension array, this
+entry will not be present.
+
+5 - N  Ranges of Subsequent Dimensions
+@end [description]
+
+The number of dimensions of an array can be determined by looking at the length
+of the array header.  The rank will be this number minus 6.  The maximum array
+rank is 65535 - 6, or 65529.
+
+The ranges of all indices are checked on every access, during the conversion to
+a single data-vector index.  In this conversion, each index is added to the
+accumulating total, then the total is multiplied by the range of the following
+dimension, the next index is added in, and so on.  In other words, if the data
+vector is scanned linearly, the last array index is the one that varies most
+rapidly, then the index before it, and so on.
+
+@section [Symbols Known to the Assembler Routines]
+@label [Known-Objects]
+
+A large number of symbols will be pre-defined when a CMU Common Lisp system
+is fired up.  A few of these are so fundamental to the operation of the
+system that their addresses have to be known to the assembler routines.
+These symbols are listed here.  All of these symbols are in static space,
+so they will not move around.
+
+@begin [description]
+@index [NIL]
+NIL @\94000000@-[16] The value of NIL is always NIL; it is an error
+to alter it.  The plist of NIL is always NIL; it is an error to alter
+it.  NIL is unique among symbols in that it is stored in Cons cell
+space and thus you can take its CAR and CDR, yielding NIL in either
+case.  NIL has been placed in Cons cell space so that the more common
+operations on lists will yield the desired results.  This slows down
+some symbol operations but this should be insignificant compared to
+the savings in list operations.  A test for NIL for the
+@value(DinkyMachine) is:
+@begin(Example)
+	xiu	R0,P,X'9400'
+	bz	IsNIL	or bnz	IsNotNIL
+@end(Example)
+
+@index [T]
+T @\8C000000@-[16]  The value of T is always T; it is an error
+to alter it.  A similar sequence of code as for NIL above can test for T,
+if necessary.
+
+@index [%SP-Internal-Apply]
+%SP-Internal-Apply @\8C000014@-[16] The function stored in the definition cell
+of this symbol is called by an assembler routine whenever compiled code calls
+an interpreted function.
+
+@index [%SP-Internal-Error]
+%SP-Internal-Error @\8C000028@-[16] The function stored in the definition cell
+of this symbol is called whenever an error is detected during the execution of
+an assembler routine.  See section @ref[Errors] for details.
+
+@index [%SP-Software-Interrupt-Handler]
+%SP-Software-Interrupt-Handler @\8C00003C@-[16] The function stored in the
+definition cell of this symbol is called whenever a software interrupt occurs.
+See section @ref[Interrupts] for details.
+
+@index [%SP-Internal-Throw-Tag]
+%SP-Internal-Throw-Tag @\8C000050@-[16] This symbol is bound to the tag being
+thrown when a Catch-All frame is encountered on the stack.  See section
+@ref[Catch] for details.
+
+@index [%Initial-function]
+%Initial-function@\8c000064@-[16] This symbol's function cell should contain
+a function that is called when the initial core image is started.  This
+function should initialize all the data structures that Lisp needs to run.
+
+@index [%Link-table-header]
+%Link-table-header@\8c000078@-[16] This symbol's value cell contains a pointer
+to the link table information.
+
+@index [Current-allocation-space]
+Current-allocation-space@\8c00008c@-[16] This symbol's value cell contains
+an encoded form of the current space that new lisp objects are to be allocated
+in.
+
+@index [%SP-bignum/fixnum]
+%SP-bignum/fixnum@\8c0000a0@-[16] This function is invoked by the miscops
+when a division of a bignum by a fixnum results in a ratio.
+
+@index [%SP-fixnum/bignum]
+%SP-bignum/bignum@\8c0000b4@-[16] This
+function is invoked by the miscops when a division of a fixnum by a
+bignum results in a ratio.
+
+@index [%SP-bignum/bignum]
+%SP-bignum/bignum@\8c0000c8@-[16] This function is invoked by the miscops
+when a division of a bignum by a bignum results in a ratio.
+
+@index [%SP-abs-ratio]
+%SP-abs-ratio@\8c0000dc@-[16] This function is invoked by the miscops
+when the absolute value of a ratio is taken.
+
+@index [%SP-abs-complex]
+%SP-abs-complex@\8c0000f0@-[16] This function is invoked by the miscops
+when the absolute value of a complex is taken.
+
+@index [%SP-negate-ratio]
+%SP-negate-ratio@\8c000104@-[16] This function is invoked by the miscops
+when a ratio is to be negated.
+
+@index [%SP-negate-complex]
+%SP-negate-ratio@\8c000118@-[16] This function is invoked by the miscops
+when a complex is to be negated.
+
+@index[%SP-integer+ratio]
+%SP-integer+ratio@\8c00012c@-[16] This function is invoked by the miscops
+when a fixnum or bignum is added to a ratio.
+
+@index[%SP-ratio+ratio]
+%SP-ratio+ratio@\8c000140@-[16] This function is invoked by the miscops
+when a ratio is added to a ratio.
+
+@index[%SP-complex+number]
+%SP-complex+number@\8c000154@-[16] This function is invoked by the miscops
+when a complex is added to a number.
+
+@index[%SP-number+complex]
+%SP-number+complex@\8c000168@-[16] This function is invoked by the miscops
+when a number is added to a complex.
+
+@index[%SP-complex+complex]
+%SP-complex+complex@\8c00017c@-[16] This function is invoked by the miscops
+when a number is added to a complex.
+
+@index[%SP-1+ratio]
+%SP-1+ratio@\8c000190@-[16] This function is invoked by the miscops when
+1 is added to a ratio.
+
+@index[%SP-1+complex]
+%SP-1+complex@\8c000190@-[16] This function is invoked by the miscops when
+1 is added to a complex.
+
+@index[%SP-ratio-integer]
+%SP-ratio-integer@\8c0001b8@-[16] This function is invoked by the miscops
+when an integer is subtracted from a ratio.
+
+@index[%SP-ratio-ratio]
+%SP-ratio-ratio@\8c0001cc@-[16] This function is invoked by the miscops
+when an ratio is subtracted from a ratio.
+
+@index[%SP-complex-number]
+%SP-complex-number@\8c0001e0@-[16] This function is invoked by the miscops
+when a complex is subtracted from a number.
+
+@index[%SP-number-complex]
+%SP-number-complex@\8c0001f4@-[16] This function is invoked by the miscops
+when a number is subtracted from a complex.
+
+@index[%SP-complex-complex]
+%SP-complex-complex@\8c000208@-[16] This function is invoked by the miscops
+when a complex is subtracted from a complex.
+
+@index[%SP-1-complex]
+%SP-1-complex@\8c000230@-[16] This function is invoked by the miscops when
+1 is subtracted from a complex.
+
+@index[%SP-ratio*ratio]
+%SP-ratio*ratio@\8c000244@-[16] This function is invoked by the miscops to
+multiply two ratios.
+
+@index[%SP-number*complex]
+%SP-number*complex@\8c000258@-[16] This function is invoked by the miscops to
+multiply a number by a complex.
+
+@index[%SP-complex*number]
+%SP-complex*number@\8c00026c@-[16] This function is invoked by the miscops to
+multiply a complex by a number.
+
+@index[%SP-complex*complex]
+%SP-complex*complex@\8c000280@-[16] This function is invoked by the miscops
+to multiply a complex by a complex.
+
+@index[%SP-integer/ratio]
+%SP-integer/ratio@\8c000294@-[16] This function is invoked by the miscops to
+divide an integer by a ratio.
+
+@index[%SP-ratio/integer]
+%SP-ratio/integer@\8c0002a8@-[16] This function is invoked by the miscops to
+divide a ratio by an integer.
+
+@index[%SP-ratio/ratio]
+%SP-ratio/ratio@\8c0002bc@-[16] This function is invoked by the miscops to
+divide a ratio by a ratio.
+
+@index[%SP-number/complex]
+%SP-number/complex@\8c0002d0@-[16] This function is invoked by the miscops to
+divide a number by a complex.
+
+@index[%SP-complex/number]
+%SP-complex/number@\8c0002e4@-[16] This function is invoked by the miscops to
+divide a complex by a number.
+
+@index[%SP-complex/complex]
+%SP-complex/complex@\8c0002f8@-[16] This function is invoked by the miscops
+to divide a complex by a complex.
+
+@index[%SP-integer-truncate-ratio]
+%SP-integer-truncate-ratio@\8c00030c@-[16] This function is invoked by the
+miscops to truncate an integer by a ratio.
+
+@index[%SP-ratio-truncate-integer]
+%SP-ratio-truncate-integer@\8c000320@-[16] This function is invoked by the
+miscops to truncate a ratio by an integer.
+
+@index[%SP-ratio-truncate-ratio]
+%SP-ratio-truncate-ratio@\8c000334@-[16] This function is invoked by the
+miscops to truncate a ratio by a ratio.
+
+@index[%SP-number-truncate-complex]
+%SP-number-truncate-complex@\8c000348@-[16] This function is invoked by the
+miscops to truncate a number by a complex.
+
+@index[%SP-complex-truncate-number]
+%SP-complex-truncate-number@\8c00035c@-[16] This function is invoked by the
+miscops to truncate a complex by a number.
+
+@index[%SP-complex-truncate-complex]
+%SP-complex-truncate-complex@\8c000370@-[16] This function is invoked by
+the miscops to truncate a complex by a complex.
+
+@index[maybe-gc]
+Maybe-GC@\8c000384@-[16] This function may be invoked by any miscop that
+does allocation.  This function determines whether it is time to garbage
+collect or not.  If it is it performs a garbage collection.  Whether it
+invokes a garbage collection or not, it returns the single argument passed
+to it.
+
+@index[Lisp-environment-list]
+Lisp-environment-list@\8c000398@-[16] The value of this symbol is
+set to the a list of the Unix environment strings passed into the Lisp
+process.  This list by Lisp to obtain various environment information, such
+as the user's home directory, etc.
+
+@index[Call-lisp-from-c]
+Call-lisp-from-C@\8c0003ac@-[16] This function is called whenever a
+C function called by Lisp tries to call a Lisp function.
+
+@index[Lisp-command-line-list]
+Lisp-command-line-list@\8c0003c0@-[16] The value of this symbol is
+set to the list of strings passed into the Lisp process as the command
+line.
+
+@index[*Nameserverport*]
+*Nameserverport*@\8c0003d4@-[16] The value of this symbol is set to
+the C global variable name_server_port.  This allows Lisp to access the
+name server.
+
+@index[*Ignore-Floating-Point-Underflow*]
+*Ignore-Floating-Point-Underflow*@\8c0003e8@-[16] If the the value of this
+symbol is NIL then an error is signalled when floating point underflow
+occurs, otherwise the operation quietly returns zero.
+@End[description]
+
+@chapter [Runtime Environment]
+@index [Runtime Environment]
+@label [Runtime]
+
+@section [Register Allocation]
+@index [Register allocation]
+To describe the assembler support routines in chapter @ref[Instr-Chapter] and
+the complicated
+control conventions in chapter @ref[Control-Conventions] requires that we talk
+about the allocation of the 16 32-bit general purpose registers provided
+by the @value(DinkyMachine).
+@begin [description]
+@index [Program-Counter register]
+Program-Counter (PC) [R15]@\This register contains an index into the current
+code vector when a Lisp function is about to be called.  When a miscop is
+called, it contains the return address.  It may be used as a super temporary
+between miscop and function calls.
+
+@index [Active-Function-Pointer register]
+Active-Function-Pointer (AF) [R14]@\This register contains a pointer to the
+active function object.  It is used to access the symbol and constant area for
+the currently running function.
+
+@index [Active-Frame-Pointer register]
+Active-Frame-Pointer (FP) [R13]@\This register contains a pointer to the
+current active frame on the control stack.  It is used to access the arguments
+and local variables stored on the control stack.
+
+@index [Binding-Stack-Pointer register]
+Binding-Stack-Pointer (BS) [R12]@\This register contains the current binding
+stack pointer.	The binding stack is a downward growing stack and follows
+a decrement-write/increment-read discipline.
+
+@index [Local registers]
+Local registers (L0-L4) [R7-R11]@\These registers contain locals and saved
+arguments for the currently executing function.  Functions may use these
+registers, so that stack accesses can be reduced, since a stack access is
+relatively expensive compared to a register access.
+
+@index [Argument registers]
+Argument register (A0, A1, A2) [R1, R3, R5]@\These registers contain arguments
+to a function or miscop that has just been called.  On entry to a function
+or miscop, they contain the first three arguments.  The first thing a function
+does is to move the contents of these registers into the local registers.
+
+@index [Miscop argument register]
+Miscop argument register (A3) [R4]@\This register is used to pass a fourth
+argument to miscops requiring four or more arguments.  It is also used as a
+super temporary by the compiler.
+
+@index [Control-Stack-Pointer register]
+Control-Stack-Pointer (CS) [R6]@\The stack pointer for the control stack, an
+object of type Control-Stack-Pointer.  Points to the last used word in
+Control-Stack space; this upward growing stack uses a
+increment-write/read-decrement discipline.
+
+@index [Non-Lisp temporary registers]
+Non-Lisp temporary registers (NL0, NL1) [R0, R2]@\These registers are used to
+contain non-Lisp values.  They will normally be used during miscop calls, but
+may also be used in in-line code to contain temporary data.  These are the only
+two registers never examined by the garbage collector, so no pointers to Lisp
+objects should be stored here (since they won't get updated during a garbage
+collection).
+@end [description]
+
+@section [Function Object Format]
+@label [Fn-Format]
+
+Each compiled function is represented in the machine as a Function
+Object.  This is identical in form to a G-Vector of lisp objects, and
+is treated as such by the garbage collector, but it exists in a
+special function space.  (There is no particular reason for this
+distinction.  We may decide later to store these things in G-Vector
+space, if we become short on spaces or have some reason to believe
+that this would improve paging behavior.)  Usually, the function
+objects and code vectors will be kept in read-only space, but nothing
+should depend on this; some applications may create, compile, and
+destroy functions often enough to make dynamic allocation of function
+objects worthwhile.
+
+@index [Code vector]
+@index [Constants in code] The function object contains a vector of
+header information needed by the function-calling mechanism: a
+pointer to the I-Vector that holds the actual code.  Following this
+is the so-called ``symbols and constants'' area.  The first few
+entries in this area are fixnums that give the offsets into the code
+vector for various numbers of supplied arguments.  Following this
+begin the true symbols and constants used by the function.  Any
+symbol used by the code as a special variable.
+Fixnum constants can be generated faster
+with in-line code than they can be accessed from the function-object,
+so they are not stored in the constants area.
+
+The subtype of the G-Vector header indicates the type of the function:
+@begin(Itemize, spacing 1, spread 0)
+0 - A normal function (expr).
+
+1 - A special form (fexpr).
+
+2 - A defmacro macroexpansion function.
+
+3 - An anonymous expr.  The name is the name of the parent function.
+
+4 - A compiled top-level form.
+@end(Itemize)
+Only the fexpr information has any real meaning to the system.  The rest
+is there for the printer and anyone else who cares.
+
+
+After the one-word G-Vector header, the entries of the function object
+are as follows:
+
+@begin [verbatim, group]
+0  Name of the innermost enclosing named function.
+1  Pointer to the unboxed Code vector holding the instructions.
+2  A fixnum with bit fields as follows:
+   24  - 31: The minimum legal number of args (0 to 255).
+   16  - 23: The maximum number of args, not counting &rest (0 to 255).
+	The fixnum has a negative type code, if the function accepts a &rest
+	arg and a positive one otherwise.
+3  A string describing the source file from which the function was defined.
+   See below for a description of the format.
+4  A string containing a printed representation of the argument list, for
+   documentation purposes.  If the function is a defmacro macroexpansion
+   function, the argument list will be the one originally given to defmacro
+   rather than the actual arglist to the expansion function.
+5  The symbols and constants area starts here.
+   This word is entry 0 of the symbol/constant area.
+   The first few entries in this area are fixnums representing the
+   code-vector entry points for various numbers of optional arguments.
+@end [verbatim]
+
+@section [Defined-From String Format]
+@label [Defined-From-String-Format]
+@index [Defined-From String Format]
+
+The defined-from string may have any of three different formats, depending
+on which of the three compiling functions compiled it:
+@begin(Description)
+compile-file "@i[filename user-time universal-time]"@\  The @i[filename] is
+the namestring of the truename of the file the function was defined from.
+The time is the file-write-date of the file.
+
+compile "Lisp on @i[user-time], machine @i[machine universal-time]"@\
+The time is the time that the function was compiled.  @i[Machine] is the
+machine-instance of the machine on which the compilation was done.
+
+compile-from-stream "@i[stream] on @i[user-time], machine @i[machine-instance
+universal-time]"@\@i[Stream] is the printed representation of the stream
+compiled from.  The time is the time the compilation started.
+@end(Description)
+
+An example of the format of @i[user-time] is 6-May-86 1:04:44.  The
+@i[universal-time] is the same time represented as a decimal integer.
+It should be noted that in each case, the universal time is the last
+thing in the string.
+
+@section [Control-Stack Format]
+@label [Control-Stack-Format]
+@index [Control-stack format]
+
+The CMU Common Lisp control stack is a framed stack.  Call frames, which hold
+information for function calls, are intermixed with catch frames, which hold
+information used for non-local exits.  In addition, the control stack is used
+as a scratchpad for random computations.
+
+@subsection [Call Frames]
+@index [Open frame]
+@index [Active frame]
+
+At any given time, the machine contains pointers to the current top
+of the control stack and the start of the current active frame (in
+which the current function is executing).  In addition, there is a
+pointer to the current top of the special binding stack.  CMU Common Lisp
+on the Perq also has a pointer to an open frame.  An open frame is
+one which has been partially built, but which is still having
+arguments for it computed.  When all the arguments have been computed
+and saved on the frame, the function is then started.  This means
+that the call frame is completed, becomes the current active frame,
+and the function is executed.  At this time, special variables may be
+bound and the old values are saved on the binding stack.  Upon
+return, the active frame is popped away and the result is either sent
+as an argument to some previously opened frame or goes to some other
+destination.  The binding stack is popped and old values are
+restored.
+
+On the @value(DinkyMachine), open frames still exist, however, no register is
+allocated to point at the most recent one.  Instead, a count of the arguments
+to the function is kept.  In most cases, a known fixed number of arguments are
+passed to a function, and this is all that is needed to calculate the correct
+place to set the active frame pointer.
+In some cases, it is not as simple, and runtime calculations are necessary to
+set up the frame pointer.  These calculations are simple except in some very
+strange cases.
+
+The active frame contains pointers to the previously-active frame and
+to the point to which the binding stack will be popped
+on exit, among other things.  Following this is a vector of storage locations
+for the function's arguments and local variables.  Space is allocated for the
+maximum number of arguments that the function can take, regardless of how many
+are actually supplied.
+
+In an open frame, stack space is allocated up to the point where the arguments
+are stored.  Nothing is stored in the frame
+at this time.	Thus, as arguments are computed, they can simply be pushed on
+the stack.  Since the first three arguments are passed in registers, it is
+sometimes necessary to save these values when succeeding arguments are
+complicated.  When the function is finally started, the remainder of the frame
+is built (including storing all the
+registers that must be saved).	A call frame looks like this:
+@begin [verbatim, group]
+0   Saved local 0 register.
+1   Saved local 1 register.
+2   Saved local 2 register.
+3   Saved local 3 register.
+4   Saved local 4 register.
+5   Pointer to previous binding stack.
+6   Pointer to previous active frame.
+7   Pointer to previous active function.
+8   Saved PC of caller.  A fixnum.
+9   Args-and-locals area starts here.  This is entry 0.
+@end [verbatim]
+The first slot is pointed to by the Active-Frame register if this frame is
+currently active.
+
+@subsection [Catch Frames]
+@index [Catch]
+@index [Catch frames]
+
+Catch frames contain much of the same information that call frames
+do, and have a very similar format.  A catch frame holds the function
+object for the current function, a stack pointer to the current
+active frame, a pointer to the current top of the binding stack, and
+a pointer to the previous catch frame.  When a Throw occurs, an
+operation similar to returning from this catch frame (as if it
+were a call frame) is performed, and the stacks are unwound to the
+proper place for continued execution in the current function.  A
+catch frame looks like this:
+@begin [verbatim, group]
+0   Pointer to current binding stack.
+1   Pointer to current active frame.
+2   Pointer to current function object.
+3   Destination PC for a Throw.
+4   Tag caught by this catch frame.
+5   Pointer to previous catch frame.
+@end [verbatim]
+The conventions used to manipulate call and catch frames are described in
+chapter @ref[Control-Conventions].
+
+@section [Binding-Stack Format]
+@index [Binding stack format]
+
+Each entry of the binding-stack consists of two boxed (32-bit) words.  Pushed
+first is a pointer to the symbol being bound.  Pushed second is the symbol's
+old value (any boxed item) that is to be restored when the binding stack is
+popped.
+
+@chapter [Storage Management]
+@index [Storage management]
+@index [Garbage Collection]
+@label [Alloc-Chapter]
+
+@index [Free-Storage pointer]
+@index [Clean-Space pointer]
+New objects are allocated from the lowest unused addresses within the specified
+space.	Each allocation call specifies how many words are wanted, and a
+Free-Storage pointer is incremented by that amount.  There is one of these
+Free-Storage pointers for each space, and it points to the lowest free address
+in the space.  There is also a Clean-Space pointer associated with each space
+that is used during garbage collection.  These pointers are stored in a table
+which is indexed by the type and space code.  The
+address of the Free-Storage pointer for a given space is
+@begin[verbatim]
+	(+ alloc-table-base (lsh type 5) (lsh space 3)).
+@end[verbatim]
+The address of the Clean-Space pointer is
+@begin[verbatim]
+	(+ alloc-table-base (lsh type 5) (lsh space 3) 4).
+@end[verbatim]
+
+Common Lisp on the @value(DinkyMachine) uses a stop-and-copy garbage collector
+to reclaim storage.  The Collect-Garbage miscop performs a full GC.  The
+algorithm used is a degenerate form of Baker's incremental garbage collection
+scheme.  When the Collect-Garbage miscop is executed, the following
+happens:
+@begin[enumerate]
+The current newspace becomes oldspace, and the current oldspace becomes
+newspace.
+
+The newspace Free-Storage and Clean-Space pointers are initialized to point to
+the beginning of their spaces.
+
+The objects pointed at by contents of all the registers containing Lisp objects
+are transported if necessary.
+
+The control stack and binding stack are scavenged.
+
+Each static pointer space is scavenged.
+
+Each new dynamic space is scavenged.  The scavenging of the dynamic spaces
+continues until an entire pass through all of them does not result in anything
+being transported.  At this point, every live object is in newspace.
+@end[enumerate]
+A Lisp-level GC function returns the oldspace pages to Mach.
+
+@index [Transporter]
+@section [The Transporter]
+The transporter moves objects from oldspace to newspace.  It is given an
+address @i[A], which contains the object to be transported, @i[B].  If @i[B] is
+an immediate object, a pointer into static space, a pointer into read-only
+space, or a pointer into newspace, the transporter does nothing.
+
+If @i[B] is a pointer into oldspace, the object it points to must be
+moved.  It may, however, already have been moved.  Fetch the first
+word of @i[B], and call it @i[C].  If @i[C] is a GC-forwarding
+pointer, we form a new pointer with the type code of @i[B] and the
+low 27 bits of @i[C].  Write this into @i[A].
+
+If @i[C] is not a GC-forwarding pointer, we must copy the object that
+@i[B] points to.  Allocate a new object of the same size in newspace,
+and copy the contents.  Replace @i[C] with a GC-forwarding pointer to
+the new structure, and write the address of the new structure back
+into @i[A].
+
+Hash tables maintained with an EQ relation need special treatment by the
+transporter.  Whenever a G-Vector with subtype 2 or 3 is transported to
+newspace, its subtype code is changed to 4.  The Lisp-level hash-table
+functions will see that the subtype code has changed, and re-hash the entries
+before any access is made.
+
+@index [Scavenger]
+@section [The Scavenger] The scavenger looks through an area of
+pointers for pointers into oldspace, transporting the objects they
+point to into newspace.  The stacks and static spaces need to be
+scavenged once, but the new dynamic spaces need to be scavenged
+repeatedly, since new objects will be allocated while garbage
+collection is in progress.  To keep track of how much a dynamic space
+has been scavenged, a Clean-Space pointer is maintained.  The
+Clean-Space pointer points to the next word to be scavenged.  Each
+call to the scavenger scavenges the area between the Clean-Space
+pointer and the Free-Storage pointer.  The Clean-Space pointer is
+then set to the Free-Storage pointer.  When all Clean-Space pointers
+are equal to their Free-Storage pointers, GC is complete.
+
+To maintain (and create) locality of list structures, list space is
+treated specially.  When a list cell is transported, if the cdr points
+to oldspace, it is immediately transported to newspace.  This continues until
+the end of the list is encountered or a non-oldspace pointer occurs in the cdr
+position.  This linearizes lists in the cdr direction which should
+improve paging performance.
+
+@section [Purification]
+@index [Purification]
+@label [PURIFY]
+
+Garbage is created when the files that make up a CMU Common Lisp system are
+loaded.  Many functions are needed only for initialization and
+bootstrapping (e.g. the ``one-shot'' functions produced by the compiler for
+random forms between function definitions), and these can be thrown away
+once a full system is built.  Most of the functions in the system, however,
+will be used after initialization.  Rather than bend over backwards to make
+the compiler dump some functions in read-only space and others in dynamic
+space (which involves dumping their constants in the proper spaces, also),
+@i[everything] is dumped into dynamic space.  A purify miscop is provided
+that does a garbage collection and moves accessible information in dynamic
+space into read-only or static space.
+
+@chapter [Assembler Support Routines]
+@label [Instr-Chapter]
+@index [Assembler Support Routines]
+
+To support compiled Common Lisp code many hand coded assembler
+language routines (miscops) are required.  These routines accept
+arguments in the three argument registers, the special miscop
+argument register, and in a very few cases on the stack.  The current
+register assignments are:
+@begin(Itemize, spread 0, spacing 1)
+A0 contains the first argument.
+
+A1 contains the second argument.
+
+A2 contains the third argument.
+
+A3 contains the fourth argument.
+@end(itemize)
+The rest of the arguments are passed on the stack with the last
+argument at the end of the stack.  All arguments on the stack must be
+popped off the stack by the miscop.  All miscops return their
+values in register A0.  A few miscops return two or three values,
+these are all placed in the argument registers.  The main return
+value is stored in register A0, the others in A1 and A2.  The
+compiler must generate code to use the multiple values correctly,
+i.e., place the return values on the stack and put a values marker in
+register A0 if multiple-values are wanted.  Otherwise the compiler
+can use the value(s) it needs and ignore the rest.  NB: Most of the
+miscops follow this scheme, however, a few do not.  Any
+discrepancies are explained in the description of particular
+miscops.
+
+Several of the instructions described in the Perq Internal Design Document do
+not have associated miscops, rather they have been code directly in-line.
+Examples of these instructions include push, pop, bind, bind-null, many of the
+predicates, and a few other instructions.  Most of these instructions can be
+performed in 4 or fewer @value(DinkyMachine) instructions and the overhead of
+calling a miscop seemed overly expensive.  Some instructions are encoded
+in-line or as a miscop call depending on settings of compiler optimization
+switches.  If space is more important than speed, then some Perq instructions
+are compiled as calls to out of line miscops rather than generating in-line
+code.
+
+@section [Miscop Descriptions]
+@label[macro-codes]
+
+There are 10 classes of miscops: allocation, stack manipulation,
+list manipulation, symbol manipulation, array manipulation, type predicate,
+arithmetic and logical, function call and return,
+miscellaneous, and system hacking.
+
+@subsection [Allocation]
+@instrsection
+All non-immediate objects are allocated in the ``current allocation space,''
+which is dynamic space, static space, or read-only space.  The current
+allocation space is initially dynamic space, but can be changed by using the
+Set-Allocation-Space miscop below.  The current allocation space can be
+determined by using the Get-Allocation-Space miscop.  One usually wants to
+change the allocation space around some section of code; an unwind protect
+should be used to insure that the allocation space is restored to some safe
+value.
+
+@begin(Description)
+@index [Get-Allocation-Space]
+Get-Allocation-Space (@i[])@\returns 0, 2, or 3 if the current allocation
+space is dynamic, static, or read-only, respectively.
+
+@index [Set-Allocation-Space]
+Set-Allocation-Space (@i[X])@\sets the current allocation space to dynamic,
+static, or read-only if @i[X] is 0, 2, or 3 respectively.  Returns @i[X].
+
+@index [Alloc-Bit-Vector]
+Alloc-Bit-Vector (Length)@\returns a new bit-vector @i[Length] bits long,
+which is allocated in the current allocation space.  @i[Length] must be a
+positive fixnum.
+
+@index [Alloc-I-Vector]
+Alloc-I-Vector (@i[Length A])@\returns a new I-Vector @i[Length]
+bytes long, with the access code specified by @i[A].  @i[Length] and
+@i[A] must be positive fixnums.
+
+@index [Alloc-String]
+Alloc-String (@i[Length])@\ returns a new string @i[Length] characters long.
+@i[Length] must be a fixnum.
+
+@index [Alloc-Bignum]
+Alloc-Bignum (@i[Length])@\returns a new bignum @i[Length] 32-bit words long.
+@i[Length] must be a fixnum.
+
+@index [Make-Complex]
+Make-Complex (@i[Realpart Imagpart])@\returns a new complex number with the
+specified @i[Realpart] and @i[Imagpart].  @i[Realpart] and @i[Imagpart] should
+be the same type of non-complex number.
+
+@index [Make-Ratio]
+Make-Ratio (@i[Numerator Denominator])@\returns a new ratio with the
+specified @i[Numerator] and @i[Denominator].  @i[Numerator] and
+@i[Denominator] should be integers.
+
+@index [Alloc-G-Vector]
+Alloc-G-Vector (@i[Length Initial-Element])@\returns a new G-Vector
+with @i[Length] elements initialized to @i[Initial-Element].
+@i[Length] should be a fixnum.
+
+@index [Static-Alloc-G-Vector]
+Static-G-Vector (@i[Length Initial-Element])@\returns a new G-Vector in
+static allocation space with @i[Length] elements initialized to
+@i[Initial-Element].
+
+@index [Vector]
+Vector (@i[Elt@-[0] Elt@-[1] ... Elt@-[Length - 1] Length])@\returns a new
+G-Vector containing the specified @i[Length] elements.	@i[Length] should be a
+fixnum and is passed in register A0.  The rest of the arguments are passed on
+the stack.
+
+@index [Alloc-Function]
+Alloc-Function (@i[Length])@\returns a new function with @i[Length] elements.
+@i[Length] should be a fixnum.
+
+@index [Alloc-Array]
+Alloc-Array (@i[Length])@\returns a new array with @i[Length] elements.
+@i[Length] should be a fixnum.
+
+@index [Alloc-Symbol]
+Alloc-Symbol (@i[Print-Name])@\returns a new symbol with the print-name as
+@i[Print-Name].  The value is initially Trap, the definition is Trap,
+the property list and the package are initially NIL.  The symbol is
+not interned by this operation -- that is done in Lisp code.
+@i[Print-Name] should be a simple-string.
+
+@index [Cons]
+Cons (@i[Car Cdr])@\returns a new cons with the specified @i[Car] and @i[Cdr].
+
+@index [List]
+List (@i[Elt@-[0] Elt@-[1] ... Elt@-[CE - 1] Length])@\returns a new list
+containing the @i[Length] elements.  @i[Length] should be fixnum and is
+passed in register NL0.  The first three arguments are passed in A0, A1, and
+A2.  The rest of the arguments are passed on the stack.
+
+@index [List*]
+List* (@i[Elt@-[0] Elt@-[1] ... Elt@-[CE - 1] Length])@\returns a list* formed
+by the @i[Length-1] elements.  The last element is placed in the cdr of the
+last element of the new list formed.  @i[Length] should be a fixnum and is
+passed in register NL0.  The first three arguments are passed in A0, A1, and
+A2.  The rest of the arguments are passed on the stack.
+
+@index[mv-list]
+MV-List (@i[Elt@-<0> Elt@-<1> ... Elt@-<CE - 1> Length])@\returns a list
+formed from the elements, all of which are on the stack.  @i[Length] is
+passed in register A0.  This miscop is invoked when multiple values from
+a function call are formed into a list.
+@end(Description)
+
+@subsection [Stack Manipulation]
+@instrsection
+
+@begin(Description)
+@index [Push]
+Push (@i[E])@\pushes E on to the control stack.
+
+@index [Pop]
+Pop (@i[E])@\pops the top item on the control stack into @i[E].
+
+@index [NPop]
+NPop (@i[N])@\If @i[N] is positive, @i[N] items are popped off of the stack.
+If @i[N] is negative, NIL is pushed onto the stack -@i[N] times.  @i[N] must be
+a fixnum.
+
+@index [Bind-Null]
+Bind-Null (@i[E])@\pushes @i[E] (which must be a symbol) and its current value
+onto the binding stack, and sets the value of @i[E] to NIL.  Returns NIL.
+
+@index [Bind]
+Bind (Value Symbol)@\pushes @i[Symbol] (which must be a symbol) and its current
+value onto the binding stack, and sets the value cell of @i[Symbol] to
+@i[Value].  Returns @i[Symbol].
+
+@index [Unbind]
+Unbind (@i[N])@\undoes the top @i[N] bindings on the binding stack.
+@end(Description)
+
+@subsection [List Manipulation]
+@instrsection
+
+@begin(Description)
+@index [Car]
+@index [Cdr]
+@index [Caar]
+@index [Cadr]
+@index [Cdar]
+@index [Cddr]
+Car, Cdr, Caar, Cadr, Cdar, Cddr (@i[E])@\returns the car, cdr, caar, cadr,
+cdar, or cddr of @i[E] respectively.
+
+@index [Set-Cdr]
+@index [Set-Cddr]
+Set-Cdr, Set-Cddr (@i[E])@\The cdr or cddr of the contents of @i[E] is stored
+in @i[E]. The contents of @i[E] should be either a list or NIL.
+
+@index [Set-Lpop]
+Set-Lpop (@i[E])@\The car of the contents of @i[E] is returned;
+the cdr of the contents of @i[E] is stored in @i[E].  The contents of @i[E]
+should be a list or NIL.
+
+@index [Spread]
+Spread (@i[E])@\pushes the elements of the list @i[E] onto the stack in
+left-to-right order.
+
+@index [Replace-Car]
+@index [Replace-Cdr]
+Replace-Car, Replace-Cdr (@i[List Value])@\sets the car or cdr of the @i[List]
+to @i[Value] and returns @i[Value].
+
+@index [Endp]
+Endp (X)@\sets the condition code eq bit to 1 if @i[X] is NIL, or 0 if @i[X] is
+a cons cell.  Otherwise an error is signalled.
+
+@index [Assoc]
+@index [Assq]
+Assoc, Assq (@i[List Item])@\returns the first cons in the association-list
+@i[List] whose car is EQL to @i[Item].  If the = part of the EQL comparison
+bugs out (and it can if the numbers are too complicated), a Lisp-level Assoc
+function is called with the current cdr of the @i[List].  Assq returns the
+first cons in the association-list @i[List] whose car is EQ to @i[Item].
+
+@index [Member]
+@index [Memq] Member, Memq (@i[List Item])@\returns the first cons in
+the list @i[List] whose car is EQL to @i[Item].  If the = part of the
+EQL comparison bugs out, a Lisp-level Member function is called with
+the current cdr of the @i[List].  Memq returns the first cons in
+@i[List] whose car is EQ to the @i[Item].
+
+@index [GetF]
+
+GetF (@i[List Indicator Default])@\searches for the @i[Indicator] in
+the list @i[List], cddring down as the Common Lisp form GetF would.
+If @i[Indicator] is found, its associated value is returned,
+otherwise @i[Default] is returned.
+@end(Description)
+
+@subsection [Symbol Manipulation]
+@instrsection
+
+Most of the symbol manipulation miscops are compiled in-line rather than
+actual calls.
+
+@begin(Description)
+@index [Get-Value]
+Get-Value (@i[Symbol])@\returns the value of @i[Symbol] (which must be a
+symbol).  An error is signalled if @i[Symbol] is unbound.
+
+@index [Set-Value]
+Set-Value (@i[Symbol Value])@\sets the value cell of the symbol @i[Symbol] to
+@i[Value].  @i[Value] is returned.
+
+@index [Get-Definition]
+Get-Definition (@i[Symbol])@\returns the definition of the symbol
+@i[Symbol].  If @i[Symbol] is undefined, an error is signalled.
+
+@index [Set-Definition]
+Set-Definition (@i[Symbol Definition])@\sets the definition of the symbol
+@i[Symbol] to @i[Definition].  @i[Definition] is returned.
+
+@index [Get-Plist]
+Get-Plist (@i[Symbol])@\returns the property list of the symbol @i[Symbol].
+
+@index [Set-Plist] 
+Set-Plist (@i[Symbol Plist])@\sets the property
+list of the symbol @i[Symbol] to
+@i[Plist].  @i[Plist] is returned.
+
+@index [Get-Pname]
+Get-Pname (@i[Symbol])@\returns the print name of the symbol @i[Symbol].
+
+@index [Get-Package]
+Get-Package (@i[Symbol])@\returns the package cell of the symbol @i[Symbol].
+
+@index [Set-Package]
+Set-Package (@i[Symbol Package])@\sets the package cell of the symbol
+@i[Symbol] to @i[Package].  @i[Package] is returned.
+
+@index [Boundp]
+Boundp (@i[Symbol])@\sets the eq condition code bit to 1 if the symbol
+@i[Symbol] is bound; sets it to 0 otherwise.
+
+@index [FBoundp]
+FBoundp (@i[Symbol])@\sets the eq condition code bit to 1 if the symbol
+@i[Symbol] is defined; sets it to 0 otherwise.
+
+@index [Get]
+Get (@i[Symbol] @i[Indicator] @i[Default])@\searches the property list of
+@i[Symbol] for @i[Indicator] and returns the associated value.  If
+@i[Indicator] is not found, @i[Default] is returned.
+
+@index [Put]
+Put (@i[Symbol] @i[Indicator] @i[Value])@\searches the property list of
+@i[Symbol] for @i[Indicator] and replaces the associated value with @i[Value].
+If @i[Indicator] is not found, the @i[Indicator] @i[Value] pair are consed onto
+the front of the property list.
+@end(Description)
+
+@subsection [Array Manipulation]
+@instrsection
+
+Common Lisp arrays have many manifestations in CMU Common Lisp.  The CMU
+Common Lisp data types Bit-Vector, Integer-Vector, String, General-Vector,
+and Array are used to implement the collection of data types the Common
+Lisp manual calls ``arrays.''
+
+In the following miscop descriptions, ``simple-array'' means an array
+implemented in CMU Common Lisp as a Bit-Vector, I-Vector, String, or
+G-Vector.  ``Complex-array'' means an array implemented as a CMU Common Lisp
+Array object.  ``Complex-bit-vector'' means a bit-vector implemented as a
+CMU Common Lisp array; similar remarks apply for ``complex-string'' and so
+forth.
+
+@begin(Description)
+@index [Vector-Length] @index [G-Vector-Length] @index
+[Simple-String-Length] @index [Simple-Bit-Vector-Length] Vector-Length
+(@i[Vector])@\returns the length of the one-dimensional Common Lisp array
+@i[Vector].  G-Vector-Length, Simple-String-Length, and
+Simple-Bit-Vector-Length return the lengths of G-Vectors, CMU Common Lisp
+strings, and CMU Common Lisp Bit-Vectors respectively.  @i[Vector] should
+be a vector of the appropriate type.
+
+@index [Get-Vector-Subtype]
+Get-Vector-Subtype (@i[Vector])@\returns the subtype field of the vector
+@i[Vector] as an integer.  @i[Vector] should be a vector of some sort.
+
+@index [Set-Vector-Subtype]
+Set-Vector-Subtype (@i[Vector A])@\sets the subtype field of the vector
+@i[Vector] to @i[A], which must be a fixnum.
+
+@index [Get-Vector-Access-Code]
+Get-Vector-Access-Code (@i[Vector])@\returns the access code of the I-Vector
+(or Bit-Vector) @i[Vector] as a fixnum.
+
+@index [Shrink-Vector]
+Shrink-Vector (@i[Vector Length])@\sets the length field and the
+number-of-entries field of the vector @i[Vector] to @i[Length].  If the vector
+contains Lisp objects, entries beyond the new end are set to Trap.
+Returns the shortened vector.  @i[Length] should be a fixnum.  One cannot
+shrink array headers or function headers.
+
+@index [Typed-Vref]
+Typed-Vref (@i[A Vector I])@\returns the @i[I]'th element of the I-Vector
+@i[Vector] by indexing into it as if its access-code were @i[A].  @i[A] and
+@i[I] should be fixnums.
+
+@index [Typed-Vset]
+Typed-Vset (@i[A Vector I Value])@\sets the @i[I]'th element of the I-Vector
+@i[Vector] to @i[Value] indexing into @i[Vector] as if its access-code were
+@i[A].	@i[A], @i[I], and @i[Value] should be fixnums.	@i[Value] is returned.
+
+@index [Header-Length]
+Header-Length (@i[Object])@\returns the number of Lisp objects in the header of
+the function or array @i[Object].  This is used to find the number of
+dimensions of an array or the number of constants in a function.
+
+@index [Header-Ref]
+Header-Ref (@i[Object I])@\returns the @i[I]'th element of the function or
+array header @i[Object].  @i[I] must be a fixnum.
+
+@index [Header-Set]
+Header-Set (@i[Object I Value])@\sets the @i[I]'th element of the function of
+array header @i[Object] to @i[Value], and pushes @i[Value].  @i[I] must be a
+fixnum.
+@end(Description)
+
+The names of the miscops used to reference and set elements of arrays are
+based somewhat on the Common Lisp function names.  The SVref, SBit, and SChar
+miscops perform the same operation as their Common Lisp namesakes --
+referencing elements of simple-vectors, simple-bit-vectors, and simple-strings
+respectively.  Aref1 references any kind of one dimensional array.
+The names of setting functions are derived by replacing ``ref'' with ``set'',
+``char'' with ``charset'', and ``bit'' with ``bitset.''
+
+@begin(Description)
+@index [Aref1]
+@index [SVref]
+@index [SChar]
+@index [SBit]
+Aref1, SVref, SChar, SBit (@i[Array I])@\returns the @i[I]'th element of the
+one-dimensional
+array @i[Array].  SVref pushes an element of a G-Vector; SChar an element of a
+string; Sbit an element of a Bit-Vector.  @i[I] should be a fixnum.
+
+@index [Aset1]
+@index [SVset]
+@index [SCharset]
+@index [SBitset]
+Aset1, SVset, SCharset, SBitset (@i[Array I Value])@\sets the @i[I]'th element
+of the one-dimensional
+array @i[Array] to @i[Value].  SVset sets an element of a G-Vector; SCharset an
+element of a string; SBitset an element of a Bit-Vector.  @i[I] should be a
+fixnum and @i[Value] is returned.
+
+@index [CAref2]
+@index [CAref3]
+CAref2, CAref3 (@i[Array I1 I2])@\returns the element (@i[I1], @i[I2]) of the
+two-dimensional array @i[Array].  @i[I1] and @i[I2] should be
+fixnums.  CAref3 pushes the element (@i[I1], @i[I2], @i[I3]).
+
+@index [CAset2]
+@index [CAset3]
+CAset2, CAset3 (@i[Array I1 I2 Value]) @\sets the element (@i[I1], @i[I2]) of
+the two-dimensional array @i[Array] to @i[Value] and returns @i[Value].
+@i[I1] and @i[I2] should be fixnums.  CAset3 sets the element (@i[I1], @i[I2],
+@i[I3]).
+
+@index [Bit-Bash]
+Bit-Bash (@i[V1 V2 V3 Op])@\@i[V1], @i[V2], and @i[V3] should be bit-vectors
+and @i[Op] should be a fixnum.	The elements of the bit vector @i[V3] are
+filled with the result of @i[Op]'ing the corresponding elements of @i[V1] and
+@i[V2].  @i[Op] should be a Boole-style number (see the Boole miscop in
+section @ref[Boole-Section]).
+@end(Description)
+
+The rest of the miscops in this section implement special cases of sequence or
+string operations.	Where an operand is referred to as a string, it may
+actually be an 8-bit I-Vector or system area pointer.
+
+@begin(Description)
+@index [Byte-BLT]
+Byte-BLT (@i[Src-String Src-Start Dst-String Dst-Start Dst-End])@\
+moves bytes from @i[Src-String] into @i[Dst-String] between @i[Dst-Start]
+(inclusive) and @i[Dst-End] (exclusive).  @i[Dst-Start] - @i[Dst-End] bytes are
+moved.	If the substrings specified overlap, ``the right thing happens,'' i.e.
+all the characters are moved to the right place.  This miscop corresponds
+to the Common Lisp function REPLACE when the sequences are simple-strings.
+
+@index [Find-Character]
+Find-Character (@i[String Start End Character])@\
+searches @i[String] for the @i[Character] from @i[Start] to @i[End].  If the
+character is found, the corresponding index into @i[String] is returned,
+otherwise NIL is returned.  This miscop corresponds to the Common Lisp
+function FIND when the sequence is a simple-string.
+
+@index [Find-Character-With-Attribute]
+Find-Character-With-Attribute (@i[String Start End Table Mask])@\
+The codes of the characters of @i[String] from @i[Start] to @i[End] are used as
+indices into the @i[Table], which is an I-Vector of 8-bit bytes.  When the
+number picked up from the table bitwise ANDed with @i[Mask] is non-zero, the
+current index into the @i[String] is returned.
+
+@index [SXHash-Simple-String]
+SXHash-Simple-String (@i[String Length])@\Computes the hash code of the first
+@i[Length] characters of @i[String] and pushes it on the stack.  This
+corresponds to the Common Lisp function SXHASH when the object is a
+simple-string.	The @i[Length] operand can be Nil, in which case the length of
+the string is calculated in assembler.
+@end(Description)
+
+@subsection [Type Predicates]
+@instrsection
+
+Many of the miscops described in this sub-section can be coded in-line rather
+than as miscops.  In particular, all the predicates on basic types are coded
+in-line with default optimization settings in the compiler.  Currently, all of
+these predicates set the eq condition code bit to return an indication of
+whether the predicate is true or false.  This is so that the
+@value(DinkyMachine) branch instructions can be used directly without having to
+test for NIL.  However, this only works if the value of the predicate is needed
+for a branching decision.  In the cases where the value is actually needed, T
+or NIL is generated in-line according to whether the predicate is true or
+false.  At some point it might be worthwhile having two versions of these
+predicates, one which sets the eq condition code bit, and one which returns T
+or NIL.  This is especially true if space becomes an issue.
+
+@begin(Description)
+@index [Bit-Vector-P]
+Bit-Vector-P (@i[Object])@\sets the eq condition code bit to 1 if @i[Object] is
+a Common Lisp bit-vector or 0 if it is not.
+
+@index [Simple-Bit-Vector-P]
+Simple-Bit-Vector-P (@i[Object])@\sets the eq condition code bit to 1 if
+@i[Object] is a CMU Common Lisp bit-vector or 0 if it is not.
+
+@index [Simple-Integer-Vector-P]
+Simple-Integer-Vector-P (@i[Object])@\sets the eq condition code bit to 1
+if @i[Object] is a CMU Common Lisp I-Vector or 0 if it is not.
+
+@index [StringP]
+StringP (@i[Object])@\sets the eq condition code bit to 1 if @i[Object] is a
+Common Lisp string or 0 if it is not.
+
+@index [Simple-String-P]
+Simple-String-P (@i[Object])@\sets the eq condition code bit to 1 if
+@i[Object] is a CMU Common Lisp string or 0 if it is not.
+
+@index [BignumP]
+BignumP (@i[Object])@\sets the eq condition code bit to 1 if @i[Object] is a
+bignum or 0 if it is not.
+
+@index [Long-Float-P]
+Long-Float-P (@i[Object])@\sets the eq condition code bit to 1 if
+@i[Object] is a long-float or 0 if it is not.
+
+@index [ComplexP]
+ComplexP (@i[Object])@\sets the eq condition code bit to 1 if @i[Object] is a
+complex number or 0 if it is not.
+
+@index [RatioP]
+RatioP (@i[Object])@\sets the eq condition code bit to 1 if @i[Object] is a
+ratio or 0 if it is not.
+
+@index [IntegerP]
+IntegerP (@i[Object])@\sets the eq condition code bit to 1 if @i[Object] is a
+fixnum or bignum or 0 if it is not.
+
+@index [RationalP]
+RationalP (@i[Object])@\sets the eq condition code bit to 1 if @i[Object] is a
+fixnum, bignum, or ratio or 0 if it is not.
+
+@index [FloatP]
+FloatP (@i[Object])@\sets the eq condition code bit to 1 if @i[Object] is a
+short-float or long-float or 0 if it is not.
+
+@index [NumberP]
+NumberP (@i[Object])@\sets the eq condition code bit to 1 if @i[Object] is a
+number or 0 if it is not.
+
+@index [General-Vector-P]
+General-Vector-P (@i[Object])@\sets the eq condition code bit to 1 if
+@i[Object] is a Common Lisp general vector or 0 if it is not.
+
+@index [Simple-Vector-P]
+Simple-Vector-P (@i[Object])@\sets the eq condition code bit to 1 if @i[Object]
+is a CMU Common Lisp G-Vector or 0 if it is not.
+
+@index [Compiled-Function-P]
+Compiled-Function-P (@i[Object])@\sets the eq condition code bit to 1 if
+@i[Object] is a compiled function or 0 if it is not.
+
+@index [ArrayP]
+ArrayP (@i[Object])@\sets the eq condition code bit to 1 if @i[Object] is a
+Common Lisp array or 0 if it is not.
+
+@index [VectorP]
+VectorP (@i[Object])@\sets the eq condition code bit to 1 if @i[Object] is a
+Common Lisp vector of 0 if it is not.
+
+@index [Complex-Array-P]
+Complex-Array-P (@i[Object])@\sets the eq condition code bit to 1 if @i[Object]
+is a CMU Common Lisp array or 0 if it is not.
+
+@index [SymbolP]
+SymbolP (@i[Object])@\sets the eq condition code bit to 1 if @i[Object] is a
+symbol or 0 if it is not.
+
+@index [ListP]
+ListP (@i[Object])@\sets the eq condition code bit to 1 if @i[Object] is a cons
+or NIL or 0 if it is not.
+
+@index [ConsP]
+ConsP (@i[Object])@\sets the eq condition code bit to 1 if @i[Object] is a cons
+or 0 if it is not.
+
+@index [FixnumP]
+FixnumP (@i[Object])@\sets the eq condition code bit to 1 if @i[Object] is a
+fixnum or 0 if it is not.
+
+@index [Single-Float-P]
+Single-Float-P (@i[Object])@\sets the eq condition code bit to 1 if @i[Object]
+is a single-float or 0 if it is not.
+
+@index [CharacterP]
+CharacterP (@i[Object])@\sets the eq condition code bit to 1 if @i[Object] is
+a character or 0 if it is not.
+@end(Description)
+
+@subsection [Arithmetic]
+@instrsection
+
+@begin(Description)
+@index [Integer-Length]
+Integer-Length (@i[Object])@\returns the integer-length (as defined in the
+Common Lisp manual) of the integer @i[Object].
+
+@index [Logcount]
+Logcount (@i[Object])@\returns the number of 1's if @i[object] is a
+positive integer, the number of 0's if @i[object] is a negative integer,
+and signals an error otherwise.
+
+@index [Float-Short]
+Float-Short (@i[Object])@\returns a short-float corresponding to the number
+@i[Object].
+
+@index [Float-Long]
+Float-Long (@i[Number])@\returns a long float formed by coercing @i[Number] to
+a long float.  This corresponds to the Common Lisp function Float when given a
+long float as its second argument.
+
+@index [Realpart]
+Realpart (@i[Number])@\returns the realpart of the @i[Number].
+
+@index [Imagpart]
+Imagpart (@i[Number])@\returns the imagpart of the @i[Number].
+
+@index [Numerator]
+Numerator (@i[Number])@\returns the numerator of the rational @i[Number].
+
+@index [Denominator]
+Denominator (@i[Number])@\returns the denominator of the rational @i[Number].
+
+@index [Decode-Float]
+Decode-Float (@i[Number])@\performs the Common Lisp Decode-Float function,
+returning 3 values.
+
+@index [Scale-Float]
+Scale-Float (@i[Number X])@\performs the Common Lisp Scale-Float function,
+returning the result.
+
+@index[=]
+= (@i[X Y])@\sets the condition codes according to whether @i[X] is equal
+to @i[Y].  Both @i[X] and @i[Y] must be numbers, otherwise an error is
+signalled.  If a rational is compared with a flonum, the rational is
+converted to a flonum of the same type first.  If a short flonum is compared
+with a long flonum, the short flonum is converted to a long flonum.
+Flonums must be exactly equal (after conversion) for the condition codes to
+be set to equality.  This miscop also deals with complex numbers.
+
+@index [Compare]
+Compare (@i[X Y])@\sets the condition codes according to
+whether @i[X] is less than, equal to, or greater than @i[Y].  @i[X]
+and @i[Y] must be numbers.  Conversions as described in = above are done
+as necessary.  This miscop replaces the < and > instructions on the Perq,
+so that the branch on condition instructions can be used more
+effectively.  The value of < and > as defined for the Perq are
+only generated if necessary, i.e., the result is saved.  If @i[X] or @i[Y]
+is a complex number, an error is signalled.
+
+@index [Truncate]
+Truncate (@i[N X])@\performs the Common Lisp TRUNCATE operation.  There are 3
+cases depending on @i[X]:
+@Begin[Itemize]
+If @i[X] is fixnum 1, return two items: a fixnum or bignum
+representing the integer part of @i[N] (rounded toward 0), then either 0 if
+@i[N] was already an integer or the fractional part of @i[N] represented as a
+flonum or ratio with the same type as @i[N].
+
+If @i[X] and @i[N] are both fixnums or bignums and @i[X] is not 1, divide
+@i[N] by @i[X].  Return two items: the integer quotient (a fixnum or
+bignum) and the integer remainder.
+
+If either @i[X] or @i[N] is a flonum or ratio, return a fixnum or bignum
+quotient (the true quotient rounded toward 0), then a flonum or ratio
+remainder.  The type of the remainder is determined by the same type-coercion
+rules as for +.  The value of the remainder is equal to @i[N] - @i[X] *
+@i[Quotient].
+@End[Itemize]
+On the @value(DinkyMachine), the integer part is returned in register A0, and
+the remainder in A1.
+
+@index [+]
+@index [-]
+@index [*]
+@index [/]
++, -, *, / (@i[N X])@\returns  @i[N] + @i[X].  -, *, and / are similar.
+
+@index [Fixnum*Fixnum]
+@index [Fixnum/Fixnum]
+Fixnum*Fixnum, Fixnum/Fixnum (@i[N X])@\returns @i[N] * @i[X], where
+both @i[N] and @i[X] are fixnums.  Fixnum/ is similar.
+
+@index [1+]
+1+ (@i[E])@\returns @i[E] + 1.
+
+@index [1-]
+1- (@i[E])@\returns @i[E] - 1.
+
+@index [Negate]
+Negate (@i[N])@\returns -@i[N].
+
+@index [Abs]
+Abs (@i[N])@\returns |@i[N]|.
+
+@index [GCD]
+GCD (@i[N X])@\returns the greatest common divisor of the integers @i[N] and @i[X].
+
+@index [Logand]
+@index [Logior]
+@index [Logxor]
+Logand (@i[N X])@\returns the bitwise and of the integers @i[N] and @i[X].
+Logior and Logxor are analogous.
+
+@index [Lognot]
+Lognot (@i[N])@\returns the bitwise complement of @i[N].
+
+@index [Boole]
+@label [Boole-Section]
+Boole (@i[Op X Y])@\performs the Common Lisp Boole operation @i[Op] on @i[X],
+and @i[Y].  The Boole constants for CMU Common Lisp are these:
+@begin [verbatim, group]
+	boole-clr	0
+	boole-set	1
+	boole-1 	2
+	boole-2 	3
+	boole-c1	4
+	boole-c2	5
+	boole-and	6
+	boole-ior	7
+	boole-xor	8
+	boole-eqv	9
+	boole-nand	10
+	boole-nor	11
+	boole-andc1	12
+	boole-andc2	13
+	boole-orc1	14
+	boole-orc2	15
+@end [verbatim]
+
+@index [Ash]
+Ash (@i[N X])@\performs the Common Lisp ASH operation on @i[N] and @i[X].
+
+@index [Ldb]
+Ldb (@i[S P N])@\All args are integers; @i[S] and @i[P] are non-negative.
+Performs the Common Lisp LDB operation with @i[S] and @i[P] being the size and
+position of the byte specifier.
+
+@index [Mask-Field]
+Mask-Field (@i[S P N])@\performs the Common Lisp Mask-Field operation with
+@i[S] and @i[P] being the size and position of the byte specifier.
+
+@index [Dpb]
+Dpb (@i[V S P N])@\performs the Common Lisp DPB operation with @i[S] and @i[P]
+being the size and position of the byte specifier.
+
+@index [Deposit-Field]
+Deposit-Field (@i[V S P N])@\performs the Common Lisp Deposit-Field operation
+with @i[S] and @i[P] as the size and position of the byte specifier.
+
+@index [Lsh]
+Lsh (@i[N X])@\returns a fixnum that is @i[N] shifted left by @i[X] bits, with
+0's shifted in on the right.  If @i[X] is negative, @i[N] is shifted to the
+right with 0's coming in on the left.  Both @i[N] and @i[X] should be fixnums.
+
+@index [Logldb]
+Logldb (@i[S P N])@\All args are fixnums.  @i[S] and @i[P] specify a ``byte''
+or bit-field of any length within @i[N].  This is extracted and is returned
+right-justified as a fixnum.  @i[S] is the length of the field in bits; @i[P]
+is the number of bits from the right of @i[N] to the beginning of the
+specified field.  @i[P] = 0 means that the field starts at bit 0 of @i[N], and
+so on.	It is an error if the specified field is not entirely within the 26
+bits of @i[N]
+
+@index [Logdpb]
+Logdpb (@i[V S P N])@\All args are fixnums.  Returns a number equal to @i[N],
+but with the field specified by @i[P] and @i[S] replaced by the @i[S] low-order
+bits of @i[V].	It is an error if the field does not fit into the 26 bits of
+@i[N].
+
+@index[Sin]@index[Cos]@index[Tan]@index[Atan]
+Sin(@i[X]), Cos(@i[X]), Tan(@i[X]), and Atan(@i[X])@\accept a single number
+@i[X] as argument and return the sine, cosine, tangent, and arctangent of
+the number respectively.  These miscops take advantage of the hardware
+support provided on the IBM RT PC if it is available, otherwise they escape
+to Lisp code to calculate the appropriate result.
+
+@index[Log]
+Log(@i[X])@\returns the natural log of the number @i[X].  This miscop uses
+the hardware operation if it is available, otherwise it escapes to Lisp
+code to calculate the result.
+
+@index[Exp]
+Exp(@i[X])@\returns e raised to the power @i[X].  This miscop uses the
+hardware operation if it is available, otherwise it escapes to Lisp code to
+calculate the result.
+
+@index[Sqrt]
+Sqrt(@i[X])@\returns the square root of @i[X].  This miscop uses the
+hardware operation if it is available, otherwise it escapes to Lisp code to
+calculate the result.
+@end(Description)
+
+@subsection [Branching]
+All branching is done with @value(DinkyMachine) branch instructions.
+Instructions are generated to set the condition code bits appropriately, and
+a branch which tests the appropriate condition code bit is generated.
+
+@subsection [Function Call and Return]
+@instrsection
+
+@begin(Description)
+@index [Call]
+Call()@\A call frame for a function is opened.	This is explained in
+more detail in the next chapter.
+
+@index [Call-0]
+Call-0 (@i[F])@\@i[F] must be an executable function, but is a
+function of 0 arguments.  Thus, there is no need to collect arguments.	The
+call frame is opened and activated in a single miscop.
+
+@index [Call-Multiple]
+Call-Multiple ()@\Just like a Call miscop, but it marks the frame
+to indicate that multiple values will be accepted.  See
+section @ref[Multi].
+
+@index[Set-Up-Apply-Args]
+Set-Up-Apply-Args ()@\is called to handle the last argument of a
+function called by apply.  All the other arguments will have been
+properly set up by this time.  Set-up-apply-args places the values of
+the list passed as the last argument to apply in their proper
+locations, whether they belong in argument registers or on the stack.
+It updates the NArgs register with the actual count of the arguments
+being passed to the function.  When Set-up-apply-args returns, all the
+arguments to the function being applied are in their correct
+locations, and the function can be invoked normally.
+
+@index[Start-Call-Interpreter]
+Start-Call-Interpreter (@i[NArgs])@\is called from the interpreter to
+start a function call.  It accepts the number of arguments that are
+pushed on the stack in register A0.  Just below the arguments is the
+function to call; just below the function is the area to store the
+preserved registers.  This miscop sets up the argument registers
+correctly, moves any other arguments down on the stack to their
+proper place, and invokes the function.
+
+@index[Invoke1]
+Invoke1 (@i[Function] @i[Argument])@\is similar to Start-Call-Interpreter,
+but is simpler, since the @i[Function] is being called with only a
+single @i[Argument].
+
+@index[Invoke1*]
+Invoke1* (@i[Function] @i[Argument])@\is similar to Invoke1, but the
+@i[Function] being called is called for one value, rather than multiple ones.
+
+@index [Start-call-mc]
+Start-call-mc ()@\is called when the compiler generates code for the
+form multiple-value-call.  Register A0 contains the function to be
+called, A1 contains a 0 if the call if for a single value, and 1
+otherwise, NArgs contains the number of arguments that are stored on
+the stack.  The argument registers are set up correctly, and the
+excess values moved down on the stack if necessary.  Finally, the
+function is actually invoked.
+
+@index [Push-Last]
+Push-Last ()@\closes the currently open call frame, and initiates a function
+call.
+
+@index [Return]
+Return (@i[X])@\Return from the current function call.	After the current
+frame is popped off the stack, @i[X] is returned in register A0 as the result
+Being returned. See section @ref[Return] for more details.
+
+@index [Return-From]
+Return-From (@i[X] @i[F])@\is similar to Return, except it accepts the frame
+to return from as an additional argument.
+
+@index [Return-1-Value-Any-Bind]
+Return-1-Value-Any-Bind (@i[X])@\is similar to return, except only
+one value is returned.  Any number of bindings are undone during the
+return operation.
+
+@index [Return-Mult-Value-0-Bind]
+Return-Mult-Value-0-Bind (@i[X])@\is similar to return, except multiple values
+may be returned, but the binding stack does not have to be popped.
+
+@index [Link-Address-Fixup]
+Link-Address-Fixup (@i[Symbol NArgs Code-Vector Offset])@\finds the
+correct link table entry for @i[Symbol] with @i[NArgs] (@i[NArgs]
+specifies the fixed number of arguments and a flag if more may be
+passed).  It smashes the @i[Code-Vector] at @i[Offset] to generate
+code to point at the absolute address of the link table entry.
+
+@index [Miscop-Fixup]
+Miscop-Fixup (@i[Code-Vector Offset Index])@\smashes @i[Code-Vector] at
+@i[Offset] with the correct value for the miscop specified by @i[Index] in a
+transfer vector of all the miscops.
+
+@index [Make-Compiled-Closure]
+Make-Compiled-Closure (@i[env fcn offset])@\returns a new function object
+that is a copy of the function object @i[fcn] which has the @i[env]
+information stored at @i[offset].  Compiled lexical closures are now
+represented as real function objects rather than as lists.  This miscop is
+necessary to support this change.
+
+@index [Reset-link-table]
+Reset-link-table (@i[function])@\resets all the link table entries for
+@i[function] to the default action.  This is necessary because Portable
+Commonloops updates generic function objects by copying new information
+into the function object.  The link table must be updated to reflect this
+or the wrong function will be called.
+
+@index[Interrupt-Handler]
+@begin[Multiple]
+Interrupt-Handler (@i[Signal Code Signal-Context])@\gets the first
+indication that a Unix signal has occurred.  This miscop does not follow
+the normal Lisp calling conventions at all.  Instead it follows the
+standard IBM RT PC calling conventions for C or other algorithmic
+languages.  On entry the registers are as follows:
+@begin(Description)
+R0@\Pointer to C data area for Interrupt-Handler.  Currently this data area
+only holds a pointer to the entry point for Interrupt-Handler and nothing
+else.
+
+R1@\Pointer to a C stack that contains information about the signal.
+
+R2@\Contains the @i[Signal] number that caused the interrupt to happen.
+
+R3@\Contains the @i[Code] that further specifies what caused the interrupt
+(if necessary).
+
+R4@\Contains a pointer to the @i[signal-context] which contains
+information about where the interrupt occurred, the saved registers, etc.
+
+R5-R14@\Contain unknown values.
+
+R15@\is the return PC which will return from the interrupt handler and
+restart the computation.
+@end(Description)
+Interrupt-Handler determines whether it is safe to take the interrupt now,
+i.e., it is executing in Lisp code, C code,  or an interruptible miscop.  An
+interruptible miscop is one that has been specially written to make sure
+that it is safe to interrupt it at any point and is possible that it will
+never return of its own accord (e.g., length which could be passed a
+circular list, some of the system call miscops, etc.).  If it is safe to
+take the interrupt, the signal-context is modified so that control will
+transfer to the miscop interrupt-routine when the interrupt-handler returns
+normally (i.e., after the kernel has done the necessary bookkeeping).  If
+it is unsafe to take the interrupt (i.e., it is executing in an
+non-interruptible miscop), then the return PC of the miscop is modified to
+be interrupt-routine and interrupt-handler returns to the kernel.  In
+either case interrupts are disabled and information is stored in a global
+Lisp data area, so that the interrupt-routine miscop can retrieve the
+important information about the interrupt.
+@end[Multiple]
+
+Interrupt-Routine ()@\gets control when it is safe to take an interrupt.
+It saves the current state of the computation on the appropriate stack (on
+the C stack if it was executing in C or on the Lisp stack if in Lisp)
+including all the registers, some control information specifying whether
+the computation was in C code, Lisp code, whether it should form a PC in
+register R15.  When a PC has to be formed in R15, R14 will contain a pointer
+to the active function and R15 will contain an index into the code vector
+associated with the active function.  Reforming the PC is necessary so
+it is possible to restart a computation even after a garbage collection
+may have moved the function.  Once this information is stored,
+interrupt-routine invokes the Lisp function %sp-software-interrupt-routine
+which moves the processing of the interrupt to Lisp code.
+
+@index [Break-Return]
+Break-Return (@i[])@\returns from a function called by the
+interrupt-routine miscop.  The only function that should ever do this is
+%sp-software-interrupt-routine.  This miscop expects the stack to be in a
+format that is generated during an interrupt and should not be used for
+anything else.
+
+@index [Catch]
+Catch (@i[Tag PC])@\builds a catch frame.  @i[Tag] is the tag caught by this
+catch frame, @i[PC] is a saved-format PC (i.e., an index into the current code
+vector).  See section @ref[Catch] for details.
+
+@index [Catch-Multiple]
+Catch-Multiple (@i[Tag PC])@\builds a multiple-value catch frame.  @i[Tag] is
+the tag caught by this catch frame, and @i[PC] is a saved-format PC.  See
+section @ref[Catch] for details.
+
+@index [Catch-All]
+Catch-All (@i[PC])@\builds a catch frame whose tag is the special Catch-All
+object.  @i[PC] is the saved-format PC, which is the address to branch to if
+this frame is thrown through.  See section @ref[Catch] for details.
+
+@index [Throw]
+Throw (@i[X Tag])@\@i[Tag] is the throw-tag, normally a symbol.  @i[X] is the
+value to be returned.  See section @ref[Catch] for a description of how this
+miscop works.
+
+@index[Rest-Entry-0]@index[Rest-Entry-1]@index[Rest-Entry-2]@index[Rest-Entry]
+Rest-Entry-0, Rest-Entry-1, Rest-Entry-2, Rest-Entry@\are miscops
+that do the processing for a function at its &rest entry point.
+Rest-Entry-@i[i] are miscops that are invoked by functions that have
+0, 1, or 2 arguments before the &rest argument.  Rest-entry is
+invoked for all other cases, and is passed an additional argument in
+A3 which is the number of non-&rest arguments.  These miscops form
+the &rest arg list and set up all the registers to have the
+appropriate values.  In particular, the non-&rest arguments are copied
+into preserved registers, and the &rest arg list is built and stored
+in the appropriate preserved register or on the stack as appropriate.
+
+@index[Call-Foreign]
+Call-Foreign (@i[C-Function Arguments NArgs])@\establishes the C
+environment so that C code can be called correctly.  @i[C-Function] is a
+pointer to the data area for a C function, the first word of which is a
+pointer to the entry point of the C function.  @i[Arguments] is a block of
+storage that contains the @i[NArgs] arguments to be passed to the C
+function.  The first four of these arguments are passed in registers R2
+through R5 respectively, the rest are moved onto the C stack in the proper
+location.  When the C function returns, Call-Foreign restores the Lisp
+environment and returns as its value the integer in R2.
+
+@index[Call-Lisp]
+Call-Lisp (@i[Arg@-<1> ... Arg@-<2>])@\is a Lisp miscop that gets control
+when a C function needs to call a Lisp function.  Lisp provides a mechanism
+for setting up an object that looks like a C procedure pointer.  The code
+pointer in this object always points at Call-Lisp.  Additional data in this
+procedure pointer is the Lisp function to call and the number of arguments
+that it should be called with.  Call-Lisp restores the Lisp environment,
+saves the state of the C computation, moves the C arguments into the
+correct places for a call to a Lisp function and then invokes the special
+Lisp function call-lisp-from-c.  This Lisp function actually invokes the
+correct Lisp function.  Call-Lisp never regains control.
+
+@index[Return-To-C]
+Return-To-C (@i[C-Stack-Pointer Value])@\is used in the
+function call-lisp-from-c to return control to C from a Lisp function
+called by C.  @i[C-Stack-Pointer] is the C stack pointer when the call-lisp
+miscop got control.  The C stack pointer argument is used to restore the C
+environment to what it was at the time the call to Lisp was made.
+@i[Value] is the value returned from Lisp and is passed back to C in
+register R2.  Currently, it is not possible to return other than a single
+32 bit quantity.
+
+@index[Reset-C-Stack]
+Reset-C-Stack ()@\is invoked when a Lisp function called by C throws out
+past where it should return to C.  Reset-C-Stack restores the C stack to
+what it was before the original call to C happened.  This is so that in the
+future, the C stack will not contain any garbage that should not be there.
+
+@index[Set-C-Procedure-Pointer]
+Set-C-Procedure-Pointer (@i[Sap] @i[I] @I[Proc])@\sets the @i[I/2]'th
+element of @i[sap] to be the data part of the statically allocated g-vector
+@i[Proc].  This is used to set up a C procedure argument in the argument
+block that is passed to call-foreign.
+
+@end(Description)
+
+@subsection [Miscellaneous]
+@instrsection
+
+@begin(Description)
+@index [Eq]
+Eq (@i[X Y])@\sets the eq condition code bit to 1 if @i[X] and @i[Y] are the
+same object, 0 otherwise.
+
+@index [Eql]
+Eql (@i[X Y])@\sets the eq condition code bit to 1 if @i[X] and @i[Y] are the
+same object or if
+@i[X] and @i[Y] are numbers of the same type with the same value, 0 otherwise.
+
+@index [Make-Predicate]
+Make-Predicate (@i[X])@\returns NIL if @i[X] is NIL or T if it is not.
+
+@index [Not-Predicate]
+Not-Predicate (@i[X])@\returns T if @i[X] is NIL or NIL if it is not.
+
+@index [Values-To-N]
+Values-To-N (@i[V])@\@i[V] must be a Values-Marker.  Returns the number
+of values indicated in the low 24 bits of @i[V] as a fixnum.
+
+@index [N-To-Values]
+N-To-Values (@i[N])@\@i[N] is a fixnum.  Returns a Values-Marker with the
+same low-order 24 bits as @i[N].
+
+@index [Force-Values]
+Force-Values (@i[VM])@\If the @i[VM] is a Values-Marker, do
+nothing; if not, push @i[VM] and return a Values-Marker 1.
+
+@index [Flush-Values]
+Flush-Values (@i[])@\is a no-op for the @value(DinkyMachine), since the only
+time that a Flush-Values miscop is generated is in some well-defined cases
+where all the values are wanted on the stack.
+@end(Description)
+
+@subsection [System Hacking]
+@label [System-Hacking-Instructions]
+@instrsection
+
+@begin(Description)
+@index [Get-Type]
+Get-Type (@i[Object])@\returns the five type bits of the @i[Object] as a
+fixnum.
+
+@index [Get-Space]
+Get-Space (@i[Object])@\returns the two space bits of @i[Object] as a
+fixnum.
+
+@index [Make-Immediate-Type]
+Make-Immediate-Type (@i[X A])@\returns an object whose type bits are the
+integer @i[A] and whose other bits come from the immediate object or pointer
+@i[X].	@i[A] should be an immediate type code.
+
+@index [8bit-System-Ref]
+8bit-System-Ref (@i[X I])@\@i[X] must be a system area pointer, returns
+the @i[I]'th byte of @i[X], indexing into @i[X] directly.  @i[I]
+must be a fixnum.
+
+@index [8bit-System-Set]
+8bit-System-Set (@i[X I V])@\@i[X] must be a system area pointer, sets the
+@i[I]'th element of @i[X] to @i[V], indexing into @i[X] directly.
+
+@index [16bit-System-Ref]
+16bit-System-Ref (@i[X I])@\@i[X] must be a system area pointer, returns the
+@i[I]'th 16-bit word of @i[X], indexing into @i[X] directly.
+
+@index [Signed-16bit-System-Ref]
+Signed-16bit-System-Ref (@i[X I])@\@i[X] must be a system area pointer,
+returns the @i[I]'th 16-bit word of @i[X] extending the high order bit as
+the sign bit.
+
+@Index [16bit-System-Set]
+16bit-System-Set (@i[X I V])@\@i[X] must be a system area pointer, sets the
+@i[I]'th element of @i[X] to @i[V], indexing into @i[X] directly.
+
+@Index [Signed-32bit-System-Ref]
+Signed-32bit-System-Ref (@i[X I])@\@i[X] must be a system area pointer and
+@i[I] an even fixnum, returns the @i[I]/2'th 32 bit word as a signed
+quantity.
+
+@Index [Unsigned-32bit-System-Ref]
+Unsigned-32bit-System-Ref (@i[X I])@\@i[X] must be a system area pointer and
+@i[I] an even fixnum, returns the @i[I]/2'th 32 bit word as an unsigned
+quantity.
+
+@Index [Signed-32bit-System-Set]
+Signed-32bit-System-Set (@i[X I V])@\@i[X] must be a system area pointer,
+@i[I] an even fixnum, and @i[V] an integer, sets the @i[I]/2'th element of
+@i[X] to @i[V].
+
+@index[Sap-System-Ref]
+Sap-System-Ref (@i[X I])@\@i[X] must be a system area pointer and @i[I] and
+even fixnum, returns the @i[I]/2'th element of @i[X] as a system area
+pointer.
+
+@index[Sap-System-Set]
+Sap-System-Set (@i[X I V])@\@i[X] and @i[V] must be a system area pointers
+and @i[I] an even fixnum, sets the @i[I]/2'th element of @i[X] to @i[V].
+
+@index[Pointer-System-Set]
+Pointer-System-Set (@i[X I])@\@i[X] must be a system area pointer, @i[I] an
+even fixnum, and @i[V] a pointer (either system area pointer or Lisp
+pointer), sets the @i[I]/2'th element of @i[X] to the pointer @i[V].  If
+the pointer is a Lisp pointer, the pointer stored is to the first word of
+data (i.e., the header word(s) are bypassed).
+
+@index[Sap-Int]
+Sap-Int (@i[X])@\@i[X] should be a system area pointer, returns a Lisp
+integer containing the system area pointer.  This miscop is useful when it
+is necessary to do arithmetic on system area pointers.
+
+@index[Int-Sap]
+Int-Sap (@i[X])@\@i[X] should be an integer (fixnum or bignum), returns a
+system area pointer.  This miscop performs the inverse operation of sap-int.
+
+@index[Check-<=]
+Check-<= (@i[X] @i[Y])@\checks to make sure that @i[X] is less than or
+equal to @i[Y].  If not, then check-<= signals an error, otherwise it just
+returns.
+
+@index [Collect-Garbage]
+Collect-Garbage (@i[])@\causes a stop-and-copy GC to be performed.
+
+@index [Purify]
+Purify (@i[])@\is similar to collect-garbage, except it copies Lisp objects
+into static or read-only space.  This miscop needs Lisp level code to get
+the process started by putting some root structures into the correct space.
+
+@index [Newspace-Bit]
+Newspace-Bit (@i[])@\returns 0 if newspace is currently space 0 or 1 if it is
+1.
+
+@index [Save]
+Save (@i[*current-alien-free-pointer*] @i[Checksum] @I[memory])@\Save takes
+a snap short of the current state of the Lisp computation.  The value of
+the symbol *Current-alien-free-pointer* must be passed to save, so that it
+can save the static alien data structures.  The parameter @i[checksum]
+specifies whether a checksum should be generated for the saved image.
+Currently, this parameter is ignored and no checksum is generated.  The
+parameter @i[memory] should be be a pointer to a block of memory where the
+saved core image will be stored.  Save returns the size of the core image
+generated.
+
+@index [Syscall0]
+@index [Syscall1]
+@index [Syscall2]
+@index [Syscall3]
+@index [Syscall4]
+@index [Syscall]
+Syscall0 Syscall1 Syscall2 Syscall3 Syscall4 Syscall (@i[number]
+@i[arg@-<1> ... arg@-<n>])@\is for making syscalls to the Mach kernel.  The
+argument @i[number] should be the number of the syscall.  Syscall0 accepts
+no arguments to the syscall; syscall1 accepts one argument to the syscall,
+etc.  Syscall accepts five or more arguments to the syscall.
+
+@index[Unix-write]
+Unix-Write (@i[fd buffer offset length])@\performs a Unix write syscall to
+the file descriptor @i[fd].  @i[Buffer] should contain the data to be
+written;  @i[Offset] should be an offset into buffer from which to start
+writing; and @i[length] is the number of bytes of data to write.
+
+@index[Unix-fork]
+Unix-Fork ()@\performs a Unix fork operation returning one or two values.
+If an error occurred, the value -1 and the error code is returned.  If no
+error occurred, 0 is returned in the new process and the process id of the
+child process is returned in the parent process.
+
+@index [Arg-In-Frame] Arg-In-Frame (@i[N F])@\@i[N] is a fixnum, @i[F] is a
+control stack pointer as returned by the Active-Call-Frame miscop.  It
+returns the item in slot @i[N] of the args-and-locals area of call frame
+@i[F].
+
+@index [Active-Call-Frame]
+Active-Call-Frame (@i[])@\returns a control-stack pointer to the start of the
+currently active call frame.  This will be of type Control-Stack-Pointer.
+
+@index [Active-Catch-Frame]
+Active-Catch-Frame (@i[])@\returns the control-stack pointer to the start of
+the currently active catch frame.  This is Nil if there is no active catch.
+
+@index [Set-Call-Frame]
+Set-Call-Frame (@i[P])@\@i[P] must be a control stack pointer.	This becomes
+the current active call frame pointer.
+
+@index [Current-Stack-Pointer]
+Current-Stack-Pointer (@i[])@\returns the Control-Stack-Pointer that points
+to the current top of the stack (before the result of this operation is
+pushed).  Note: by definition, this points to the
+to the last thing pushed.
+
+@index [Current-Binding-Pointer]
+Current-Binding-Pointer (@i[])@\returns a Binding-Stack-Pointer that points
+to the first word above the current top of the binding stack.
+
+@index [Read-Control-Stack]
+Read-Control-Stack (@i[F])@\@i[F] must be a control stack pointer.  Returns
+the Lisp object that resides at this location.	If the addressed object is
+totally outside the current stack, this is an error.
+
+@index [Write-Control-Stack]
+Write-Control-Stack (@i[F V])@\@i[F] is a stack pointer, @i[V] is any Lisp
+object.  Writes @i[V] into the location addressed.  If the addressed cell is
+totally outside the current stack, this is an error.  Obviously, this should
+only be used by carefully written and debugged system code, since you can
+destroy the world by using this miscop.
+
+@index [Read-Binding-Stack]
+Read-Binding-Stack (@i[B])@\@i[B] must be a binding stack pointer.  Reads and
+returns the Lisp object at this location.  An error if the location specified
+is outside the current binding stack.
+
+@index [Write-Binding-Stack]
+Write-Binding-Stack (@i[B V])@\@i[B] must be a binding stack pointer.  Writes
+@i[V] into the specified location.  An error if the location specified is
+outside the current binding stack.
+@end(Description)
+
+@chapter [Control Conventions]
+@label [Control-Conventions]
+@index [Hairy stuff]
+
+@section [Function Calls]
+@index [Call]
+@index [Call-0]
+@index [Call-Multiple]
+
+On the Perq function calling is done by micro-coded instructions.  The
+instructions perform a large number of operations, including determining
+whether the function being called is compiled or interpreted, determining that
+a legal number of arguments are passed, and branching to the correct entry
+point in the function.  To do all this on the @value(DinkyMachine) would
+involve a large amount of computation.	In the general case, it is necessary to
+do all this, but in some common cases, it is possible to short circuit most of
+this work.
+
+To perform a function call in the general case, the following steps occur:
+@begin(Enumerate)
+
+Allocate space on the control stack for the fix-sized part of a call
+frame.  This space will be used to store all the registers that must
+be preserved across a function call.
+
+Arguments to the function are now evaluated.  The first three
+arguments are stored in the argument registers A0, A1, and A2.  The
+rest of the arguments are stored on the stack as they are evaluated.
+Note that during the evaluation of arguments, the argument registers
+may be used and may have to be stored in local variables and restored
+just before the called function is invoked.
+
+Load R0 with the argument count.
+
+Load the PC register with the offset into the current code vector of
+the place to return to when the function call is complete.
+
+If this call is for multiple values, mark the frame as accepting
+multiple values, by making the fixnum offset above negative by oring
+in the negative fixnum type code.
+
+Store all the registers that must be preserved over the function call in the
+current frame.
+@end(Enumerate)
+
+At this point, all the arguments are set up and all the registers have been
+saved.	All the code to this point is done inline.  If the object being called
+as a function is a symbol, we get the definition from the definition cell of
+the symbol.  If this definition is the trap object, an undefined symbol error
+is generated.  The function calling mechanism diverges at this point depending
+on the type of function being called, i.e., whether it is a compiled function
+object or a list.
+
+If we have a compiled function object, the following steps are performed (this
+code is out of line):
+@begin(Enumerate)
+Load the active function register with a pointer to the compiled function
+object.
+
+The active frame register is set to the start of the current frame.
+
+Note the number of arguments evaluated.  Let this be K.  The correct
+entry point in the called function's code vector must be computed as
+a function of K and the number of arguments the called function
+wants:
+@begin(Enumerate, spread 0, spacing 1)
+If K < minimum number of arguments, signal an error.
+
+If K > maximum number of arguments and there is no &rest argument,
+signal an error.
+
+If K > maximum number of arguments and there is a &rest argument,
+start at offset 0 in the code vector.  This entry point must collect
+the excess arguments into a list and leave the &rest argument in the
+appropriate argument register or on the stack as appropriate.
+
+If K is between the minimum and maximum arguments (inclusive), get
+the starting offset from the appropriate slot of the called
+function's function object.  This is stored as a fixnum in slot K -
+MIN + 6 of the function object.
+@end(Enumerate)
+
+Load one of the Non-Lisp temporary registers with the address of the
+code vector and add in the offset calculated above.  Then do a branch
+register instruction with this register as the operand.  The called
+function is now executing at the appropriate place.
+@end(enumerate)
+
+If the function being called is a list, %SP-Internal-Apply must be called to
+interpret the function with the given arguments.  Proceed as follows:
+@begin(Enumerate)
+Note the number of arguments evaluated for the current open frame (call this N)
+and the frame pointer for the frame (call it F).  Also remember the lambda
+expression in this frame (call it L).
+
+Load the active function register with the list L.
+
+Load the PC register with 0.
+
+Allocate a frame on the control stack for the call to %SP-Internal-Apply.
+
+Move the contents of the argument registers into the local registers L0, L1,
+and L2 respectively.
+
+Store all the preserved registers in the frame.
+
+Place N, F, and L into argument registers A0, A1, and A2 respectively.
+
+Do the equivalent of a start call on %SP-Internal-Apply.
+@end(Enumerate) %SP-Internal-Apply, a function of three arguments,
+now evaluates the call to the lambda-expression or interpreted
+lexical closure L, obtaining the arguments from the frame pointed to
+by F.  The first three arguments must be obtained from the frame that
+%SP-Internal-Apply runs in, since they are stored in its stack frame
+and not on the stack as the rest of the arguments are. Prior to
+returning %SP-Internal-Apply sets the Active-Frame register to F, so
+that it returns from frame F.
+
+The above is the default calling mechanism.  However, much of the
+overhead can be reduced.  Most of the overhead is incurred by having
+to check the legality of the function call everytime the function is
+called.  In many situations where the function being called is a
+symbol, this checking can be done only once per call site by
+introducing a data structure called a link table.  The one exception
+to this rule is when the function apply is used with a symbol.  In
+this situation, the argument count checks are still necessary, but
+checking for whether the function is a list or compiled function
+object can be bypassed.
+
+The link table is a hash table whose key is based on the name of the
+function, the number of arguments supplied to the call and a flag
+specifying whether the call is done through apply or not.  Each entry
+of the link table consists of two words:
+@begin(Enumerate)
+The address of the function object associated with the symbol being
+called.  This is here, so that double indirection is not needed to
+access the function object which must be loaded into the active
+function register.  Initially, the symbol is stored in this slot.
+
+The address of the instruction in the function being called to start
+executing when this table entry is used.  Initially, this points to
+an out of line routine that checks the legality of the call and
+calculates the correct place to jump to in the called function.  This
+out of line routine replaces the contents of this word with the
+correct address it calculated.  In the case when the call is caused
+by apply, this will often be an out of line routine that checks the
+argument count and calculates where to jump.  In the case where the
+called function accepts &rest arguments and the minimum number of
+arguments passed is guaranteed to be greater than the maximum number
+of arguments, then a direct branch to the &rest arg entry point is
+made.
+@end(Enumerate)
+
+When a compiled file is loaded into the lisp environment, all the
+entries for the newly loaded functions will be set to an out of line
+routine mentioned above.  Also, during a garbage collection the
+entries in this table must be updated when a function object for a
+symbol is moved.
+
+The @value(DinkyMachine) code to perform a function call using the link table
+becomes:
+@begin(Example)
+	cal	CS,CS,%Frame-Size	; Alloc. space on control st.
+
+	<Code to evaluate arguments to the function>
+
+	cau	NL1,0,high-half-word(lte(function nargs flag))
+	oil	NL1,0,low-half-word(lte(function nargs flag))
+	cal	PC,0,return-tag 	; Offset into code vector.
+       <oiu	PC,PC,#xF800		; Mark if call-multiple frame>
+	stm	L0,CS,-(%Frame-Size-4)	; Save preserved regs.
+	lm	AF,NL1,0 		; Link table entry contents.
+	bnbrx	pz,R15			; Branch to called routine.
+	cal	FP,CS,-(%Frame-Size-4)	; Get pointer to frame.
+return-tag:
+@end(Example)
+The first two instructions after the arguments are evaled get the
+address of the link table entry into a register.  The two 16-bit half
+word entries are filled in at load time.  The rest of the
+instructions should be fairly straight forward.
+
+@section(Returning from a Function Call)
+@label(Return)
+@index(Return)
+
+Returning from a function call on the Perq is done by a micro-coded
+instruction.  On the @value(DinkyMachine), return has to do the following:
+@begin(enumerate)
+Pop the binding stack back to the binding stack pointer stored in the frame
+we're returning from.  For each symbol/value pair popped of the binding stack,
+restore that value for the symbol.
+
+Save the current value of the frame pointer in a temporary registers.  This
+will be used to restore the control stack pointer at the end.
+
+Restore all the registers that are preserved across a function call.
+
+Get a pointer to the code vector for the function we're returning to.  This is
+retrieved from the code slot of what is now the active function.
+
+Make sure the relative PC (which is now in a register) is positive and add it
+to the code vector pointer above, giving the address of the instruction to
+return to.
+
+If the function is returning multiple values do a block transfer of all the
+return values down over the stack frame just released, i.e., the first return
+value should be stored where the temporarily saved frame pointer points to.
+In effect the return values can be pushed onto the stack using the saved frame
+pointer above as a stack pointer that is incremented everytime a value is
+pushed.   Register A0 can be examined to determine the number of values that
+must be transferred.
+
+Set the control stack register to the saved frame pointer above.  NB: it may
+have been updated if multiple values are being returned.
+
+Resume execution of the calling function.
+@end(enumerate)
+
+Again, it is not always necessary to use the general return code.  At compile
+time it is often possible to determine that no special symbols have to be
+unbound and/or only one value is being returned.  For example the code to
+perform a return when only one value is returned and it is unnecessary to
+unbind any special symbols is:
+@begin(Example)
+	cas	NL1,FP,0		; Save frame register.
+	lm	L0,FP,0			; Restore all preserved regs.
+	ls	A3,AF,%function-code	; Get pointer to code vector.
+	niuo	PC,PC,#x07FF		; Make relative PC positive.
+	cas	PC,A3,PC		; Get addr. of instruction
+	bnbrx	pz,PC			; to return to and do so while
+	cas	CS,NL1,0		; updating control stack reg.
+@end(Example)
+
+
+@subsection [Returning Multiple-Values]
+@label [Multi]
+@index [Multiple values]
+
+If the current frame can accept multiple values and a values marker is in
+register A0 indicating N values on top of the stack, it is necessary to copy
+the N return values down to the top of the control stack after the current
+frame is popped off.  Thus returning multiple values is similar to the
+above, but a block transfer is necessary to move the returned values down to
+the correct location on the control stack.
+
+In tail recursive situations, such as in the last form of a PROGN, one
+function, FOO, may want to call another function, BAR, and return ``whatever
+BAR returns.''  Call-Multiple is used in this case.  If BAR returns multiple
+values, they will all be passed to FOO.  If FOO's caller wants multiple values,
+the values will be returned.  If not, FOO's Return instruction will see that
+there are multiple values on the stack, but that multiple values will not be
+accepted by FOO's caller.  So Return will return only the first value.
+
+@section [Non-Local Exits]
+@label [Catch]
+@index [Catch]
+@index [Throw]
+@index [Catch-All object]
+@index [Unwind-Protect]
+@index [Non-Local Exits]
+
+The Catch and Unwind-Protect special forms are implemented using
+catch frames.  Unwind-Protect builds a catch frame whose tag is the
+Catch-All object.  The Catch miscop creates a catch frame for a
+given tag and PC to branch to in the current instruction.  The Throw
+miscop looks up the stack by following the chain of catch frames
+until it finds a frame with a matching tag or a frame with the
+Catch-All object as its tag.  If it finds a frame with a matching
+tag, that frame is ``returned from,'' and that function is resumed.
+If it finds a frame with the Catch-All object as its tag, that frame
+is ``returned from,'' and in addition, %SP-Internal-Throw-Tag is set
+to the tag being searched for.  So that interrupted cleanup forms
+behave correctly, %SP-Internal-Throw-Tag should be bound to the
+Catch-All object before the Catch-All frame is built.  The protected
+forms are then executed, and if %SP-Internal-Throw-Tag is not the
+Catch-All object, its value is thrown to.  Exactly what we do is
+this:
+@begin [enumerate]
+Put the contents of the Active-Catch register into a register, A.
+Put NIL into another register, B.
+
+If A is NIL, the tag we seek isn't on the stack.  Signal an
+Unseen-Throw-Tag error.
+
+Look at the tag for the catch frame in register A.  If it's the tag
+we're looking for, go to step 4.  If it's the Catch-All object and B
+is NIL, copy A to B.  Set A to the previous catch frame and go back
+to step 2.
+
+If B is non-NIL, we need to execute some cleanup forms.  Return into
+B's frame and bind %SP-Internal-Throw-Tag to the tag we're searching
+for.  When the cleanup forms are finished executing, they'll throw to
+this tag again.
+
+If B is NIL, return into this frame, pushing the return value (or
+BLTing the multiple values if this frame accepts multiple values and
+there are multiple values).
+@end [enumerate]
+
+If no form inside of a Catch results in a Throw, the catch frame
+needs to be removed from the stack before execution of the function
+containing the throw is resumed.  For now, the value produced by the
+forms inside the Catch form are thrown to the tag.  Some sort of
+specialized miscop could be used for this, but right now we'll
+just go with the throw.  The branch PC specified by a Catch
+miscop is part of the constants area of the function object,
+much like the function's entry points.
+
+@section [Escaping to Lisp code]
+@label [Escape]
+@index [Escape to Lisp code convention]
+
+Escaping to Lisp code is fairly straight forward.  If a miscop discovers that
+it needs to call a Lisp function, it creates a call frame on the control
+stack and sets it up so that the called function returns to the function that
+called the miscop.  This means it is impossible to return control to a miscop
+from a Lisp function.
+
+@section [Errors]
+@label [Errors]
+@index [Errors]
+
+When an error occurs during the execution of a miscop, a call
+to %SP-Internal-Error is performed.  This call is a break-type call,
+so if the error is proceeded (with a Break-Return instruction), no
+value will be returned.
+
+
+%SP-Internal-Error is passed a fixnum error code as its first
+argument.  The second argument is a fixnum offset into the current
+code vector that points to the location immediately following the
+instruction that encountered the trouble.  From this offset, the
+Lisp-level error handler can reconstruct the PC of the losing
+instruction, which is not readily available in the micro-machine.
+Following the offset, there may be 0 - 2 additional arguments that
+provide information of possible use to the error handler.  For
+example, an unbound-symbol error will pass the symbol in question as
+the third arg.
+
+The following error codes are currently defined.  Unless otherwise
+specified, only the error code and the code-vector offset are passed
+as arguments.
+
+@begin 
+[description]
+1  Object Not List@\The object is passed as the third argument.
+
+2  Object Not Symbol@\The object is passed as the third argument.
+
+3  Object Not Number@\The object is passed as the third argument.
+
+4  Object Not Integer@\The object is passed as the third argument.
+
+5  Object Not Ratio@\The object is passed as the third argument.
+
+6  Object Not Complex@\The object is passed as the third argument.
+
+7  Object Not Vector@\The object is passed as the third argument.
+
+8  Object Not Simple Vector@\The object is passed as the third argument.
+
+9  Illegal Function Object@\The object is passed as the third argument.
+
+10  Object Not Header@\The object (which is not an array or function header)
+is passed as the third argument.
+
+11  Object Not I-Vector@\The object is passed as the third argument.
+
+12  Object Not Simple Bit Vector@\The object is passed as the third argument.
+
+13  Object Not Simple String@\The object is passed as the third argument.
+
+14  Object Not Character@\The object is passed as the third argument.
+
+15  Object Not Control Stack Pointer@\The object is passed as the third
+argument.
+
+16  Object Not Binding Stack Pointer@\The object is passed as the third
+argument.
+
+17  Object Not Array@\The object is passed as the third argument.
+
+18  Object Not Non-negative Fixnum@\The object is passed as the third
+argument.
+
+19  Object Not System Area Pointer@\The object is passed as the third
+argument.
+
+20  Object Not System Pointer@\The object is passed as the third argument.
+
+21  Object Not Float@\The object is passed as the third argument.
+
+22  Object Not Rational@\The object is passed as the third argument.
+
+23  Object Not Non-Complex Number@\A complex number has been passed to
+the comparison routine for < or >.  The complex number is passed as the
+third argument.
+
+25  Unbound Symbol @\Attempted access to the special value of an unbound
+symbol.  Passes the symbol as the third argument to %Sp-Internal-Error.
+
+26  Undefined Symbol @\Attempted access to the definition cell of an undefined
+symbol.  Passes the symbol as the third argument to %Sp-Internal-Error.
+
+27 Altering NIL @\Attempt to bind or setq the special value of NIL.
+
+28 Altering T @\Attempt to bind or setq the special value of T.
+
+30 Illegal Vector Access Type @\The specified access type is returned as the
+third argument.
+
+31 Illegal Vector Size @\Attempt to allocate a vector with negative size or
+size too large for vectors of this type.  Passes the requested size as the
+third argument.
+
+32 Vector Index Out of Range @\The specified index is out of bounds for
+this vector.  The bad index is passed as the third argument.
+
+33 Illegal Vector Index@\The specified index is not a positive fixnum.  The
+bad index is passed as the third argument.
+
+34 Illegal Shrink Vector Value@\The specified value to shrink a vector to is
+not a positive fixnum.  The bad value is passed as the third argument.
+
+35 Not A Shrink@\The specified value is greater than the current size of the
+vector being shrunk.  The bad value is passed as the third argument.
+
+36  Illegal Data Vector@\The data vector of an array is illegal.  The bad
+vector is passed as the third value.
+
+37  Array has Too Few Indices@\An attempt has been made to access
+an array as a two or three dimensional array when it has fewer than two
+or three dimensions, respectively.
+
+38  Array has Too Many Indices@\An attempt has been made to access an array
+as a two or three dimensional array when it has more than two or three
+dimensions, respectively.
+
+40  Illegal Byte Specifier@\A bad byte specifier has been passed to one
+of the byte manipulation miscops.  The offending byte specifier is passed
+as the third argument.
+
+41  Illegal Position in Byte Specifier@\A bad position has been given in a
+byte specifier that has been passed to one of the byte manipulation
+miscops.  The offending byte specifier is passed as the third
+argument.
+
+42  Illegal Size in Byte Specifier@\A bad size has been given in a
+byte specifier that has been passed to one of the byte manipulation
+miscops.  The offending byte specifier is passed as the third
+argument.
+
+43  Illegal Shift Count@\A shift miscop has encountered non fixnum shift
+count.  The offending shift count is passed as the third argument.
+
+44  Illegal Boole Operation@\The operation code passed to the boole miscop
+is either not a fixnum or is out of range.  The operation code is passed as
+the third argument.
+
+50  Too Few Arguments@\Too few arguments have been passed to a function.  The
+number of arguments actually passed is passed as the third argument, and the
+function is passed as the fourth.
+
+51  Too Many Arguments@\Too many arguments have been passed to a function.
+The number of arguments actually passed is passed as the third argument, and
+the function is passed as the fourth.
+
+52  Last Apply Arg Not a List@\The last argument to a function being
+invoked by apply is not a list.  The last argument is passed as the third
+argument.
+
+53  Deleted Link Table Entry@\An attempt has been made to call a function
+through a link table entry which no longer exists.  This is a serious
+internal error and should never happen.
+
+55  Error Not <=@\The check-<= miscop will invoke this error if the condition
+is false.  The two arguments are passed as the third and fourth arguments
+to %SP-internal-error.
+
+60  Divide by 0@\An division operation has done a division by zero.  The
+two operands are passed as the third and fourth arguments.
+
+61  Unseen Throw Tag@\An attempt has been made to throw to a tag that is
+not in the current catch hierarchy.  The offending tag is passed as the
+third argument.
+
+62  Short Float Underflow@\A short float operation has resulted in
+underflow.  The two arguments to the operation are passed as the third
+and fourth arguments.
+
+63  Short Float Overflow@\A short float operation has resulted in
+overflow.  The two arguments to the operation are passed as the third
+and fourth arguments.
+
+64  Single Float Underflow@\A single float operation has resulted in
+underflow.  The two arguments to the operation are passed as the third
+and fourth arguments.
+
+65  Single Float Overflow@\A single float operation has resulted in
+overflow.  The two arguments to the operation are passed as the third
+and fourth arguments.
+
+66  Long Float Underflow@\A long float operation has resulted in
+underflow.  The two arguments to the operation are passed as the third
+and fourth arguments.
+
+67  Long Float Overflow@\A long float operation has resulted in
+overflow.  The two arguments to the operation are passed as the third
+and fourth arguments.
+
+68  Monadic Short Float Underflow@\A short float operation has resulted in
+underflow.  The argument to the operation is passed as the third argument.
+
+69  Monadic Short Float Overflow@\A short float operation has resulted in
+overflow.  The argument to the operation is passed as the third argument.
+
+70  Monadic Long Float Underflow@\A long float operation has resulted in
+underflow.  The argument to the operation is passed as the third argument.
+
+71  Monadic Long Float Overflow@\A long float operation has resulted in
+overflow.  The argument to the operation is passed as the third argument.
+@end [description]
+
+@section [Trapping to the Mach Kernel]
+@label [Trap]
+@index [Trapping to the kernel]
+@index [Kernel traps]
+
+Trapping to the Mach kernel is done through one of the syscall0, syscall1,
+syscall2, syscall3, syscall4, or syscall miscops.  The first argument to
+these miscops is the number of the Unix syscall that is to be invoked.  Any
+other arguments the syscall requires are passed in order after the first
+one.  Syscall0 accepts only the syscall number and no other arguments;
+syscall1 accepts the syscall number and a single argument to the syscall;
+etc.  Syscall accepts the syscall number and five or more arguments to the
+Unix syscall.  These syscalls generally return two values: the result twice
+if the syscall succeeded and a -1 and the Unix error code if the syscall
+failed.
+
+@section [Interrupts]
+@label [Interrupts]
+@index [Interrupts]
+
+An interface has been built to the general signal mechanism defined by the
+Unix operating system.  As mentioned in the section on function call and
+return miscops, several miscops are defined that support the lowest level
+interface to the Unix signal mechanism.  The manual @I[CMU Common Lisp
+User's Manual, Mach/IBM RT PC Edition] contains descriptions of functions
+that allow a user to set up interrupt handlers for any of the Unix signals
+from within Lisp.
+
+@appendix [Fasload File Format]
+@section [General]
+
+The purpose of Fasload files is to allow concise storage and rapid
+loading of Lisp data, particularly function definitions.  The intent
+is that loading a Fasload file has the same effect as loading the
+ASCII file from which the Fasload file was compiled, but accomplishes
+the tasks more efficiently.  One noticeable difference, of course, is
+that function definitions may be in compiled form rather than
+S-expression form.  Another is that Fasload files may specify in what
+parts of memory the Lisp data should be allocated.  For example,
+constant lists used by compiled code may be regarded as read-only.
+
+In some Lisp implementations, Fasload file formats are designed to
+allow sharing of code parts of the file, possibly by direct mapping
+of pages of the file into the address space of a process.  This
+technique produces great performance improvements in a paged
+time-sharing system.  Since the Mach project is to produce a
+distributed personal-computer network system rather than a
+time-sharing system, efficiencies of this type are explicitly @i[not]
+a goal for the CMU Common Lisp Fasload file format.
+
+On the other hand, CMU Common Lisp is intended to be portable, as it will
+eventually run on a variety of machines.  Therefore an explicit goal
+is that Fasload files shall be transportable among various
+implementations, to permit efficient distribution of programs in
+compiled form.  The representations of data objects in Fasload files
+shall be relatively independent of such considerations as word
+length, number of type bits, and so on.  If two implementations
+interpret the same macrocode (compiled code format), then Fasload
+files should be completely compatible.  If they do not, then files
+not containing compiled code (so-called "Fasdump" data files) should
+still be compatible.  While this may lead to a format which is not
+maximally efficient for a particular implementation, the sacrifice of
+a small amount of performance is deemed a worthwhile price to pay to
+achieve portability.
+
+The primary assumption about data format compatibility is that all
+implementations can support I/O on finite streams of eight-bit bytes.
+By "finite" we mean that a definite end-of-file point can be detected
+irrespective of the content of the data stream.  A Fasload file will
+be regarded as such a byte stream.
+
+@section [Strategy]
+
+A Fasload file may be regarded as a human-readable prefix followed by
+code in a funny little language.  When interpreted, this code will
+cause the construction of the encoded data structures.  The virtual
+machine which interprets this code has a @i[stack] and a @i[table],
+both initially empty.  The table may be thought of as an expandable
+register file; it is used to remember quantities which are needed
+more than once.  The elements of both the stack and the table are
+Lisp data objects.  Operators of the funny language may take as
+operands following bytes of the data stream, or items popped from the
+stack.  Results may be pushed back onto the stack or pushed onto the
+table.  The table is an indexable stack that is never popped; it is
+indexed relative to the base, not the top, so that an item once
+pushed always has the same index.
+
+More precisely, a Fasload file has the following macroscopic
+organization.  It is a sequence of zero or more groups concatenated
+together.  End-of-file must occur at the end of the last group.  Each
+group begins with a series of seven-bit ASCII characters terminated
+by one or more bytes of all ones (FF@-(16)); this is called the
+@i[header].  Following the bytes which terminate the header is the
+@i[body], a stream of bytes in the funny binary language.  The body
+of necessity begins with a byte other than FF@-(16).  The body is
+terminated by the operation @f[FOP-END-GROUP].
+
+The first nine characters of the header must be "@f[FASL FILE]" in
+upper-case letters.  The rest may be any ASCII text, but by
+convention it is formatted in a certain way.  The header is divided
+into lines, which are grouped into paragraphs.  A paragraph begins
+with a line which does @i[not] begin with a space or tab character,
+and contains all lines up to, but not including, the next such line.
+The first word of a paragraph, defined to be all characters up to but
+not including the first space, tab, or end-of-line character, is the
+@i[name] of the paragraph.  A Fasload file header might look something like
+this:
+@begin(verbatim)
+FASL FILE >SteelesPerq>User>Guy>IoHacks>Pretty-Print.Slisp
+Package Pretty-Print
+Compiled 31-Mar-1988 09:01:32 by some random luser
+Compiler Version 1.6, Lisp Version 3.0.
+Functions: INITIALIZE DRIVER HACK HACK1 MUNGE MUNGE1 GAZORCH
+	   MINGLE MUDDLE PERTURB OVERDRIVE GOBBLE-KEYBOARD
+	   FRY-USER DROP-DEAD HELP CLEAR-MICROCODE
+	    %AOS-TRIANGLE %HARASS-READTABLE-MAYBE
+Macros:    PUSH POP FROB TWIDDLE
+@r[<one or more bytes of FF@-(16)>]
+@end(verbatim)
+The particular paragraph names and contents shown here are only intended as
+suggestions.
+
+@section [Fasload Language]
+
+Each operation in the binary Fasload language is an eight-bit
+(one-byte) opcode.  Each has a name beginning with "@f[FOP-]".  In
+the following descriptions, the name is followed by operand
+descriptors.  Each descriptor denotes operands that follow the opcode
+in the input stream.  A quantity in parentheses indicates the number
+of bytes of data from the stream making up the operand.  Operands
+which implicitly come from the stack are noted in the text.  The
+notation "@PushArrow stack" means that the result is pushed onto the
+stack; "@PushArrow table" similarly means that the result is added to the
+table.  A construction like "@i[n](1) @i[value](@i[n])" means that
+first a single byte @i[n] is read from the input stream, and this
+byte specifies how many bytes to read as the operand named @i[value].
+All numeric values are unsigned binary integers unless otherwise
+specified.  Values described as "signed" are in two's-complement form
+unless otherwise specified.  When an integer read from the stream
+occupies more than one byte, the first byte read is the least
+significant byte, and the last byte read is the most significant (and
+contains the sign bit as its high-order bit if the entire integer is
+signed).
+
+Some of the operations are not necessary, but are rather special
+cases of or combinations of others.  These are included to reduce the
+size of the file or to speed up important cases.  As an example,
+nearly all strings are less than 256 bytes long, and so a special
+form of string operation might take a one-byte length rather than a
+four-byte length.  As another example, some implementations may
+choose to store bits in an array in a left-to-right format within
+each word, rather than right-to-left.  The Fasload file format may
+support both formats, with one being significantly more efficient
+than the other for a given implementation.  The compiler for any
+implementation may generate the more efficient form for that
+implementation, and yet compatibility can be maintained by requiring
+all implementations to support both formats in Fasload files.
+
+Measurements are to be made to determine which operation codes are
+worthwhile; little-used operations may be discarded and new ones
+added.  After a point the definition will be "frozen", meaning that
+existing operations may not be deleted (though new ones may be added;
+some operations codes will be reserved for that purpose).
+
+@begin(description)
+0 @f[ ] @f[FOP-NOP] @\
+No operation.  (This is included because it is recognized
+that some implementations may benefit from alignment of operands to some
+operations, for example to 32-bit boundaries.  This operation can be used
+to pad the instruction stream to a desired boundary.)
+
+1 @f[ ] @f[FOP-POP] @f[ ] @PushArrow @f[ ] table @\
+One item is popped from the stack and added to the table.
+
+2 @f[ ] @f[FOP-PUSH] @f[ ] @i[index](4) @f[ ] @PushArrow @f[ ] stack @\
+Item number @i[index] of the table is pushed onto the stack.
+The first element of the table is item number zero.
+
+3 @f[ ] @f[FOP-BYTE-PUSH] @f[ ] @i[index](1) @f[ ] @PushArrow @f[ ] stack @\
+Item number @i[index] of the table is pushed onto the stack.
+The first element of the table is item number zero.
+
+4 @f[ ] @f[FOP-EMPTY-LIST] @f[ ] @PushArrow @f[ ] stack @\
+The empty list (@f[()]) is pushed onto the stack.
+
+5 @f[ ] @f[FOP-TRUTH] @f[ ] @PushArrow @f[ ] stack @\
+The standard truth value (@f[T]) is pushed onto the stack.
+
+6 @f[ ] @f[FOP-SYMBOL-SAVE] @f[ ] @i[n](4) @f[ ] @i[name](@i[n])
+@f[ ] @PushArrow @f[ ] stack & table@\
+The four-byte operand @i[n] specifies the length of the print name
+of a symbol.  The name follows, one character per byte,
+with the first byte of the print name being the first read.
+The name is interned in the default package,
+and the resulting symbol is both pushed onto the stack and added to the table.
+
+7 @f[ ] @f[FOP-SMALL-SYMBOL-SAVE] @f[ ] @i[n](1) @f[ ] @i[name](@i[n]) @f[ ] @PushArrow @f[ ] stack & table@\
+The one-byte operand @i[n] specifies the length of the print name
+of a symbol.  The name follows, one character per byte,
+with the first byte of the print name being the first read.
+The name is interned in the default package,
+and the resulting symbol is both pushed onto the stack and added to the table.
+
+8 @f[ ] @f[FOP-SYMBOL-IN-PACKAGE-SAVE] @f[ ] @i[index](4)
+@f[ ] @i[n](4) @f[ ] @i[name](@i[n])
+@f[ ] @PushArrow @f[ ] stack & table@\
+The four-byte @i[index] specifies a package stored in the table.
+The four-byte operand @i[n] specifies the length of the print name
+of a symbol.  The name follows, one character per byte,
+with the first byte of the print name being the first read.
+The name is interned in the specified package,
+and the resulting symbol is both pushed onto the stack and added to the table.
+
+9 @f[ ] @f[FOP-SMALL-SYMBOL-IN-PACKAGE-SAVE]  @f[ ] @i[index](4)
+@f[ ] @i[n](1) @f[ ] @i[name](@i[n]) @f[ ]
+@PushArrow @f[ ] stack & table@\
+The four-byte @i[index] specifies a package stored in the table.
+The one-byte operand @i[n] specifies the length of the print name
+of a symbol.  The name follows, one character per byte,
+with the first byte of the print name being the first read.
+The name is interned in the specified package,
+and the resulting symbol is both pushed onto the stack and added to the table.
+
+10 @f[ ] @f[FOP-SYMBOL-IN-BYTE-PACKAGE-SAVE] @f[ ] @i[index](1)
+@f[ ] @i[n](4) @f[ ] @i[name](@i[n])
+@f[ ] @PushArrow @f[ ] stack & table@\
+The one-byte @i[index] specifies a package stored in the table.
+The four-byte operand @i[n] specifies the length of the print name
+of a symbol.  The name follows, one character per byte,
+with the first byte of the print name being the first read.
+The name is interned in the specified package,
+and the resulting symbol is both pushed onto the stack and added to the table.
+
+11@f[ ] @f[FOP-SMALL-SYMBOL-IN-BYTE-PACKAGE-SAVE] @f[ ] @i[index](1)
+@f[ ] @i[n](1) @f[ ] @i[name](@i[n]) @f[ ]
+@PushArrow @f[ ] stack & table@\
+The one-byte @i[index] specifies a package stored in the table.
+The one-byte operand @i[n] specifies the length of the print name
+of a symbol.  The name follows, one character per byte,
+with the first byte of the print name being the first read.
+The name is interned in the specified package,
+and the resulting symbol is both pushed onto the stack and added to the table.
+
+12 Unused.
+
+13 @f[ ] @f[FOP-DEFAULT-PACKAGE] @f[ ] @i[index](4) @\
+A package stored in the table entry specified by @i[index] is made
+the default package for future @f[FOP-SYMBOL] and @f[FOP-SMALL-SYMBOL]
+interning operations. (These package FOPs may change or disappear
+as the package system is determined.)
+
+14 @f[ ] @f[FOP-PACKAGE] @f[ ] @PushArrow @f[ ] table @\
+An item is popped from the stack; it must be a symbol.	The package of
+that name is located and pushed onto the table.
+
+15 @f[ ] @f[FOP-LIST] @f[ ] @i[length](1) @f[ ] @PushArrow @f[ ] stack @\
+The unsigned operand @i[length] specifies a number of
+operands to be popped from the stack.  These are made into a list
+of that length, and the list is pushed onto the stack.
+The first item popped from the stack becomes the last element of
+the list, and so on.  Hence an iterative loop can start with
+the empty list and perform "pop an item and cons it onto the list"
+@i[length] times.
+(Lists of length greater than 255 can be made by using @f[FOP-LIST*]
+repeatedly.)
+
+16 @f[ ] @f[FOP-LIST*] @f[ ] @i[length](1) @f[ ] @PushArrow @f[ ] stack @\
+This is like @f[FOP-LIST] except that the constructed list is terminated
+not by @f[()] (the empty list), but by an item popped from the stack
+before any others are.	Therefore @i[length]+1 items are popped in all.
+Hence an iterative loop can start with
+a popped item and perform "pop an item and cons it onto the list"
+@i[length]+1 times.
+
+17-24 @f[ ] @f[FOP-LIST-1], @f[FOP-LIST-2], ..., @f[FOP-LIST-8] @\
+@f[FOP-LIST-@i{k}] is like @f[FOP-LIST] with a byte containing @i[k]
+following it.  These exist purely to reduce the size of Fasload files.
+Measurements need to be made to determine the useful values of @i[k].
+
+25-32 @f[ ] @f[FOP-LIST*-1], @f[FOP-LIST*-2], ..., @f[FOP-LIST*-8] @\
+@f[FOP-LIST*-@i{k}] is like @f[FOP-LIST*] with a byte containing @i[k]
+following it.  These exist purely to reduce the size of Fasload files.
+Measurements need to be made to determine the useful values of @i[k].
+
+33 @f[ ] @f[FOP-INTEGER] @f[ ] @i[n](4) @f[ ] @i[value](@i[n]) @f[ ]
+@PushArrow @f[ ] stack @\
+A four-byte unsigned operand specifies the number of following
+bytes.	These bytes define the value of a signed integer in two's-complement
+form.  The first byte of the value is the least significant byte.
+
+34 @f[ ] @f[FOP-SMALL-INTEGER] @f[ ] @i[n](1) @f[ ] @i[value](@i[n])
+@f[ ] @PushArrow @f[ ] stack @\
+A one-byte unsigned operand specifies the number of following
+bytes.	These bytes define the value of a signed integer in two's-complement
+form.  The first byte of the value is the least significant byte.
+
+35 @f[ ] @f[FOP-WORD-INTEGER] @f[ ] @i[value](4) @f[ ] @PushArrow @f[ ] stack @\
+A four-byte signed integer (in the range -2@+[31] to 2@+[31]-1) follows the
+operation code.  A LISP integer (fixnum or bignum) with that value
+is constructed and pushed onto the stack.
+
+36 @f[ ] @f[FOP-BYTE-INTEGER] @f[ ] @i[value](1) @f[ ] @PushArrow @f[ ] stack @\
+A one-byte signed integer (in the range -128 to 127) follows the
+operation code.  A LISP integer (fixnum or bignum) with that value
+is constructed and pushed onto the stack.
+
+37 @f[ ] @f[FOP-STRING] @f[ ] @i[n](4) @f[ ] @i[name](@i[n])
+@f[ ] @PushArrow @f[ ] stack @\
+The four-byte operand @i[n] specifies the length of a string to
+construct.  The characters of the string follow, one per byte.
+The constructed string is pushed onto the stack.
+
+38 @f[ ] @f[FOP-SMALL-STRING] @f[ ] @i[n](1) @f[ ] @i[name](@i[n]) @f[ ] @PushArrow @f[ ] stack @\
+The one-byte operand @i[n] specifies the length of a string to
+construct.  The characters of the string follow, one per byte.
+The constructed string is pushed onto the stack.
+
+39 @f[ ] @f[FOP-VECTOR] @f[ ] @i[n](4) @f[ ] @PushArrow @f[ ] stack @\
+The four-byte operand @i[n] specifies the length of a vector of LISP objects
+to construct.  The elements of the vector are popped off the stack;
+the first one popped becomes the last element of the vector.
+The constructed vector is pushed onto the stack.
+
+40 @f[ ] @f[FOP-SMALL-VECTOR] @f[ ] @i[n](1) @f[ ] @PushArrow @f[ ] stack @\
+The one-byte operand @i[n] specifies the length of a vector of LISP objects
+to construct.  The elements of the vector are popped off the stack;
+the first one popped becomes the last element of the vector.
+The constructed vector is pushed onto the stack.
+
+41 @f[ ] @f[FOP-UNIFORM-VECTOR] @f[ ] @i[n](4) @f[ ] @PushArrow @f[ ] stack @\
+The four-byte operand @i[n] specifies the length of a vector of LISP objects
+to construct.  A single item is popped from the stack and used to initialize
+all elements of the vector.  The constructed vector is pushed onto the stack.
+
+42 @f[ ] @f[FOP-SMALL-UNIFORM-VECTOR] @f[ ] @i[n](1) @f[ ] @PushArrow @f[ ] stack @\
+The one-byte operand @i[n] specifies the length of a vector of LISP objects
+to construct.  A single item is popped from the stack and used to initialize
+all elements of the vector.  The constructed vector is pushed onto the stack.
+
+43 @f[ ] @f[FOP-INT-VECTOR] @f[ ] @i[n](4) @f[ ] @i[size](1) @f[ ] @i[count](1) @f[ ]
+@i[data](@ceiling<@i[n]/@i[count]>@ceiling<@i[size]*@i[count]/8>) @f[ ]
+@PushArrow @f[ ] stack @\
+The four-byte operand @i[n] specifies the length of a vector of
+unsigned integers to be constructed.   Each integer is @i[size]
+bits big, and are packed in the data stream in sections of
+@i[count] apiece.  Each section occupies an integral number of bytes.
+If the bytes of a section are lined up in a row, with the first
+byte read at the right, and successive bytes placed to the left,
+with the bits within a byte being arranged so that the low-order bit
+is to the right, then the integers of the section are successive
+groups of @i[size] bits, starting from the right and running across
+byte boundaries.  (In other words, this is a consistent
+right-to-left convention.)  Any bits wasted at the left end of
+a section are ignored, and any wasted groups in the last section
+are ignored.
+It is permitted for the loading implementation to use a vector
+format providing more precision than is required by @i[size].
+For example, if @i[size] were 3, it would be permitted to use a vector
+of 4-bit integers, or even vector of general LISP objects filled
+with integer LISP objects.  However, an implementation is expected
+to use the most restrictive format that will suffice, and is expected
+to reconstruct objects identical to those output if the Fasload file
+was produced by the same implementation.
+(For the PERQ U-vector formats, one would have
+@i[size] an element of {1, 2, 4, 8, 16}, and @i[count]=32/@i[size];
+words could be read directly into the U-vector.
+This operation provides a very general format whereby almost
+any conceivable implementation can output in its preferred packed format,
+and another can read it meaningfully; by checking at the beginning
+for good cases, loading can still proceed quickly.)
+The constructed vector is pushed onto the stack.
+
+44 @f[ ] @f[FOP-UNIFORM-INT-VECTOR] @f[ ] @i[n](4) @f[ ] @i[size](1) @f[ ]
+@i[value](@ceiling<@i[size]/8>) @f[ ] @PushArrow @f[ ] stack @\
+The four-byte operand @i[n] specifies the length of a vector of unsigned
+integers to construct.
+Each integer is @i[size] bits big, and is initialized to the value
+of the operand @i[value].
+The constructed vector is pushed onto the stack.
+
+45 @f[ ] @f[FOP-FLOAT] @f[ ] @i[n](1) @f[ ] @i[exponent](@ceiling<@i[n]/8>) @f[ ]
+@i[m](1) @f[ ] @i[mantissa](@ceiling<@i[m]/8>) @f[ ] @PushArrow @f[ ] stack @\
+The first operand @i[n] is one unsigned byte, and describes the number of
+@i[bits] in the second operand @i[exponent], which is a signed
+integer in two's-complement format.  The high-order bits of
+the last (most significant) byte of @i[exponent] shall equal the sign bit.
+Similar remarks apply to @i[m] and @i[mantissa].  The value denoted by these
+four operands is @i[mantissa]@f[x]2@+{@i[exponent]-length(@i[mantissa])}.
+A floating-point number shall be constructed which has this value,
+and then pushed onto the stack.  That floating-point format should be used
+which is the smallest (most compact) provided by the implementation which
+nevertheless provides enough accuracy to represent both the exponent
+and the mantissa correctly.
+
+46-51 Unused
+
+52 @f[ ] @f[FOP-ALTER] @f[ ] @i[index](1) @\
+Two items are popped from the stack; call the first @i[newval] and
+the second @i[object].	The component of @i[object] specified by
+@i[index] is altered to contain @i[newval].  The precise operation
+depends on the type of @i[object]:
+@begin(description)
+List @\ A zero @i[index] means alter the car (perform @f[RPLACA]),
+and @i[index]=1 means alter the cdr (@f[RPLACD]).
+
+Symbol @\ By definition these indices have the following meaning,
+and have nothing to do with the actual representation of symbols
+in a given implementation:
+@begin(description)
+0 @\ Alter value cell.
+
+1 @\ Alter function cell.
+
+2 @\ Alter property list (!).
+@end(description)
+
+Vector (of any kind) @\ Alter component number @i[index] of the vector.
+
+String @\ Alter character number @i[index] of the string.
+@end(description)
+
+53 @f[ ] @f[FOP-EVAL] @f[ ] @PushArrow @f[ ] stack @\
+Pop an item from the stack and evaluate it (give it to @f[EVAL]).
+Push the result back onto the stack.
+
+54 @f[ ] @f[FOP-EVAL-FOR-EFFECT] @\
+Pop an item from the stack and evaluate it (give it to @f[EVAL]).
+The result is ignored.
+
+55 @f[ ] @f[FOP-FUNCALL] @f[ ] @i[nargs](1) @f[ ] @PushArrow @f[ ] stack @\
+Pop @i[nargs]+1 items from the stack and apply the last one popped
+as a function to
+all the rest as arguments (the first one popped being the last argument).
+Push the result back onto the stack.
+
+56 @f[ ] @f[FOP-FUNCALL-FOR-EFFECT] @f[ ] @i[nargs](1) @\
+Pop @i[nargs]+1 items from the stack and apply the last one popped
+as a function to
+all the rest as arguments (the first one popped being the last argument).
+The result is ignored.
+
+57 @f[ ] @f[FOP-CODE-FORMAT] @f[ ] @i[id](1) @\
+The operand @i[id] is a unique identifier specifying the format
+for following code objects.  The operations @f[FOP-CODE]
+and its relatives may not
+occur in a group until after @f[FOP-CODE-FORMAT] has appeared;
+there is no default format.  This is provided so that several
+compiled code formats may co-exist in a file, and so that a loader
+can determine whether or not code was compiled by the correct
+compiler for the implementation being loaded into.
+So far the following code format identifiers are defined:
+@begin(description)
+0 @\ PERQ
+
+1 @\ VAX
+
+3 @\ @value(DinkyMachine)
+@end(description)
+
+58 @f[ ] @f[FOP-CODE] @f[ ] @i[nitems](4) @f[ ] @i[size](4) @f[ ]
+@i[code](@i[size]) @f[ ] @PushArrow @f[ ] stack @\
+A compiled function is constructed and pushed onto the stack.
+This object is in the format specified by the most recent
+occurrence of @f[FOP-CODE-FORMAT].
+The operand @i[nitems] specifies a number of items to pop off
+the stack to use in the "boxed storage" section.  The operand @i[code]
+is a string of bytes constituting the compiled executable code.
+
+59 @f[ ] @f[FOP-SMALL-CODE] @f[ ] @i[nitems](1) @f[ ] @i[size](2) @f[ ]
+@i[code](@i[size]) @f[ ] @PushArrow @f[ ] stack @\
+A compiled function is constructed and pushed onto the stack.
+This object is in the format specified by the most recent
+occurrence of @f[FOP-CODE-FORMAT].
+The operand @i[nitems] specifies a number of items to pop off
+the stack to use in the "boxed storage" section.  The operand @i[code]
+is a string of bytes constituting the compiled executable code.
+
+60 @f[ ] @f[FOP-STATIC-HEAP] @\
+Until further notice operations which allocate data structures
+may allocate them in the static area rather than the dynamic area.
+(The default area for allocation is the dynamic area; this
+default is reset whenever a new group is begun.
+This command is of an advisory nature; implementations with no
+static heap can ignore it.)
+
+61 @f[ ] @f[FOP-DYNAMIC-HEAP] @\
+Following storage allocation should be in the dynamic area.
+
+62 @f[ ] @f[FOP-VERIFY-TABLE-SIZE] @f[ ] @i[size](4) @\
+If the current size of the table is not equal to @i[size],
+then an inconsistency has been detected.  This operation
+is inserted into a Fasload file purely for error-checking purposes.
+It is good practice for a compiler to output this at least at the
+end of every group, if not more often.
+
+63 @f[ ] @f[FOP-VERIFY-EMPTY-STACK] @\
+If the stack is not currently empty,
+then an inconsistency has been detected.  This operation
+is inserted into a Fasload file purely for error-checking purposes.
+It is good practice for a compiler to output this at least at the
+end of every group, if not more often.
+
+64 @f[ ] @f[FOP-END-GROUP] @\
+This is the last operation of a group.	If this is not the
+last byte of the file, then a new group follows; the next
+nine bytes must be "@f[FASL FILE]".
+
+65 @f[ ] @f[FOP-POP-FOR-EFFECT] @f[ ] stack @f[ ] @PushArrow @f[ ] @\
+One item is popped from the stack.
+
+66 @f[ ] @f[FOP-MISC-TRAP] @f[ ] @PushArrow @f[ ] stack @\
+A trap object is pushed onto the stack.
+
+67 @f[ ] @f[FOP-READ-ONLY-HEAP] @\
+Following storage allocation may be in a read-only heap.
+(For symbols, the symbol itself may not be in a read-only area,
+but its print name (a string) may be.
+This command is of an advisory nature; implementations with no
+read-only heap can ignore it, or use a static heap.)
+
+68 @f[ ] @f[FOP-CHARACTER] @f[ ] @i[character](3) @f[ ] @PushArrow @f[ ] stack @\
+The three bytes specify the 24 bits of a CMU Common Lisp character object.
+The bytes, lowest first, represent the code, control, and font bits.
+A character is constructed and pushed onto the stack.
+
+69 @f[ ] @f[FOP-SHORT-CHARACTER] @f[ ] @i[character](1) @f[ ]
+@PushArrow @f[ ] stack @\
+The one byte specifies the lower eight bits of a CMU Common Lisp character
+object (the code).  A character is constructed with zero control
+and zero font attributes and pushed onto the stack.
+
+70 @f[ ] @f[FOP-RATIO] @f[ ] @PushArrow @f[ ] stack @\
+Creates a ratio from two integers popped from the stack.
+The denominator is popped first, the numerator second.
+
+71 @f[ ] @f[FOP-COMPLEX] @f[ ] @PushArrow @f[ ] stack @\
+Creates a complex number from two numbers popped from the stack.
+The imaginary part is popped first, the real part second.
+
+72 @f[ ] @f[FOP-LINK-ADDRESS-FIXUP] @f[ ] @i[nargs](1) @f[ ] @i[restp](1)
+@f[ ] @i[offset](4) @f[ ] @PushArrow @f[ ] stack @\
+Valid only for when FOP-CODE-FORMAT corresponds to the Vax or the
+@value(DinkyMachine).
+This operation pops a symbol and a code object from the stack and pushes
+a modified code object back onto the stack according to the needs of the
+runtime code linker on the Vax or @value(DinkyMachine).
+
+73 @f[ ] @f[FOP-LINK-FUNCTION-FIXUP] @f[ ] @i[offset](4) @f[ ]
+@PushArrow @f[ ] stack @\
+Valid only for when FOP-CODE-FORMAT corresponds to the Vax or the
+@value(DinkyMachine).
+This operation pops a symbol and a code object from the stack and pushes
+a modified code object back onto the stack according to the needs of the
+runtime code linker on the Vax or the @value(DinkyMachine).
+
+74 @f[ ] @f[FOP-FSET] @f[ ] @\
+Pops the top two things off of the stack and uses them as arguments to FSET
+(i.e. SETF of SYMBOL-FUNCTION).
+
+128 @f[ ] @f[FOP-LINK-ADDRESS-FIXUP] @f[ ] @i[nargs] @f[ ] @i[flag] @f[ ]
+@i[offset] @f[ ]@\Valid only when FOP-CODE-FORMAT corresponds to the
+@value(DinkyMachine).  This operation pops a symbol and a function object
+off the stack.  The code vector in the function object is modified
+according to the needs of the runtime code linker of the @value(DinkyMachine)
+and pushed back on the stack.  This FOP links in calls to other functions.
+
+129 @f[ ] @f[FOP-MISCOP-FIXUP] @f[ ] @i[index](2) @f[ ] @i[offset](4) @f[ ]@\
+Valid only when FOP-CODE-FORMAT corresponds to the @value(DinkyMachine).
+This operation pops a code object from the stack and pushes a
+modified code object back onto the stack according to the needs of
+the runtime code linker on the @value(DinkyMachine).  This FOP links in
+calls to the assembler language support routines.
+
+130 @f[ ] @f[FOP-ASSEMBLER-ROUTINE] @f[ ] @i[code-length] @f[ ] @\
+Valid only when FOP-CODE-FORMAT corresponds to the @value(DinkyMachine).
+This operation loads assembler code into the assembler code space of the
+currently running Lisp.
+
+131 @f[ ] @f[FOP-FIXUP-MISCOP-ROUTINE] @f[ ]@\Valid only when FOP-CODE-FORMAT
+corresponds to the @value(DinkyMachine).  This operation pops a list of
+external references, a list of external labels defined, the name, and the
+code address off the stack.  This information is saved, so that after
+everything is loaded, all the external references can be resolved.
+
+132 @f[ ] @f[FOP-FIXUP-ASSEMBLER-ROUTINE] @f[ ]@\is similar to
+FOP-FIXUP-MISCOP-ROUTINE, except it is for internal assembler routines
+rather than ones visible to Lisp.
+
+133 @f[ ] @f[FOP-FIXUP-USER-MISCOP-ROUTINE] @f[ ]@\is similar to
+FOP-FIXUP-MISCOP-ROUTINE, except it is for routines written by users who
+have an extremely good understanding of the system internals.
+
+134 @f[ ] @f[FOP-USER-MISCOP-FIXUP] @f[ ] @i[offset](4) @f[ ]@\is similar
+to FOP-MISCOP-FIXUP, but is used to link in user defined miscops.
+
+255 @f[ ] @f[FOP-END-HEADER] @\ Indicates the end of a group header, as described above.
+@end(description)
+
+@Appendix[Building CMU Common Lisp]
+
+@section(Introduction)
+This document explains how to build a working Common Lisp from source code on
+the IBM RT PC under the Mach operating system.  You should already have a
+working Common Lisp running on an IBM RT PC before trying to build a new Common
+Lisp.
+
+Throughout this document the following terms are used:
+@begin(Description)
+Core file@\A core file is a file containing an image of a Lisp system.  The
+core file contains header information describing where the data in the rest of
+the file should be placed in memory.  There is a simple C program which reads a
+core file into memory at the correct locations and then jumps to a location
+determined by the contents of the core file.  The C code includes the X
+window system version 10 release 4 which may be called from Lisp.
+
+
+Cold core file @\A cold core file contains enough of the Lisp system to make it
+possible to load in the rest of the code necessary to generate a full Common
+Lisp.  A cold core file is generated by the program Genesis.
+
+Miscops@\Miscops are assembler language routines that are used to support
+compiled Lisp code.  A Lisp macro assembler provides a
+convenient mechanism for writing these assembler language routines.
+
+Matchmaker@\Matchmaker is a program developed to automatically generate
+remote procedure call interfaces between programs.  Matchmaker accepts
+a description of a remote procedure call interface and generates code
+that implements it.
+@end(Description)
+
+There are many steps required to go from sources to a working Common Lisp
+system.  Each step will be explained in detail in the following sections.
+It is possible to perform more than one step with one invocation of Lisp.
+However, I recommend that each step be started with a fresh Lisp.  There
+is some small chance that something done in one step will adversely affect
+a following step if the same Lisp is used.  The scripts for each
+step assume that you are in the user package which is the default when
+Lisp first starts up.  If you change to some other package, some of these
+steps may not work correctly.
+
+In many of the following steps, there are lines setting up search lists so that
+command files know where to find the sources.  What I have done is create a
+init.lisp file that sets up these search lists for me.  This file is
+automatically loaded from the user's home directory (as determined by the
+@b[HOME] environment variable) when you start up Lisp.  Note that my init.lisp
+file is included with the sources.  You may have to modify it, if you change
+where the lisp sources are.
+
+@section(Installing Source Code)
+With this document, you should also have received a tape cartridge in tar
+format containing the complete Common Lisp source code.  You should create
+some directory where you want to put the source code.  For the following
+discussion, I will assume that the source code lives in the directory
+/usr/lisp.  To install the source code on your machine, issue the following
+commands:
+@begin(Example)
+cd /usr/lisp
+tar xvf <tape device>
+@end(Example)
+The first command puts you into the directory where you want the source code,
+and the second extracts all the files and sub-directories from the tape into
+the current directory.  <Tape device> should be the name of the tape device on
+your machine, usually /dev/st0.
+
+The following sub-directories will be created by tar:
+@begin(Description)
+bin@\contains a single executable file, lisp, which is a C program
+used to start up Common Lisp.
+
+clc@\contains the Lisp source code for the Common Lisp compiler and assembler.
+
+code@\contains the Lisp source code that corresponds to all the functions,
+variables, macros, and special forms described in @i[Common Lisp: The Language]
+by Guy L. Steele Jr., as well as some Mach specific files.
+
+hemlock@\contains the Lisp source code for Hemlock, an emacs-like editor
+written completely in Common Lisp.
+
+icode@\contains Matchmaker generated code for interfaces to Inter Process
+Communication (IPC) routines.  This code is used to communicate with other
+processes using a remote procedure call mechanism.  Under Mach, all the
+facilities provided by Mach beyond the normal Berkeley Unix 4.3 system
+calls are accessed from Lisp using this IPC mechanism.  Currently, the
+code for the Mach, name server, Lisp typescript, and Lisp eval server
+interfaces reside in this directory.
+
+idefs@\contains the Matchmaker definition files used to generate the Lisp
+code in the icode directory.
+
+lib@\contains files needed to run Lisp.  The file lisp.core is known as a
+Lisp core file and is loaded into memory by the lisp program mentioned
+above in the entry for the bin directory.  This file has a format which
+allows it to be mapped into memory at the correct locations.  The files
+spell-dictionary.text and spell-dictionary.bin are the text and binary
+form of a dictionary, respectively, used by Hemlock's spelling checker and
+corrector.  The two files hemlock.cursor and hemlock.mask are used by
+Hemlock when running under the X window system.
+
+miscops@\contains the Lisp assembler source code for all the miscops
+that support low level Lisp functions, such as storage allocation,
+complex operations that can not performed in-line, garbage collection, and
+other operations.  These routines are written in assembler, so that they
+are as efficient as possible.  These routines use a very short calling
+sequence, so calling them is very cheap compared to a normal Lisp
+function call.
+
+mm@\contains the Lisp source code for the Matchmaker program.  This program
+is used to generate the Lisp source code files in icode from the corresponding
+matchmaker definitions in idefs.
+
+pcl@\contains the Lisp source code for a version of the Common Lisp Object
+System (originally Portable Common Loops),
+an object oriented programming language built on top of Common Lisp.
+
+X@\contains the C object files for X version 10 release 4 C library
+routines.  These are linked with the lisp startup code, so that X is
+available from Lisp.
+
+scribe@\contains Scribe source and postscript output for the manuals
+describing various aspects of the CMU Common Lisp implementation.
+
+demos@\contains the Lisp source code for various demonstration programs.
+This directory contains the Gabriel benchmark set (bmarks.lisp) and
+a sub-directory containing the Soar program which is also used for
+benchmarking purposes.  There may be other programs and/or sub-directories
+here that you may look at.
+@end(Description)
+These directories contain source files as well as Lisp object files.
+This means it is not necessary to go through all the steps to
+build a new a Common Lisp, only those steps that are affected by
+a modification to the sources.  For example, modifying the compiler
+will require recompiling everything.  Modifying a miscop file should
+require only reassembling that particular file and rebuilding the
+cold core file and full core file.
+
+As well as the directories mentioned above, there are also several files
+contained in the top-level directory.  These are:
+@begin(Description)
+init.lisp@\is a Lisp init file I use.  This sets up some standard search
+lists, as well as defines a Hemlock mode for editing miscop
+source files.
+
+lisp.c@\contains the C code used to start up the lisp core image under Mach.
+
+lispstart.s@\contains some assembler language code that is invoked by lisp.c
+to finish the process of starting up the lisp process.
+
+makefile@\contains make definitions for compiling lisp.c and lispstart.s
+into the lisp program.
+
+rg@\contains some adb commands that can be read into adb while debugging a lisp
+process.  It prints out all the registers, the name of the currently
+executing Lisp function, and sets an adb variable to the current stack frame
+which is used by the following file.
+
+st@\contains some adb commands that can be read into adb while debugging
+a lisp process.  It prints out a Lisp stack frame and the name of the
+function associated with the stack frame.  It also updates the adb variable
+mentioned above to point to the next stack frame.  Repeatedly reading this
+file into adb will produce a backtrace of all the active call frames
+on the Lisp stack.
+
+ac@\contains some adb commands that print out the current values of the
+active catch pointer.  This points to the head of a list of catch frames
+that exist on the control stack.
+
+cs@\contains some adb commands that print out the contents of a catch
+frame.  Reading cs into adb several times in a row (after reading ac once)
+will print out the catch frames in order.
+@end(Description)
+
+@section(Compiling the Lisp Startup Program)
+To compile the lisp start up program, you should be in the top level directory
+of the sources (/usr/lisp) and type:
+@begin(Example)
+make lisp
+@end(Example)
+This will compile the file lisp.c, assemble the file lispstart.s and produce
+an executable file lisp.  Currently the default location for the lisp core
+file is /usr/misc/.lisp/lib/lisp.core.  If you want to change this default
+location, edit the file lisp.c and change the line
+@begin(Example)
+#define COREFILE "/usr/misc/.lisp/lib/lisp.core"
+@end(Example)
+to refer to the file where you intend to put the core file.
+
+This step takes a few seconds.
+
+@section(Assembling Assembler routines)
+The standard core image includes a Lisp macro assembler.  To assemble all
+the miscops, the following steps should be performed:
+@begin(Example)
+(compile-file "/usr/lisp/clc/miscasm.lisp")
+(load "/usr/lisp/clc/miscasm.fasl")
+(setf (search-list "msc:") '("/usr/lisp/miscops/"))
+(clc::asm-files)
+@end(Example)
+The first line compiles a file that contains a couple of functions used to
+assemble miscop source files.  The second line loads the resulting compiled
+file into the currently executing core image.  The third line defines the
+msc search list which is used by the function clc::asm-files to locate
+the miscop sources.  The terminal will display information as each file
+is assembled.  For each file a .fasl, a .list, and an .err file will be
+generated in /usr/lisp/miscops.
+
+This step takes about half an hour.
+
+@section(Compiling the Compiler)
+
+To compile the compiler is simple:
+@begin(Example)
+(setf (search-list "clc:") '("/usr/lisp/clc/"))
+(load "clc:compclc.lisp")
+@end(Example)
+The first line just sets up a search list variable clc, so that the file
+compclc.lisp can find the compiler sources.  The terminal will display
+information as each file is assembled.  For each file a .fasl and an .err file
+will be generated.  A log of the compiler output is also displayed on the
+terminal.
+
+This step takes about forty-five minutes.
+
+@section(Compiling the Lisp Sources)
+
+Compiling the Lisp source code is also easy:
+@begin(Example)
+(setf (search-list "code:") '("/usr/lisp/code/"))
+(load "code:worldcom.lisp")
+@end(Example)
+Again, the first line defines a search list variable, so that the file
+worldcom.lisp can find the Lisp sources.  As each file is compiled, the
+name of the file is printed on the terminal.  For each file a .fasl will be
+generated.  Also, a single error log will be generated in the file
+code:compile-lisp.log.
+
+This step takes about an hour and a half.
+
+@section(Compiling Hemlock)
+
+Compiling the Hemlock source code is done as follows:
+@begin(Example)
+(setf (search-list "hem:") '("/usr/lisp/hemlock/"))
+(load "hem:ctw.lisp")
+@end(Example)
+Again, the first line defines a search list variable, so that ctw.lisp can
+find the Hemlock sources.  As each file is compiled, the name of the file is
+printed on the terminal.  For each file a .fasl will be generated.  Also, a
+single error log will be generated in the file hem:lossage.log.
+
+This step takes about forty-five minutes.
+
+@section(Compiling Matchmaker)
+Compiling the matchmaker sources is done as follows:
+@begin(Example)
+(setf (search-list "mm:") '("/usr/lisp/mm"))
+(compile-file "mm:mm.lisp")
+(load "mm:mm.fasl")
+(compile-mm)
+@end(Example)
+The first line sets up a search list, so that the matchmaker sources can be
+found.  The second line compiles the file containing a function for compiling
+the matchmaker sources.  The third line loads the file just
+compiled, and the final line invokes the function compile-mm which compiles the
+matchmaker sources.  For each file, a .fasl and .err file is generated.  Also,
+a log of the compiler output is printed to the terminal.
+
+This step takes about 15 minutes
+
+@section(Generating Lisp Source Files from Matchmaker Definition Files)
+The following sequence of commands is necessary to generate the Lisp
+files for the Mach interface:
+@begin(Example)
+(setf (search-list "mm:") '("/usr/lisp/mm/"))
+(setf (search-list "idefs:") '("/usr/lisp/idefs/"))
+(setf (search-list "icode:") '("/usr/lisp/icode/"))
+(setf (search-list "code:") '("/usr/lisp/code/"))
+(setf (default-directory) "/usr/lisp/icode/")
+(load "code:mm-interfaces.lisp")
+@end(Example)
+The first four lines set up search lists for mm (matchmaker sources), idefs
+(matchmaker interface definition files), icode (Lisp matchmaker interface
+sources), and code (Lisp code sources).  The fifth line changes the current
+working directory to be /usr/lisp/icode.  This is where the output from
+matchmaker will be placed.  And finally, the last line invokes matchmaker on
+the matchmaker definition files for all the interfaces.
+
+Matchmaker generates three files for each interface XXX:
+@begin(Description)
+XXXdefs.lisp@\contains constants and record definitions for the interface.
+
+XXXmsgdefs.lisp@\contains definitions of offsets to important fields in the
+messages that are sent to and received from the interface.
+
+XXXuser.lisp@\contains code for each remote procedure, that sends a message
+to the server and receives the reply from the server (if appropriate).
+Each of these functions returns one or more values.  The first value
+returned is a general return which specifies whether the remote procedure
+call succeeded or gives an indication of why it failed.  Other values may
+be returned depending on the particular remote procedure.  These values are
+returned using the multiple value mechanism of Common Lisp.
+@end(Description)
+
+This step takes about five minutes.
+
+@section(Compiling Matchmaker Generated Lisp Files)
+To compile the matchmaker generated Lisp files the following steps should
+be performed:
+@begin(Example)
+(setf (search-list "code:") '("/usr/lisp/code/"))
+(setf (search-list "icode:") '("/usr/lisp/icode/"))
+(load "code:comutil.lisp")
+@end(Example)
+The first two lines set up search lists for the code and icode directory.
+The final line loads a command file that compiles the Mach interface
+definition in the correct order.  Note that once the files are compiled,
+the XXXmsgdefs files are no longer needed.  The file
+/usr/lisp/icode/lossage.log contains a listing of all the error messages
+generated by the compiler.
+
+This step takes about fifteen minutes.
+
+@section(Compiling the Common Lisp Object System)
+
+To compile the Common Lisp Object System (CLOS) do the following:
+@begin(Example)
+(setf (search-list "pcl:") '("/usr/lisp/pcl/"))
+(rename-package (find-package "CLOS") "OLD-CLOS")
+(compile-file "pcl:defsys.lisp")
+(load "pcl:defsys.fasl")
+(clos::compile-pcl)
+@end(Example)
+The first line sets up a search list as usual.  The second line renames the
+CLOS package to be the OLD-CLOS package.  This is so that the current version
+of CLOS doesn't interfere with the compilation process. The third line
+compiles a file containing some functions for building CLOS.  The fourth
+line loads in the result of the previous compilation.  The final line
+compiles all the CLOS files necessary for a working CLOS system. 
+
+The file /usr/lisp/pcl/test.lisp is a file that contains some test functions.
+To run it through CLOS build a new Lisp and start up a fresh Lisp
+resulting from the build and do the following:
+@begin(Example)
+(in-package 'clos)
+(compile-file "/usr/lisp/pcl/test.lisp")
+(load "/usr/lisp/pcl/test.fasl")
+@end(Example)
+This sequence of function calls puts you in the CLOS package, compiles the
+test file and then loads it.  As the test file is loaded, it executes several
+tests.  It will print out a message specifying whether each test passed or
+failed.
+
+Currently, CLOS is built into the standard core.
+
+This step takes about 30 minutes.
+
+@section(Compiling Genesis)
+To compile genesis do the following:
+@begin(Example)
+(compile-file "/usr/lisp/clc/genesis.lisp")
+@end(Example)
+Genesis is used to build a cold core file.  Compiling Genesis takes about five
+minutes.
+
+@section(Building a Cold Core File)
+Once all the files have been assembled or compiled as described above, it is
+necessary to build a cold core file as follows:
+@begin(Example)
+(setf (search-list "code:") '("/usr/lisp/code/"))
+(setf (search-list "icode:") '("/usr/lisp/icode/"))
+(setf (search-list "msc:") '("/usr/lisp/miscops/"))
+(load "/usr/lisp/clc/genesis.fasl")
+(load "code:worldbuild.lisp")
+@end(Example)
+The first three lines set up search lists for the code, icode, and miscops
+subdirectories.  The fourth line loads in the program Genesis which builds
+the cold core file.  The last line calls Genesis on a list of the files that
+are necessary to build the cold core file.  As each file is being processed,
+its name is printed to the terminal.  Genesis generates two files:
+/usr/lisp/ilisp.core and /usr/lisp/lisp.map.  Ilisp.core is the cold core
+file and lisp.map is a file containing the location of all the functions
+and miscops in the cold core file.  Lisp.map is useful for debugging the
+cold core file.
+
+This step takes from about fifteen minutes.
+
+@section(Building a Full Common Lisp)
+The cold core file built above does not contain some of the more useful
+programs such as the compiler and hemlock.  To build these into a core, it is
+necessary to do the following:
+@begin(Example)
+lisp -c /usr/lisp/ilisp.core
+(in-package "USER")
+(load (open "/usr/lisp/code/worldload.lisp"))
+@end(Example)
+The first line invokes the lisp startup program specifying the cold core
+file just built as the core file to load.  This cold core file is set up
+to do a significant amount of initialization and it is quite possible that
+some bug will occur during this initialization process.  After about a
+minute, you should get a prompt of the form:
+@begin(Example)
+CMU Common Lisp kernel core image 2.7(?).
+[You are in the Lisp Package.]
+*
+@end(Example)
+The following two lines should then be entered.  The first of these puts
+you into the User package which is the package you should be in when the
+full core is first started up.  It is necessary to add this line, because
+the current package is rebound while a file is loaded.  The last line loads
+in a file that loads in the compiler, hemlock, and some other files not yet
+loaded.  The open call is @b[essential] otherwise when the full core is
+started up, load will try to close the file and probably invalidate memory
+that is needed.  When load is passed a stream, it does not automatically
+close the stream.  With a file name it now does after a recent bug fix.
+This file prompts for the versions of the Lisp system, the compiler, and
+hemlock.  You should enter versions that make sense for your installation.
+It then purifies the core image.  Up to this point most of the Lisp system
+has been loaded into dynamic space.  Only a few symbols and some other data
+structures are in static space.  The process of purification moves Lisp
+objects into static and read-only space, leaving very little in dynamic
+space.  Having the Lisp system in static and read-only space reduces the
+amount of work the garbage collector has to do.  Only those objects needed
+in the final core file are retained.  Finally, a new core file is generated
+and is written to the file /usr/lisp/nlisp.core.  Also, the currently
+running Lisp should go through the default initialization process, finally
+prompting for input with an asterisk.  At this point you have successfully
+built a new core file containing a complete Common Lisp implementation.
+
+This step takes about thirty minutes.
+
+@section(Debugging)
+Debugging Lisp code is much easier with a fully functional Lisp.  However, it
+is quite possible that a change made in the system can cause a bug to happen
+while running the cold core file.  If this happens, it is best to use adb to
+track down the problem.  Unfortunately, the core file (i.e., the
+remains of a process normally created by Unix when a process dies) generated by
+such a bug will be of no use.  To get some useful information, follow these
+steps:
+@begin(Enumerate)
+Look at the file /usr/lisp/lisp.map and find the entry points for the
+miscop routines error0, error1, and error2.  These entry points are
+used to invoke the Lisp error system from the miscops.  Write down
+the numbers beside these names.  They are the addresses (in hex) of where
+the miscops are located when the cold core file is loaded into memory.
+
+Run adb on the lisp file, i.e.:
+@begin(example)
+adb lisp
+@end(Example)
+
+Set a breakpoint at the lispstart entry point:
+@begin(Example)
+lispstart:b
+@end(Example)
+
+Start the lisp program running, telling it to use ilisp.core (I'm
+assuming you're in /usr/lisp):
+@begin(Example)
+:r -c ilisp.core
+@end(Example)
+
+After a while, you will hit the lispstart breakpoint.  The core file has been
+mapped into memory, but control is still in the C startup code.  At this point,
+you should enter breakpoints for all the error entry points described above.
+
+Continue running the program by typing :c.  Shortly after this, the C lisp
+program will give up control to Lisp proper.  Lisp will start doing its
+initialization and will probably hit one of the error break points.
+At that point you can look around at the state and try and discover
+what has gone wrong.  Note that the two files rg and st are useful at this
+point.  Also, you should look at the document @i[Internal Design of Common
+Lisp on the IBM RT PC] by David B. McDonald, Scott E. Fahlman, and Skef
+Wholey so that you know the internal data structures.
+@end(Enumerate)
+
+@section(Running the Soar Benchmark)
+To compile the soar benchmark, you should do the following:
+@begin(Example)
+(compile-file "/usr/lisp/demos/soar/soar.lisp")
+@end(Example)
+
+To run the benchmark, you should start up a fresh Lisp and do the following:
+@begin(Example)
+(load "/usr/lisp/demos/soar/soar.fasl")
+(load "/usr/lisp/demos/soar/default.soar")
+(load "/usr/lisp/demos/soar/eight.soar")
+(user-select 'first)
+(init-soar)
+(time (run))
+@end(Example)
+The first two lines load in the standard Soar system.  The third line loads in
+information about the eight puzzle which is a standard Soar puzzle that has
+been run on several different machines.  The fourth line sets up the puzzle
+conditions so that it will select a goal to work on automatically.  The fifth
+line initializes Soar's working memory, etc.  The final line is the one that
+actually runs the benchmark.  Soar prints out a fair amount of information as
+it solves the puzzle.  The final state should be numbered 143 when it finishes.
+The time macro prints out information about information various resources after
+the eight puzzle has run.
+
+@section(Summary)
+I have tried to present sufficient information here to allow anyone to be
+able to build a Common Lisp system under Mach from the sources.  I am sure
+there are many tricks that I have learned to use to reduce the amount of grief
+necessary to build a system.  My best recommendation is to go slowly.  Start
+by building a system from the sources provided on the tape.  Make sure you
+are comfortable doing that before you try modifying anything.
+
+Some hints on building the system which you may find useful:
+@begin(Itemize)
+If you change the compiler, you will have to recompile all the sources before
+the change is reflected in a system.  Changing the compiler is probably the
+most dangerous change you can make, since an error here means that
+nothing will work.  In particular, this is the time you are going to need
+to get familiar with adb and the internal structure of the Lisp, since a
+serious error in the compiler will show up during the initialization of the
+cold core file.
+
+Changing the miscops should be done with care.  They follow a fairly rigid
+convention and you should understand all the information provided in
+@i[Internal Design of Common Lisp on the IBM RT PC] before making any changes
+to miscops.  You will probably need to get familiar with adb to debug some of
+the changes.  Note that this requires building a new cold core file and a final
+core file before the change is reflected in the system.
+
+Changing sources in the code directory should be fairly straight forward.  The
+only time this will cause trouble is if you change something that a lot of 
+files depend on in which case you will have to recompile everything and build
+a new cold core file and a core file.
+
+Changing hemlock should have no adverse effect on system integrity.
+
+If you make a fairly major change, it is a good idea to go through the complete
+process of building a core file at least two or three times.  If things are
+still working at the end of this, your change is probably correct and shouldn't
+cause any serious trouble.
+
+Finally, always keep at least one backup copy of a good core image around.
+If you build a bad core file over an existing one and can't back up, it is
+possible that you may not be able to recover from a serious error.
+@end(Itemize)
-- 
GitLab