1844 lines
64 KiB
HTML
1844 lines
64 KiB
HTML
|
<html>
|
||
|
<head>
|
||
|
<!-- This file has been generated by unroff 1.0, 03/21/96 19:29:31. -->
|
||
|
<!-- Do not edit! -->
|
||
|
<link rev="made" href="mailto:net@informatik.uni-bremen.de">
|
||
|
<title>An `ms' document</title>
|
||
|
</head><body>
|
||
|
<!-- $Revision: 1.12 $ -->
|
||
|
<h1>
|
||
|
unroff 1.0 Programmer's Manual
|
||
|
</h1>
|
||
|
<p>
|
||
|
<i>Oliver Laumann
|
||
|
<br>
|
||
|
</i><hr>
|
||
|
<p>
|
||
|
<i>unroff
|
||
|
</i>is a programmable, extensible troff translator that is useful for
|
||
|
converting documents with embedded troff markup into another
|
||
|
format.<tt> </tt>
|
||
|
Although
|
||
|
<i>unroff
|
||
|
</i>has been designed with higher-level, structure-oriented target
|
||
|
languages (such as SGML) in mind, it fully supports all constructs
|
||
|
and idiosyncrasies of ordinary troff, so that even low-level
|
||
|
formatting requests can be handled correctly if desired.<tt> </tt>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Translation rules for a specific output format and knowledge about
|
||
|
existing troff macro packages are not hard-wired in
|
||
|
<i>unroff</i>,
|
||
|
instead, the translation is controlled by a user-supplied set
|
||
|
of procedures written in the
|
||
|
<a href="http://www-swiss.ai.mit.edu/scheme-home.html"><i>Scheme</i> programming language</a>.<tt> </tt>
|
||
|
Interpretation of the procedures is facilitated by a full Scheme
|
||
|
interpreted embedded in
|
||
|
<i>unroff</i>.<tt> </tt>
|
||
|
This manual describes the Scheme primitives provided by
|
||
|
<i>unroff
|
||
|
</i>that can be used to customize the translation rules implemented
|
||
|
by existing back-ends and to write new ones for new output formats.<tt> </tt>
|
||
|
<hr>
|
||
|
<h2>1. <tt> </tt>Additional Documentation
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>For a general overview of
|
||
|
<i>unroff
|
||
|
</i>and a description from the user's perspective, please read the
|
||
|
<a href="./unroff.1.html">manual page</a>
|
||
|
<i>unroff</i>(1)
|
||
|
that accompanies the distribution.<tt> </tt>
|
||
|
In addition, there exists one manual page for each output format
|
||
|
for which a back-end is provided, and another one for each
|
||
|
combination of output format and troff macro package explaining
|
||
|
the translation rules associated with the individual macros.<tt> </tt>
|
||
|
For example, the back-end for the Hypertext Markup Language (HTML)
|
||
|
that is part of the distribution and that supports the
|
||
|
<b>-man
|
||
|
</b>and
|
||
|
<b>-ms
|
||
|
</b>macros comes with these manual pages:
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
<a href="./unroff-html.1.html">unroff-html(1)</a>
|
||
|
<a href="./unroff-html-man.1.html">unroff-html-man(1)</a>
|
||
|
<a href="./unroff-html-ms.1.html">unroff-html-ms(1)</a>
|
||
|
</pre>
|
||
|
</dl>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>This text assumes familiarity with the basic troff and Scheme concepts.<tt> </tt>
|
||
|
For a troff manual, refer to the documentation provided by
|
||
|
your UNIX system's vendor.<tt> </tt>
|
||
|
As
|
||
|
<i>unroff
|
||
|
</i>supports a number of troff extensions introduced by the free
|
||
|
<i>groff
|
||
|
</i>formatter (which is part of the GNU project), you may want to read the
|
||
|
manual page
|
||
|
<i>troff</i>(1)
|
||
|
that is included in the groff distribution.<tt> </tt>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt><i>unroff
|
||
|
</i>is centered around
|
||
|
<i>Elk</i>,
|
||
|
the Scheme-based Extension Language Kit.<tt> </tt>
|
||
|
For a description of the Elk-specific Scheme language features
|
||
|
please refer to the documentation included in the Elk distribution
|
||
|
(which is freely available).<tt> </tt>
|
||
|
An overview of Elk can be found in:
|
||
|
Oliver Laumann and Carsten Bormann, Elk: The Extension Language Kit,
|
||
|
<i>USENIX Computing Systems</i>,
|
||
|
vol. 7, no. 4, pp. 419-449, 1994.<tt> </tt>
|
||
|
The Scheme language is described in several textbooks; and the
|
||
|
Revised^4 Report on the Algorithmic Language Scheme, on which
|
||
|
the IEEE Standard for Scheme is based, can be downloaded from
|
||
|
several major FTP sites.<tt> </tt>
|
||
|
<h2>2. <tt> </tt>Where to Place Scheme Code?
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt><i>unroff
|
||
|
</i>accepts Scheme code in a number of places.<tt> </tt>
|
||
|
First, several Scheme files are loaded on startup:
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
scm/troff.scm
|
||
|
scm/<i>format</i>/common.scm
|
||
|
scm/<i>format</i>/<i>package</i>.scm
|
||
|
~/.unroff
|
||
|
</pre>
|
||
|
</dl>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>The first three path names are relative to a site-specific library
|
||
|
directory where the files have been installed by the system
|
||
|
administrator.<tt> </tt>
|
||
|
``troff.scm'' contains definitions that are independent of the
|
||
|
actual output format and troff macro-package; and the
|
||
|
file ``.unroff'' (loaded from the caller's home directory) typically
|
||
|
contains Scheme code to define user-preferences and to tailor
|
||
|
and extend the translation rules implemented by the files loaded
|
||
|
from a central location.<tt> </tt>
|
||
|
See the
|
||
|
<a href="./unroff.1.html">manual page</a>
|
||
|
<i>unroff</i>(1)
|
||
|
for more information.<tt> </tt>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Additional files with user-supplied Scheme definitions
|
||
|
(e.g. translation rules for user-defined macros) can be passed to
|
||
|
<i>unroff
|
||
|
</i>by mentioning them in the command line.<tt> </tt>
|
||
|
In general, troff input files and Scheme source files can be mixed
|
||
|
arbitrarily when calling
|
||
|
<i>unroff</i>.<tt> </tt>
|
||
|
Finally, Scheme code can be embedded directly in the troff documents
|
||
|
by means of the new ``.##'' troff request and the corresponding
|
||
|
extension to the ``.ig'' request as explained in the
|
||
|
<a href="./unroff.1.html">manual page</a>.<tt> </tt>
|
||
|
Such inline Scheme code is executed on-the-fly when it is encountered
|
||
|
by the parser while processing the document.<tt> </tt>
|
||
|
<h2>3. <tt> </tt><a name=".events">Events and Event Handling</a>
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt><i>unroff
|
||
|
</i>interprets a troff document as a sequence of chunks of normal
|
||
|
text and interspersed ``events''.<tt> </tt>
|
||
|
Plain text is usually just copied to the current output (a file or
|
||
|
standard output).<tt> </tt>
|
||
|
The output produced for an event is determined by an ``event
|
||
|
handler'' (usually a Scheme procedure) that can be associated
|
||
|
with each event.<tt> </tt>
|
||
|
If no event handler can be found for an event encountered in the
|
||
|
currently processed document (with a few exceptions), a warning message
|
||
|
is displayed and the input that triggered the event is skipped
|
||
|
(in case of requests and macros) or treated like normal text.<tt> </tt>
|
||
|
For events such as troff requests, a separate Scheme procedure
|
||
|
can be defined for each request, and the name of the request that
|
||
|
triggered the event is then passed to the procedure as an argument.<tt> </tt>
|
||
|
An event handling procedure can be defined for
|
||
|
<ul>
|
||
|
<li>
|
||
|
each troff request, including requests that perform intrinsic troff
|
||
|
functions, such as ``.de'' and ``.if''
|
||
|
<li>
|
||
|
each troff macro, whether user-defined or part of a macro
|
||
|
package
|
||
|
<li>
|
||
|
each troff string
|
||
|
<li>
|
||
|
each number register
|
||
|
<li>
|
||
|
each special character
|
||
|
<li>
|
||
|
each escape sequence
|
||
|
<li>
|
||
|
each character (to provide character translations)
|
||
|
<li>
|
||
|
each inline equation enclosed by the current
|
||
|
<i>eqn</i>(1)
|
||
|
delimiter characters
|
||
|
<li>
|
||
|
each end of sentence (defined as a period, exclamation mark, or
|
||
|
question mark, followed by a newline).<tt> </tt>
|
||
|
</ul>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>When invoked, every Scheme procedure associated with one of
|
||
|
the above events receives one or more arguments.<tt> </tt>
|
||
|
For example, a procedure registered for the escape sequence `\h'
|
||
|
(horizontal space) is passed the name of the escape sequence
|
||
|
(the letter `h') as well as the argument to `\h' (i.e. the amount
|
||
|
of space).<tt> </tt>
|
||
|
Likewise, event handling procedures for requests and macros are
|
||
|
called with the name of the request or macro as well as any
|
||
|
arguments specified in the troff input.<tt> </tt>
|
||
|
The exact arguments passed to each type of event handler will be
|
||
|
explained below.<tt> </tt>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>A Scheme procedure associated with an event must return a string
|
||
|
which is then output in place of whatever input triggered the
|
||
|
event.<tt> </tt>
|
||
|
Here, and in a number of other places, a Scheme symbol or a Scheme
|
||
|
is accepted as an alternative to a string return value.<tt> </tt>
|
||
|
Event handling procedures are free to directly produce output
|
||
|
in addition to returning it as a result.<tt> </tt>
|
||
|
As procedures associated with events frequently just return a
|
||
|
fixed text, the text itself may be defined as the event handler
|
||
|
in place of the procedure to save the overhead of the procedure
|
||
|
call.<tt> </tt>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Predefined Scheme procedures are supplied for events such as the
|
||
|
requests ``.de'', ``.nr'', ``.ds'', and the corresponding escape
|
||
|
sequences `\n' and `\*' to support user-defined macros, strings,
|
||
|
and number registers.<tt> </tt>
|
||
|
In any case, specific event handlers registered for macros,
|
||
|
strings, and number registers supersede any user-supplied
|
||
|
definitions.<tt> </tt>
|
||
|
Thus, the author of a document can attach a
|
||
|
special translation rule to a macro, string, or number register
|
||
|
defined in the document to take effect when the document is processed by
|
||
|
<i>unroff</i>.<tt> </tt>
|
||
|
This is particularly important for high-level, structure-oriented
|
||
|
target languages like SGML, as the the micro-formatting
|
||
|
used by typical, more complex troff macros and by many low-level requests
|
||
|
may not be expressible in such languages.<tt> </tt>
|
||
|
As a case in point, it would obviously be impossible to translate, for
|
||
|
example, the ``.IP'' macro defined by the ``ms'' package to a
|
||
|
language such as HTML just by looking at the definition of the macro.<tt> </tt>
|
||
|
For this reason,
|
||
|
<i>unroff
|
||
|
</i>does not really load the actual macro definitions for a troff macro
|
||
|
package selected via the ``-m'' option; instead, an event handler
|
||
|
is defined for each macro exported by the package to generate
|
||
|
whatever represents the corresponding macro's function in the
|
||
|
target language.<tt> </tt>
|
||
|
<h2>4. <tt> </tt>Defining Event Handlers
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>In the following list of Scheme primitives, the argument
|
||
|
<i>name
|
||
|
</i>denotes the name of a troff request, macro, escape sequence
|
||
|
etc. (without any initial period or escape character) and can be
|
||
|
supplied in form of a Scheme string, a Scheme symbol, or
|
||
|
a Scheme character:
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
(defrequest "ti" ...)
|
||
|
|
||
|
(defrequest 'sp ...)
|
||
|
|
||
|
(defescape #\h ...)
|
||
|
</pre>
|
||
|
</dl>
|
||
|
(the primitives
|
||
|
<i>defrequest
|
||
|
</i>and
|
||
|
<i>defescape
|
||
|
</i>will be introduced in a moment).<tt> </tt>
|
||
|
An argument named
|
||
|
<i>handler
|
||
|
</i>is either a procedure (usually a lambda expression) which returns
|
||
|
a string, a symbol, or a character; or
|
||
|
<i>handler
|
||
|
</i>can itself be specified as a string, symbol, or character.<tt> </tt>
|
||
|
In addition, the literal ``#f'' (false) can be supplied as a
|
||
|
<i>handler
|
||
|
</i>argument to remove any event handler that is currently associated with
|
||
|
that event.<tt> </tt>
|
||
|
Each of the ``def'' primitives listed below returns the handler
|
||
|
that was previously associated with the corresponding event,
|
||
|
or ``#f'' if the event was not handled.<tt> </tt>
|
||
|
<h2>
|
||
|
(defrequest <i>name</i> <i>handler</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Associates the given handler with the given troff request.<tt> </tt>
|
||
|
If
|
||
|
<i>handler
|
||
|
</i>is a procedure, it is passed the request's name and arguments
|
||
|
as strings when called later.<tt> </tt>
|
||
|
Passing the name of the request as the first argument aids in
|
||
|
associating the same procedure with several different requests.<tt> </tt>
|
||
|
<i>unroff
|
||
|
</i>does not limit the number of arguments to requests, thus,
|
||
|
an event handling procedure for a requests that takes a variable
|
||
|
number of arguments could be defined like this:
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
(defrequest 'rm
|
||
|
(lambda (rm . args) ...))
|
||
|
</pre>
|
||
|
</dl>
|
||
|
<p>
|
||
|
If the request is invoked with fewer arguments than the procedure
|
||
|
has formal arguments, the remaining arguments are bound to
|
||
|
the empty string.<tt> </tt>
|
||
|
If the request is invoked with
|
||
|
<i>more
|
||
|
</i>arguments than the procedure has formal arguments, the last lambda
|
||
|
variable is assigned a string consisting of the (space-delimited)
|
||
|
arguments left over after the other formal arguments have been bound to
|
||
|
the other actual arguments.<tt> </tt>
|
||
|
However, if
|
||
|
<i>handler
|
||
|
</i>has only one formal argument, an error message is displayed when the
|
||
|
request is called with any arguments at all and the event is skipped.<tt> </tt>
|
||
|
For example, consider the following handler for the (non-existing)
|
||
|
request ``xx'':
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
(defrequest 'xx
|
||
|
(lambda (name a b) ...))
|
||
|
</pre>
|
||
|
</dl>
|
||
|
The procedure's arguments
|
||
|
<i>a
|
||
|
</i>and
|
||
|
<i>b
|
||
|
</i>will be bound as follows when the request is invoked:
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
.xx foo name="xx" a="foo" b=""
|
||
|
|
||
|
.xx foo bar baz name="xx" a="foo" b="bar baz"
|
||
|
</pre>
|
||
|
</dl>
|
||
|
<h2>
|
||
|
(defmacro <i>name</i> <i>handler</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Associates
|
||
|
<i>handler
|
||
|
</i>with the given troff macro, superseding
|
||
|
any definition for this macro established by the ordinary ``.de''
|
||
|
request.<tt> </tt>
|
||
|
The only difference between
|
||
|
<i>defrequest
|
||
|
</i>and
|
||
|
<i>defmacro
|
||
|
</i>is the way arguments are bound in case
|
||
|
<i>handler
|
||
|
</i>is a procedure
|
||
|
(troff employs slightly different rules when parsing the call
|
||
|
to a request and a macro invocation).<tt> </tt>
|
||
|
The quote character can be used in the latter case to surround
|
||
|
arguments containing spaces, while quote characters are treated as
|
||
|
normal characters in requests, which allows for the following
|
||
|
remarkable troff idiom:
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
.ds xy "hello
|
||
|
</pre>
|
||
|
</dl>
|
||
|
In contrast to event handlers defined for requests, the formal
|
||
|
arguments of a handler procedure associated with a macro must
|
||
|
match the actual arguments in the normal way, that is, as if
|
||
|
the procedure were invoked from within Scheme.<tt> </tt>
|
||
|
A warning message is displayed if the number of macro arguments
|
||
|
does not match the number of formal procedure arguments, and
|
||
|
the event is skipped.<tt> </tt>
|
||
|
<h2>
|
||
|
(defspecial <i>name</i> <i>handler</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Associates
|
||
|
<i>handler
|
||
|
</i>with the special character whose name is
|
||
|
<i>name</i>.<tt> </tt>
|
||
|
The name must have a length of 2.<tt> </tt>
|
||
|
In addition, an empty name can be specified to define a
|
||
|
``fallback'' handler that is called for special characters
|
||
|
for which no handler exists.<tt> </tt>
|
||
|
Like all event handler procedures,
|
||
|
<i>handler
|
||
|
</i>can have arbitrary side-effects in addition to returning a
|
||
|
result; for example, the procedure may display a warning message
|
||
|
if the special character cannot be represented in the target
|
||
|
language and an approximation must be rendered instead.<tt> </tt>
|
||
|
<h2>
|
||
|
(defstring <i>name</i> <i>handler</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Associates a handler with the specified troff string.<tt> </tt>
|
||
|
As
|
||
|
<i>unroff
|
||
|
</i>provides a default handler for the request ``.ds'' to implement
|
||
|
used-defined strings,
|
||
|
<i>defstring
|
||
|
</i>is primarily used to give definitions for strings exported by
|
||
|
troff macro packages.<tt> </tt>
|
||
|
<h2>
|
||
|
(defnumreg <i>name</i> <i>handler</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>This request behaves like
|
||
|
<i>defstring</i>,
|
||
|
except that it works on number registers.<tt> </tt>
|
||
|
Note that the Scheme primitive
|
||
|
<i>number->string
|
||
|
</i>may have to be used by
|
||
|
<i>handler
|
||
|
</i>(if it is a procedure) to convert a numeric result into a string
|
||
|
that can be returned from the handler.<tt> </tt>
|
||
|
<p>
|
||
|
In troff input, number registers as well as strings, special
|
||
|
characters, and escape sequences can be denoted using the groff
|
||
|
``long name'' syntax, unless troff compatibility has been enabled:
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
\n[numreg] \n[string] \f[font] \[em] ...
|
||
|
</pre>
|
||
|
</dl>
|
||
|
<h2>
|
||
|
(defescape <i>name</i> <i>handler</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Associates an event handler with an escape sequence.<tt> </tt>
|
||
|
<i>name
|
||
|
</i>must have a length of 1, unless the empty string is
|
||
|
given to define a ``fallback'' event handler (as with
|
||
|
<i>defspecial</i>).<tt> </tt>
|
||
|
Handlers defined for certain escape sequences are passed
|
||
|
a second argument in addition to the name of the escape sequence.<tt> </tt>
|
||
|
This is true for all escape sequences that have an argument
|
||
|
according to the troff specification:
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
\b \c \f \h \k \l \n \o \s \v \w \x \z
|
||
|
\* \$ \"
|
||
|
</pre>
|
||
|
</dl>
|
||
|
In addition, handlers for these groff escape sequences are passed an
|
||
|
additional argument unless troff compatibility is enabled:
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
\A \C \L \N \R \V \Y \Z
|
||
|
</pre>
|
||
|
</dl>
|
||
|
The form of an escape sequence argument is determined by the
|
||
|
troff specification and cannot be programmed; for example, the
|
||
|
handler for `\z' is passed a character or a special character,
|
||
|
and the handler for `\"' is invoked with the rest of the current
|
||
|
input line sans the terminating newline.<tt> </tt>
|
||
|
(The latter can be used to translate troff comments.)
|
||
|
<p>
|
||
|
Handlers registered for the escape sequences `\n' and '\s' are
|
||
|
passed an optional third argument, one of the Scheme characters
|
||
|
#\+ and #\-, if the escape sequence argument begins with a sign.<tt> </tt>
|
||
|
The sign is then stripped from the actual argument.<tt> </tt>
|
||
|
<p>
|
||
|
As `\n' and `\*' are treated as ordinary escape sequences,
|
||
|
handlers can be defined for them to achieve some form of fallback
|
||
|
for number register and strings.<tt> </tt>
|
||
|
<i>unroff
|
||
|
</i>provides suitable default handlers for `\n', `\*', and '\$' as part
|
||
|
of the implementation of user-defined number registers, strings,
|
||
|
and macros.<tt> </tt>
|
||
|
These handlers can be overridden if desired.<tt> </tt>
|
||
|
<h2>
|
||
|
(defchar <i>name</i> <i>handler</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Associates
|
||
|
<i>handler
|
||
|
</i>with a character.<tt> </tt>
|
||
|
<i>name
|
||
|
</i>must have a length of 1.<tt> </tt>
|
||
|
Each time the specified character is encountered in the troff
|
||
|
input, the result (or value) of
|
||
|
<i>handler
|
||
|
</i>is output in place of the character.<tt> </tt>
|
||
|
Character translations are not applied to the result of event
|
||
|
handlers; event procedures can use the Scheme primitive
|
||
|
<a href="#.translate"><i>translate</i></a>
|
||
|
(as described below) to execute the character translations
|
||
|
established by calls to
|
||
|
<i>defchar
|
||
|
</i>if desired.<tt> </tt>
|
||
|
<p>
|
||
|
<i>defchar
|
||
|
</i>currently has a number of weaknesses.<tt> </tt>
|
||
|
The argument cannot be a special character
|
||
|
(that is,
|
||
|
<i>name
|
||
|
</i>must be a plain character), and the mechanism cannot be used
|
||
|
to achieve true
|
||
|
<i>output
|
||
|
</i>translations as with the troff request ``.tr'' or the groff
|
||
|
request ``.char''.<tt> </tt>
|
||
|
<h2>
|
||
|
(defsentence <i>handler</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Defines a handler to be consulted on end of sentence.<tt> </tt>
|
||
|
If
|
||
|
<i>handler
|
||
|
</i>is a procedure, it is passed the punctuation mark ending the
|
||
|
sentence as its argument (in form of a Scheme character).<tt> </tt>
|
||
|
In any case, if an event handler has been specified, its result
|
||
|
(or value) is output in place of the end-of-sentence mark and
|
||
|
the newline character following it.<tt> </tt>
|
||
|
<h2>
|
||
|
(defequation <i>handler</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Defines a handler for
|
||
|
<i>eqn
|
||
|
</i>inline equations.<tt> </tt>
|
||
|
If
|
||
|
<i>handler
|
||
|
</i>is a procedure, it is passed the contents of the inline equation
|
||
|
(with the delimiters stripped) as an argument.<tt> </tt>
|
||
|
When an inline equation is encountered in the troff input and a handler
|
||
|
has been defined for inline equations, the handler's result (or value)
|
||
|
is output in place of the equation.<tt> </tt>
|
||
|
<p>
|
||
|
For inline equations to be recognized, delimiters must be defined first
|
||
|
by passing
|
||
|
<i>eqn
|
||
|
</i>input that includes a ``delim'' directive to the Scheme primitive
|
||
|
<a href="#.filter-eqn-line"><i>filter-eqn-line</i></a>
|
||
|
(explained below), as is usually done
|
||
|
by the event handler associated with the request ``.EQ''.<tt> </tt>
|
||
|
<h2>5. <tt> </tt>Querying Event Handlers
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>In addition to associating event handlers with events by means
|
||
|
of the ``def'' primitives, several primitives exist to query
|
||
|
the currently defined handler for a given event:
|
||
|
<h2>
|
||
|
(requestdef <i>name</i>)
|
||
|
<br>
|
||
|
(macrodef <i>name</i>)
|
||
|
<br>
|
||
|
(specialdef <i>name</i>)
|
||
|
<br>
|
||
|
(stringdef <i>name</i>)
|
||
|
<br>
|
||
|
(numregdef <i>name</i>)
|
||
|
<br>
|
||
|
(escapedef <i>name</i>)
|
||
|
<br>
|
||
|
(chardef <i>name</i>)
|
||
|
<br>
|
||
|
(sentencedef)
|
||
|
<br>
|
||
|
(equationdef)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Observe that the name of each primitive is derived from the name
|
||
|
of the corresponding ``def'' primitive by exchanging the word
|
||
|
``def'' and the rest of the name.<tt> </tt>
|
||
|
Each
|
||
|
<i>name
|
||
|
</i>argument is subject to the constraints described under the
|
||
|
corresponding ``def'' primitive above.<tt> </tt>
|
||
|
Each primitive returns whatever object has been registered as
|
||
|
the event handler (procedure, string, symbol, character);
|
||
|
or #f if no handler has been defined for the event.<tt> </tt>
|
||
|
<h2>6. <tt> </tt>Event Procedures with Side-Effects
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Besides the basic events described in the
|
||
|
<a href="#.events">preceding sections</a>,
|
||
|
another group of--slightly different--events exist and can
|
||
|
be handled by user-defined Scheme procedures.<tt> </tt>
|
||
|
These events are not related to troff functions, but to a number of
|
||
|
other conditions that are encountered when processing documents:
|
||
|
<ul>
|
||
|
<li>
|
||
|
the end of an input line
|
||
|
<li>
|
||
|
the beginning of a troff input file processed by
|
||
|
<i>unroff
|
||
|
</i><li>
|
||
|
the end of a troff input file
|
||
|
<li>
|
||
|
startup of the program
|
||
|
<li>
|
||
|
termination of the program
|
||
|
<li>
|
||
|
a keyword/value option encountered in the command line.<tt> </tt>
|
||
|
</ul>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Among other tasks, these events can be used to generate a prologue and
|
||
|
epilogue for each input file.<tt> </tt>
|
||
|
In contrast to the events described in the previous section, handlers for
|
||
|
these events are called solely for their side-effects.<tt> </tt>
|
||
|
Each event handler must be a Scheme procedure.<tt> </tt>
|
||
|
Their results are ignored, thus the procedures must have side-effects
|
||
|
to be useful.<tt> </tt>
|
||
|
Another difference is that more than one event handler can be associated
|
||
|
with each request.<tt> </tt>
|
||
|
A numeric
|
||
|
<i>level
|
||
|
</i>(a small integer number) is specified together with each event handler,
|
||
|
and when the corresponding event is triggered, all procedures
|
||
|
defined for this event are executed in increasing order as indicated by
|
||
|
their levels.<tt> </tt>
|
||
|
<h2>
|
||
|
(defevent <i>event</i> <i>level</i> <i>handler</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Associates the procedure
|
||
|
<i>handler
|
||
|
</i>with an event and returns the previous event handler registered
|
||
|
for this combination of event and level.<tt> </tt>
|
||
|
<i>level
|
||
|
</i>is an integer between 0 and 99;
|
||
|
<i>handler
|
||
|
</i>is a procedure, or the literal #f to remove a previously defined handler.<tt> </tt>
|
||
|
<i>event
|
||
|
</i>indicates the type of event and is one of the following Scheme symbols:
|
||
|
<i>line
|
||
|
</i>(end of input line),
|
||
|
<i>prolog
|
||
|
</i>(beginning of input file),
|
||
|
<i>epilog
|
||
|
</i>(end of input file),
|
||
|
<i>start
|
||
|
</i>(program start),
|
||
|
<i>exit
|
||
|
</i>(program termination),
|
||
|
<i>option
|
||
|
</i>(keyword/value command line option).<tt> </tt>
|
||
|
<p>
|
||
|
Procedures defined for the events
|
||
|
<i>prolog
|
||
|
</i>and
|
||
|
<i>epilog
|
||
|
</i>are called with two string arguments:
|
||
|
the path name (as specified by the user) and the file name component of
|
||
|
the troff input file whose processing has just begun or finished,
|
||
|
or the string ``stdin'' if
|
||
|
<i>unroff
|
||
|
</i>is taking its input from standard input.<tt> </tt>
|
||
|
Procedures defined for the event
|
||
|
<i>option
|
||
|
</i>are passed the option's name and value as strings.<tt> </tt>
|
||
|
All other event procedures are invoked without arguments.<tt> </tt>
|
||
|
<i>unroff
|
||
|
</i>provides a default handler for
|
||
|
<i>option
|
||
|
</i>(see the
|
||
|
<a href="#.options">primitives for options</a>
|
||
|
below).<tt> </tt>
|
||
|
<p>
|
||
|
Example:
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
(defevent 'exit 50 ; cleanup on exit
|
||
|
(lambda ()
|
||
|
...))
|
||
|
</pre>
|
||
|
</dl>
|
||
|
The handler defined in this way will be executed on termination,
|
||
|
after any handlers with levels 0-49.<tt> </tt>
|
||
|
<h2>
|
||
|
(eventdef <i>event</i> <i>level</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Returns the procedure defined as a handler for
|
||
|
<i>event
|
||
|
</i>and
|
||
|
<i>level</i>,
|
||
|
or #f if no such handler exists.<tt> </tt>
|
||
|
See
|
||
|
<i>defevent
|
||
|
</i>above for a description of the arguments.<tt> </tt>
|
||
|
<h2>7. <tt> </tt>How Troff Input is Processed
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>To be able to write non-trivial event handling procedures, it helps
|
||
|
to have a look at how troff input is processed, especially since
|
||
|
the parser of
|
||
|
<i>unroff
|
||
|
</i>works somewhat differently than ordinary troff.<tt> </tt>
|
||
|
In particular, the parser cannot blindly rescan the result of
|
||
|
handlers for escape sequences or special characters, as these
|
||
|
handlers will probably generate text in the
|
||
|
<i>target language
|
||
|
</i>that cannot be interpreted as troff input any longer.<tt> </tt>
|
||
|
Here is a brief overview of the parsing process.<tt> </tt>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Each input line is first scanned for references to troff strings and
|
||
|
number registers (this scanning pass will later be referred to as the
|
||
|
``expansion phase'').<tt> </tt>
|
||
|
For each `\*' or `\n' sequence found in the input line,
|
||
|
<i>unroff
|
||
|
</i>checks whether a handler for the string or number register has
|
||
|
been defined with
|
||
|
<i>defstring
|
||
|
</i>or
|
||
|
<i>defnumreg</i>,
|
||
|
and if this is the case, replaces the string or number register
|
||
|
reference by the result (or value) of the handler.<tt> </tt>
|
||
|
Otherwise, if a handler for the escape sequence `\*' or `\n'
|
||
|
proper has been defined, that handler is called.<tt> </tt>
|
||
|
Otherwise the reference is left untouched and scanning resumes
|
||
|
behind it<a href="#footnote1">[note 1]</a>
|
||
|
.<tt> </tt>
|
||
|
Comments are recognized in this phase, too, by calling the handler
|
||
|
for the `\"' escape sequence if there is one.<tt> </tt>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Next, the parser checks whether the result of the first phase
|
||
|
is a request or macro invocation (that is, begins with a period
|
||
|
or an apostrophe).<tt> </tt>
|
||
|
If this is the case, the arguments are parsed mimicking the
|
||
|
behavior of ordinary troff.<tt> </tt>
|
||
|
The rules for macro arguments are employed if
|
||
|
a handler has been defined
|
||
|
for the token after the period with
|
||
|
<i>defmacro</i>,
|
||
|
else the rules for requests are used.<tt> </tt>
|
||
|
The handler for the macro or request is then used, or applied
|
||
|
to the arguments if it is a procedure.<tt> </tt>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>If the input line does not contain a request or macro invocation,
|
||
|
it is scanned a second time to take care of escape sequences
|
||
|
and special characters (for lack of a better term, we will call
|
||
|
this phase ``escape parsing'').<tt> </tt>
|
||
|
Every escape character reference, special character, and inline
|
||
|
equation is replaced by the result (or value) of the event
|
||
|
handler registered for it, or left in place if there is no handler.<tt> </tt>
|
||
|
Character translations defined by means of
|
||
|
<i>defchar
|
||
|
</i>are also executed in this phase.<tt> </tt>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Finally, the result of the escape parsing phase or of the request or
|
||
|
macro invocation is checked whether it constitutes the end of a
|
||
|
sentence, and if so, the handler for this event is called
|
||
|
(actually, in the former case, the check is applied before
|
||
|
<i>and
|
||
|
</i>after the escape parsing and must succeed both times).<tt> </tt>
|
||
|
As the final step the line is output, and any handlers for the
|
||
|
<i>line
|
||
|
</i>event are invoked.<tt> </tt>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>An important thing to note is that the arguments passed to a handler
|
||
|
defined for a request or macro are not scanned for escape sequences
|
||
|
and special characters.<tt> </tt>
|
||
|
Therefore event procedures must explicitly parse their arguments if
|
||
|
desired by calling the Scheme primitive
|
||
|
<a href="#.parse"><i>parse</i></a>
|
||
|
(which will be described in the next section).<tt> </tt>
|
||
|
Consider, for example, an event procedure associated with a
|
||
|
macro ``IP'':
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
(defmacro 'IP
|
||
|
(lambda (IP tag . indent)
|
||
|
...))
|
||
|
</pre>
|
||
|
</dl>
|
||
|
and a call to the macro with an argument containing a
|
||
|
special character:
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
.IP \(bu
|
||
|
</pre>
|
||
|
</dl>
|
||
|
As the argument to the event procedure is only scanned for
|
||
|
strings and number registers, the variable
|
||
|
<i>tag
|
||
|
</i>will be bound to the string ``\(bu''.<tt> </tt>
|
||
|
Applying
|
||
|
<i>parse
|
||
|
</i>to the argument will turn it into whatever is the target language
|
||
|
representation for the special character ``\(bu'' (that is, the
|
||
|
result of the event handler for the special character).<tt> </tt>
|
||
|
Whether or not arguments will have to be parsed depends on the
|
||
|
particular request or macro; the procedure implementing the request
|
||
|
``.tm'', for instance, will print its ``raw'' argument (a sample
|
||
|
event handler for the request ``.tm'' is supplied by
|
||
|
<i>unroff</i>).<tt> </tt>
|
||
|
<h2>8. <tt> </tt>Calling the Parser
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>The following Scheme primitives are used by event procedures for
|
||
|
requests, macros, and escape characters to parse their arguments
|
||
|
or to parse lines of text that have been read from an input source.<tt> </tt>
|
||
|
Each of the primitives can be invoked with zero or more arguments
|
||
|
of type string, symbol, or character.<tt> </tt>
|
||
|
The arguments are concatenated to form a Scheme string which is then
|
||
|
passed to the parser, and the result is returned as a new string.<tt> </tt>
|
||
|
<h2>
|
||
|
<a name=".parse">(parse <i>.</i> <i>args</i>)</a></h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>This primitive feeds its arguments to the ``escape parsing''
|
||
|
pass as described in the previous section.<tt> </tt>
|
||
|
It scans its arguments for special characters and escape
|
||
|
sequences and replaces them by the corresponding event values
|
||
|
(or results), and it executes character translations.<tt> </tt>
|
||
|
<h2>
|
||
|
<a name=".translate">(translate <i>.</i> <i>args</i>)</a></h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Like
|
||
|
<i>parse
|
||
|
</i>above, except that only output character translations (defined by calls to
|
||
|
<i>defchar</i>)
|
||
|
are executed.<tt> </tt>
|
||
|
<h2>
|
||
|
(parse-expand <i>.</i> <i>args</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>This primitive applies the ``expansion parsing'' phase (as described in the
|
||
|
previous section) to its arguments.<tt> </tt>
|
||
|
Compared to
|
||
|
<i>parse</i>,
|
||
|
<i>parse-expand
|
||
|
</i>is only used rarely, as input lines read in the normal way are
|
||
|
scanned for string and number register references anyway.<tt> </tt>
|
||
|
The sample implementation supplied by
|
||
|
<i>unroff
|
||
|
</i>for the requests ``.ds'', ``.as'', and '\*' makes use of this primitive
|
||
|
to rescan the contents of user-defined strings upon interpolation.<tt> </tt>
|
||
|
<h2>
|
||
|
(parse-line <i>.</i> <i>args</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>This primitive parses an entire input line, which may contain a call
|
||
|
to a request or macro, as described in the previous section.<tt> </tt>
|
||
|
The line made up by the primitive's arguments is treated exactly as
|
||
|
it if were read from an input file, although it need not have a
|
||
|
terminating newline.<tt> </tt>
|
||
|
Two places where this primitive is required are the handler for
|
||
|
the request ``.so'' and the code that expands user-defined macros.<tt> </tt>
|
||
|
<h2>
|
||
|
(parse-copy-mode <i>.</i> <i>args</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>The primitive
|
||
|
<i>parse-copy-mode
|
||
|
</i>parses its arguments in a manner similar to troff ``copy mode''.<tt> </tt>
|
||
|
In this mode, escape sequences beginning with '\$' are dealt
|
||
|
with (by calling their event procedures), the sequence `\\'
|
||
|
is replaced by a single `\', and each occurrence of `\.'
|
||
|
is replaced by a period.<tt> </tt>
|
||
|
Macro bodies are parsed in copy mode during macro definition and again
|
||
|
when the macros are expanded.<tt> </tt>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>The sample implementation of user-defined macros supplied by
|
||
|
<i>unroff
|
||
|
</i>defines suitable event handlers for the usual
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
\$1 \$2 ...
|
||
|
</pre>
|
||
|
</dl>
|
||
|
escape sequences (there is no limit to the number of arguments,
|
||
|
and the groff long name convention may be used to denote an
|
||
|
argument number), and in addition for the groff extensions
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
\$0 \$* \$@
|
||
|
</pre>
|
||
|
</dl>
|
||
|
as explained in the
|
||
|
<a href="./unroff.1.html">manual page</a>
|
||
|
<i>unroff</i>(1).<tt> </tt>
|
||
|
<h2>
|
||
|
(parse-expression <i>expr</i> <i>fail</i> <i>scale</i>)
|
||
|
<br>
|
||
|
(parse-expression-rest <i>expr</i> <i>fail</i> <i>scale</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>These primitives evaluate the numeric expression specified by
|
||
|
the string argument
|
||
|
<i>expr
|
||
|
</i>and return the result as an exact number.<tt> </tt>
|
||
|
The usual troff expression syntax, operators, and scale
|
||
|
indicators are supported.<tt> </tt>
|
||
|
If an error occurs during evaluation (for instance, if
|
||
|
<i>expr
|
||
|
</i>is not a syntactically valid expression),
|
||
|
a warning message is displayed and
|
||
|
<i>fail
|
||
|
</i>(which may be an arbitrary Scheme object) is returned.<tt> </tt>
|
||
|
The character argument
|
||
|
<i>scale
|
||
|
</i>is the default scale indicator, for example `#\m', or `#\u'
|
||
|
for basic units.<tt> </tt>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>The primitive
|
||
|
<i>parse-expression-rest
|
||
|
</i>is identical to
|
||
|
<i>parse-expression</i>,
|
||
|
except that its return value is a cons cell whose car consists
|
||
|
of the result of the evaluation and whose cdr is the rest of
|
||
|
<i>expr
|
||
|
</i>starting at the character position where parsing of the
|
||
|
expression stopped.<tt> </tt>
|
||
|
In other words, the primitive evaluates the portion of
|
||
|
<i>expr
|
||
|
</i>that constitutes a valid expression, and it returns the result
|
||
|
and whatever is left over.<tt> </tt>
|
||
|
Warning messages are also suppressed, except if an overflow occurs
|
||
|
during evaluation.<tt> </tt>
|
||
|
<i>parse-expression-rest
|
||
|
</i>is useful for tasks like parsing the argument of the escape
|
||
|
sequences `\l' and `\L' where an expression is immediately
|
||
|
followed by another character.<tt> </tt>
|
||
|
Examples:
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
(parse-expression "(2+8)/5" 0 #\u) => 2
|
||
|
(parse-expression "foo" #f #\u) => #f; prints warning
|
||
|
|
||
|
(parse-expression-rest "1+1" #f #\u) => (2 . "")
|
||
|
(parse-expression-rest "(2+8)/5foo" 0 #\u) => (2 . "foo")
|
||
|
(parse-expression-rest "15\&-" 0 #\u) => (15 . "\&-")
|
||
|
</pre>
|
||
|
</dl>
|
||
|
<h2>
|
||
|
(char-expression-delimiter? <i>char</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Returns #t if the character argument
|
||
|
<i>char
|
||
|
</i>is valid as the first character of a numeric expression (e.g. a digit),
|
||
|
otherwise #f.<tt> </tt>
|
||
|
<h2>
|
||
|
(set-scaling! <i>scale</i> <i>factor</i> <i>divisor</i>)
|
||
|
<br>
|
||
|
(get-scaling <i>scale</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>These primitives set and read the scale factor and divisor for
|
||
|
the specified scale indicator.<tt> </tt>
|
||
|
<i>scale
|
||
|
</i>is the scale indicator (a character);
|
||
|
<i>factor
|
||
|
</i>and
|
||
|
<i>divisor
|
||
|
</i>are integers.<tt> </tt>
|
||
|
<i>get-scaling
|
||
|
</i>returns the scaling for the specified scale indicator as a pair
|
||
|
of integers.<tt> </tt>
|
||
|
The factors and divisors are initially set to 1 for all scale
|
||
|
indicators; they must be assigned useful values by each back-end.<tt> </tt>
|
||
|
<h2>9. <tt> </tt>Streams
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Input, output, and storage of text lines in
|
||
|
<i>unroff
|
||
|
</i>are centered around a new Scheme data type named
|
||
|
<i>stream
|
||
|
</i>and a set of primitives that work on streams.<tt> </tt>
|
||
|
A stream can act as a source (input stream) or as a sink (output
|
||
|
stream) for lines of text.<tt> </tt>
|
||
|
Streams not only serve as the basis for input and output operations
|
||
|
and for the exchange of text with shell commands, but can also be used
|
||
|
to temporarily buffer lines of text (e.g. footnotes or tables of
|
||
|
contents) and to implement user-defined macros in a simple way.<tt> </tt>
|
||
|
Each input or output stream can be connected to one of the
|
||
|
following three types of
|
||
|
<i>targets</i>:
|
||
|
<ul>
|
||
|
<li>
|
||
|
a file, or the program's standard input or standard output
|
||
|
<li>
|
||
|
a UNIX pipe connected to a shell running a shell command
|
||
|
<li>
|
||
|
an internal
|
||
|
<i>buffer
|
||
|
</i>whose lifetime is limited to that of the current invocation of
|
||
|
<i>unroff</i>.<tt> </tt>
|
||
|
</ul>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Buffers act similar to (initially empty) files, except that
|
||
|
they are not visible from the outside and that they are destroyed
|
||
|
automatically on exit of the program.<tt> </tt>
|
||
|
Once a buffer has been filled with text through an output stream,
|
||
|
it can be reopened and read through an input stream multiple times.<tt> </tt>
|
||
|
However, if a buffer is currently written through an output stream,
|
||
|
no more streams may refer to the same buffer.<tt> </tt>
|
||
|
As the contents of buffers kept in memory, input and output operations
|
||
|
on buffers are fast.<tt> </tt>
|
||
|
The sample implementation of user-defined macros utilizes buffers
|
||
|
to store the macro bodies; a macro can then be expanded simply
|
||
|
by redirecting the current input source to the corresponding buffer
|
||
|
temporarily.<tt> </tt>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Both the parser and all input and output primitives operate on a
|
||
|
<i>current input stream
|
||
|
</i>and a
|
||
|
<i>current output stream</i>;
|
||
|
input and output is always performed using these two streams.<tt> </tt>
|
||
|
On startup,
|
||
|
<i>unroff
|
||
|
</i>initializes the current output stream to either point to
|
||
|
standard output or to a newly created output file (usually depending on
|
||
|
the value of the
|
||
|
<b>document
|
||
|
</b>option).<tt> </tt>
|
||
|
If the current output stream is assigned the literal #f,
|
||
|
output is sent to standard output<a href="#footnote2">[note 2]</a>
|
||
|
.<tt> </tt>
|
||
|
Likewise, for each input file mentioned in the command line,
|
||
|
a stream pointing to that file is created and assigned to
|
||
|
the current input stream before the parser starts processing
|
||
|
the file.<tt> </tt>
|
||
|
The rest of this section lists the Scheme primitives operating
|
||
|
on streams.<tt> </tt>
|
||
|
<h2>
|
||
|
(stream? <i>obj</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>The type predicate for the new data type.<tt> </tt>
|
||
|
It returns #t if
|
||
|
<i>obj
|
||
|
</i>is a member of the type
|
||
|
<i>stream</i>,
|
||
|
otherwise #f.<tt> </tt>
|
||
|
<h2>
|
||
|
(input-stream)
|
||
|
<br>
|
||
|
(output-stream)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Returns the current input stream, or output stream respectively.<tt> </tt>
|
||
|
<h2>
|
||
|
(open-input-stream <i>target</i>)
|
||
|
<br>
|
||
|
(open-output-stream <i>target</i>)
|
||
|
<br>
|
||
|
(append-output-stream <i>target</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>These primitives create a new input stream or output stream pointing
|
||
|
to the specified target.<tt> </tt>
|
||
|
The argument
|
||
|
<i>target
|
||
|
</i>is a string or a symbol.<tt> </tt>
|
||
|
If the target is enclosed in square brackets, it names a buffer;
|
||
|
if it begins with the pipe symbol `|', a pipe to a shell running
|
||
|
the rest of the target as a shell command is established; otherwise
|
||
|
<i>target
|
||
|
</i>is interpreted as a file name.<tt> </tt>
|
||
|
<i>append-output-stream
|
||
|
</i>rewinds to the end of the specified output buffer or file before
|
||
|
the first output operation; it acts like
|
||
|
<i>open-output-stream
|
||
|
</i>in case of a pipe.<tt> </tt>
|
||
|
Examples:
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
(let* ((buffer (open-output-stream '[temp]))
|
||
|
(pipe (open-input-stream "|ls -l /usr/lib/tmac"))
|
||
|
(file (open-input-stream "/etc/passwd")))
|
||
|
...)
|
||
|
</pre>
|
||
|
</dl>
|
||
|
<h2>
|
||
|
(set-input-stream! <i>stream</i>)
|
||
|
<br>
|
||
|
(set-output-stream! <i>stream</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>These primitives make the specified stream the
|
||
|
<i>current
|
||
|
</i>input stream (or output stream respectively).<tt> </tt>
|
||
|
<i>stream
|
||
|
</i>must be the result of a call to one of the three primitives that
|
||
|
open a stream, or #f.<tt> </tt>
|
||
|
An error is signaled if
|
||
|
<i>set-input-stream!
|
||
|
</i>is applied to an output stream or vice versa, or if the stream
|
||
|
has been closed in the meantime.<tt> </tt>
|
||
|
<h2>
|
||
|
(close-stream <i>stream</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Closes the specified stream.<tt> </tt>
|
||
|
An error is signaled if the stream is still the current input
|
||
|
stream or current output stream.<tt> </tt>
|
||
|
Once an output stream pointing to a buffer has been closed, the
|
||
|
buffer can be reopened for reading.<tt> </tt>
|
||
|
A stream that is no longer reachable is closed automatically
|
||
|
during the next run of the garbage collector.<tt> </tt>
|
||
|
<h2>
|
||
|
(stream-buffer? <i>stream</i>)
|
||
|
<br>
|
||
|
(stream-file? <i>stream</i>)
|
||
|
<br>
|
||
|
(stream-pipe? <i>stream</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>These predicates return #t if the specified stream points to a
|
||
|
buffer, a file, or a pipe respectively, otherwise #f.<tt> </tt>
|
||
|
<h2>
|
||
|
(stream-target <i>stream</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>This primitive returns the target to which the specified stream
|
||
|
points.<tt> </tt>
|
||
|
The return value is a string.<tt> </tt>
|
||
|
In case of a pipe, the target is truncated at the first space,
|
||
|
that is, only the command name is included.<tt> </tt>
|
||
|
The target of the current input stream (together with the current
|
||
|
line number) is displayed as a prefix of error messages and
|
||
|
can also be obtained through the primitive
|
||
|
<a href="#.substitute"><i>substitute</i></a>
|
||
|
described below.<tt> </tt>
|
||
|
<h2>
|
||
|
(stream-position <i>stream</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Returns the current character position of the specified output stream,
|
||
|
that is, the offset at which the next character will be written.<tt> </tt>
|
||
|
The return value for input streams is currently always zero.<tt> </tt>
|
||
|
This primitive is useful in conjunction with
|
||
|
<a href="#.file-insertions"><i>file-insertions</i></a>
|
||
|
(described below).<tt> </tt>
|
||
|
<h2>
|
||
|
(stream-string <i>target</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>This primitive opens an input string to the specified target,
|
||
|
reads from the stream until end-of-stream is reached, closes
|
||
|
the stream, and returns the concatenation of all the lines that
|
||
|
have been read as a string<a href="#footnote3">[note 3]</a>
|
||
|
.<tt> </tt>
|
||
|
<h2>10. <tt> </tt>Input and Output Primitives
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt><i>unroff
|
||
|
</i>provides one new input primitive and one new output primitive that
|
||
|
work with the current input stream and current output stream (and a
|
||
|
third primitive which is just an optimization of the latter, as
|
||
|
well as a few auxiliary functions).<tt> </tt>
|
||
|
<h2>
|
||
|
(emit <i>.</i> <i>args</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt><i>emit
|
||
|
</i>is the only stream-based output primitive.<tt> </tt>
|
||
|
It receives any number of strings, symbols, and characters,
|
||
|
concatenates its arguments, and sends the resulting string to
|
||
|
the current output stream (to standard output if the the current
|
||
|
output stream has been assigned #f).<tt> </tt>
|
||
|
<i>emit
|
||
|
</i>is primarily used in situations where text has to
|
||
|
be output without rescanning it and without applying any
|
||
|
character translations.<tt> </tt>
|
||
|
It is also used from within the event procedures that are called
|
||
|
for their side-effects, for example, by the
|
||
|
<i>prolog
|
||
|
</i>and
|
||
|
<i>epilog
|
||
|
</i>event procedures to generate a header and trailer for each
|
||
|
output file.<tt> </tt>
|
||
|
The primitive returns the empty symbol so that it can be called
|
||
|
as the last form in an event procedure whose result is used.<tt> </tt>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Example:
|
||
|
the new troff request for transparent output, as explained in the
|
||
|
<a href="./unroff.1.html">manual page</a>
|
||
|
<i>unroff</i>(1),
|
||
|
can be implement like this:
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
(defrequest '>>
|
||
|
(lambda (>> code)
|
||
|
(emit code #\newline)))
|
||
|
</pre>
|
||
|
</dl>
|
||
|
<h2>
|
||
|
(read-line)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>This primitive reads the next input line from the current input
|
||
|
stream and returns it as a string.<tt> </tt>
|
||
|
An error is signaled if the current input stream has been bound
|
||
|
to #f, which is the case, for example, when
|
||
|
<i>unroff
|
||
|
</i>has been called with the option
|
||
|
<b>-t
|
||
|
</b>to start an interactive top level.<tt> </tt>
|
||
|
If an incomplete last line (i.e. a line without a terminating
|
||
|
newline) is returned by the target pointed to by the current
|
||
|
input stream, a newline is appended.<tt> </tt>
|
||
|
Thus,
|
||
|
<i>read-line
|
||
|
</i>always returns at least a string containing a newline character.<tt> </tt>
|
||
|
<h2>
|
||
|
(read-line-expand)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>This primitive is nothing more than an optimization for
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
(parse-expand (read-line))
|
||
|
</pre>
|
||
|
</dl>
|
||
|
which has been provided to speed up frequently used functions like
|
||
|
macro expansion.<tt> </tt>
|
||
|
<h2>
|
||
|
(unread-line <i>string</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>This primitive pushes back an input line to the current input
|
||
|
stream, which will then be returned by the next call to
|
||
|
<i>read-line
|
||
|
</i>or
|
||
|
<i>read-line-expand</i>,
|
||
|
or it will be read by the parser in the normal way when processing
|
||
|
the current input file.<tt> </tt>
|
||
|
<i>string
|
||
|
</i>need not have a terminating newline.<tt> </tt>
|
||
|
Strings pushed back by multiple calls to
|
||
|
<i>unread-line
|
||
|
</i>are coalesced and returned as a whole by the next input operation.<tt> </tt>
|
||
|
<h2>
|
||
|
(error-port)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Returns a Scheme output port that is bound to the program's
|
||
|
standard error output.<tt> </tt>
|
||
|
This primitive is used by the default Scheme error handler provided
|
||
|
by
|
||
|
<i>unroff
|
||
|
</i>and by the
|
||
|
<i>warn
|
||
|
</i>utility function<a href="#footnote4">[note 4]</a>
|
||
|
.<tt> </tt>
|
||
|
Note that
|
||
|
<i>error-port
|
||
|
</i>returns an ordinary Scheme port, not a stream.<tt> </tt>
|
||
|
<h2>11. <tt> </tt>String Functions
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Most of the string handling primitives described in this section
|
||
|
could as well have been implemented in Scheme based on the standard
|
||
|
Scheme string primitives.<tt> </tt>
|
||
|
They are provided as built-in primitives by
|
||
|
<i>unroff
|
||
|
</i>mainly as optimizations or because writing them as Scheme
|
||
|
procedures would have been significantly more cumbersome.<tt> </tt>
|
||
|
All the string functions return new strings, that is, they
|
||
|
do not modify their arguments.<tt> </tt>
|
||
|
<h2>
|
||
|
(concat <i>.</i> <i>args</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt><i>concat
|
||
|
</i>can be called with any number of Scheme strings, symbols, and
|
||
|
characters.<tt> </tt>
|
||
|
The primitive concatenates its arguments and returns the result
|
||
|
as a string.<tt> </tt>
|
||
|
<h2>
|
||
|
(spread)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>This primitive is identical to
|
||
|
<i>concat</i>,
|
||
|
except that it delimits its arguments by a space character.<tt> </tt>
|
||
|
For example, the event procedure for a macro that just
|
||
|
returns a line consisting of its arguments could be define like this:
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
(defmacro 'X
|
||
|
(lambda (X . words)
|
||
|
(parse (apply spread words) #\newline)))
|
||
|
</pre>
|
||
|
</dl>
|
||
|
<h2>
|
||
|
(repeat-string <i>num</i> <i>string</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Returns a string consisting of the string argument
|
||
|
<i>string
|
||
|
</i>repeated
|
||
|
<i>num
|
||
|
</i>times.<tt> </tt>
|
||
|
<h2>
|
||
|
(string-prune-left <i>string</i> <i>prefix</i> <i>fail</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>This primitive checks whether
|
||
|
<i>string
|
||
|
</i>starts with the given string prefix, and if so, returns the rest of
|
||
|
<i>string
|
||
|
</i>beginning at the first character position after the initial prefix.<tt> </tt>
|
||
|
If the strings do not match,
|
||
|
<i>fail
|
||
|
</i>is returned (which may an arbitrary object).<tt> </tt>
|
||
|
Example:
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
(string-prune-left "+foo" "+" #f) => "foo"
|
||
|
(string-prune-left "gulp" "+" #f) => #f
|
||
|
</pre>
|
||
|
</dl>
|
||
|
<h2>
|
||
|
(string-prune-right <i>string</i> <i>suffix</i> <i>fail</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>This primitive is identical to
|
||
|
<i>string-prune-left</i>,
|
||
|
except that it checks for a suffix rather than a prefix,
|
||
|
that is, whether
|
||
|
<i>string
|
||
|
</i>ends with
|
||
|
<i>suffix</i>.<tt> </tt>
|
||
|
<h2>
|
||
|
(string-compose <i>string1</i> <i>string2</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>If the argument
|
||
|
<i>string2
|
||
|
</i>begins with a plus sign,
|
||
|
<i>string-compose
|
||
|
</i>returns the concatenation of
|
||
|
<i>string1
|
||
|
</i>and
|
||
|
<i>string2
|
||
|
</i>with the initial plus sign stripped.<tt> </tt>
|
||
|
If
|
||
|
<i>string2
|
||
|
</i>begins with a minus sign,
|
||
|
it returns a string consisting of
|
||
|
<i>string1
|
||
|
</i>with all characters occurring in
|
||
|
<i>string2
|
||
|
</i>removed.<tt> </tt>
|
||
|
Otherwise,
|
||
|
<i>string-compose
|
||
|
</i>just returns
|
||
|
<i>string2</i>.<tt> </tt>
|
||
|
This primitive is used for the implementation of the option type
|
||
|
<i>dynstring</i>.<tt> </tt>
|
||
|
<h2>
|
||
|
(parse-pair <i>string</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>If
|
||
|
<i>string
|
||
|
</i>consists of two parts separated and enclosed by an arbitrary delimiter
|
||
|
character,
|
||
|
<i>parse-pair
|
||
|
</i>returns a cons cell holding the two substrings.<tt> </tt>
|
||
|
Otherwise, it returns #f.<tt> </tt>
|
||
|
Example:
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
(parse-pair "'foo'bar'") => ("foo" . "bar")
|
||
|
(parse-pair "hello") => #f
|
||
|
</pre>
|
||
|
</dl>
|
||
|
<h2>
|
||
|
(parse-triple <i>string</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>This primitive is identical to
|
||
|
<i>parse-pair</i>,
|
||
|
except that it breaks up a three-part string rather than a
|
||
|
two-part string and returns an improper list whose car, cadr,
|
||
|
and cddr consist of the three substrings<a href="#footnote5">[note 5]</a>
|
||
|
.<tt> </tt>
|
||
|
<i>parse-pair
|
||
|
</i>and
|
||
|
<i>parse-triple
|
||
|
</i>are useful mainly for parsing the arguments to troff requests such
|
||
|
as ``.if'' and ``.tl''.<tt> </tt>
|
||
|
<h2>
|
||
|
<a name=".substitute">(substitute <i>string</i> <i>.</i> <i>args</i>)</a></h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>This primitive returns a copy of
|
||
|
<i>string
|
||
|
</i>in which each sequence of a percent sign, a
|
||
|
<i>substitution specifier</i>,
|
||
|
and another percent sign is replaced by another string according
|
||
|
to the specifier.<tt> </tt>
|
||
|
Two adjacent percent signs are replaced by a single percent sign.<tt> </tt>
|
||
|
The following list describes all substitution specifiers together
|
||
|
with their respective replacements.<tt> </tt>
|
||
|
<dl>
|
||
|
<dt><b>macros</b><dd>
|
||
|
The name of the troff macro package whose macros are recognized,
|
||
|
that is, the argument to the option
|
||
|
<b>-m
|
||
|
</b>(or the empty string if none was specified).<tt> </tt>
|
||
|
<dt><b>format</b><dd>
|
||
|
The output format, that is, the argument to the option
|
||
|
<b>-f
|
||
|
</b>(or the default output format if the option was omitted).<tt> </tt>
|
||
|
<dt><b>directory</b><dd>
|
||
|
The name of the library directory from which
|
||
|
<i>unroff
|
||
|
</i>loads its Scheme files.<tt> </tt>
|
||
|
<dt><b>progname</b><dd>
|
||
|
The name of the running program (this is used as a prefix in
|
||
|
error messages and warning messages).<tt> </tt>
|
||
|
<dt><b>filepos</b><dd>
|
||
|
A space character followed by the target of the current input
|
||
|
stream, a colon, the number of the last input line read from
|
||
|
the stream, and another colon.<tt> </tt>
|
||
|
If the current input stream is bound to #f, the empty string
|
||
|
is substituted.<tt> </tt>
|
||
|
This specifier is useful for displaying error messages or warning messages.<tt> </tt>
|
||
|
<dt><b>tmpname</b><dd>
|
||
|
A file name that can be used for a temporary file.<tt> </tt>
|
||
|
Each use of this specifier creates a new, unique file name.<tt> </tt>
|
||
|
<dt><b>version</b><dd>
|
||
|
The program's major and minor version numbers separated by a period.<tt> </tt>
|
||
|
<dt><b>weekday</b><dd>
|
||
|
The abbreviated weekday name.<tt> </tt>
|
||
|
<dt><b>weekday+</b><dd>
|
||
|
The full weekday name.<tt> </tt>
|
||
|
<dt><b>weekdaynum</b><dd>
|
||
|
The weekday (0-6, Sunday is 0).<tt> </tt>
|
||
|
<dt><b>monthname</b><dd>
|
||
|
The abbreviated month name.<tt> </tt>
|
||
|
<dt><b>monthname+</b><dd>
|
||
|
The full monthname.<tt> </tt>
|
||
|
<dt><b>day</b><dd>
|
||
|
The day of the month (01-31).<tt> </tt>
|
||
|
<dt><b>month</b><dd>
|
||
|
The month (01-12).<tt> </tt>
|
||
|
<dt><b>year</b><dd>
|
||
|
The year.<tt> </tt>
|
||
|
<dt><b>date</b><dd>
|
||
|
The date (in the local environment's representation).<tt> </tt>
|
||
|
<dt><b>time</b><dd>
|
||
|
The time (in the local environment's representation).<tt> </tt>
|
||
|
<dt>a positive number <i>n</i><dd>
|
||
|
The
|
||
|
<i>n</i>th
|
||
|
additional argument in the call to the
|
||
|
<i>substitute
|
||
|
</i>primitive, which must be a string.<tt> </tt>
|
||
|
<dt>a <i>string</i><dd>
|
||
|
<i>string
|
||
|
</i>is interpreted as the name of an environment variable,
|
||
|
and the value of this variable is substituted (or the empty
|
||
|
string if the environment variable is undefined).<tt> </tt>
|
||
|
</dl>
|
||
|
<p>
|
||
|
Examples:
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
(substitute "%date% %HOME%") => "04/09/95 /home/kbs/net"
|
||
|
|
||
|
(substitute "%progname%:%filepos% %1%" "hello")
|
||
|
=> "unroff: manual.ms:21: hello"
|
||
|
|
||
|
(load (substitute "%directory%/scm/%format%/m%macros%.scm"))
|
||
|
</pre>
|
||
|
</dl>
|
||
|
<h2>12. <tt> </tt>Tables
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt><i>unroff
|
||
|
</i>provides simple hash tables as a new first class data type
|
||
|
<i>table</i>.<tt> </tt>
|
||
|
Each table entry associates an arbitrary Scheme object with
|
||
|
a key (a Scheme string or symbol).<tt> </tt>
|
||
|
Tables are useful for various purposes; for example, the Scheme code
|
||
|
delivered with
|
||
|
<i>unroff
|
||
|
</i>maintains hash tables to store information about number registers,
|
||
|
options, fonts, and for other bookkeeping tasks.<tt> </tt>
|
||
|
<h2>
|
||
|
(table? <i>obj</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>The type predicate for the new type; it returns #t if
|
||
|
<i>obj
|
||
|
</i>is a member of the type
|
||
|
<i>table</i>,
|
||
|
otherwise #f.<tt> </tt>
|
||
|
<h2>
|
||
|
(make-table <i>size</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Returns a new table of the specified size.<tt> </tt>
|
||
|
<i>size
|
||
|
</i>is a positive integer.<tt> </tt>
|
||
|
The smaller the size, the more collisions occur as entries
|
||
|
are added to the table.<tt> </tt>
|
||
|
However, the hash function employed by the table primitives
|
||
|
ensures that no collisions occur in tables of size
|
||
|
256^<i>n
|
||
|
</i>if all keys have a length less than or equal to
|
||
|
<i>n</i>.<tt> </tt>
|
||
|
<h2>
|
||
|
(table-store! <i>table</i> <i>key</i> <i>obj</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>This primitive stores the Scheme object
|
||
|
<i>obj
|
||
|
</i>under the given
|
||
|
<i>key
|
||
|
</i>in the given
|
||
|
<i>table</i>.<tt> </tt>
|
||
|
The key argument must be a string or a symbol.<tt> </tt>
|
||
|
<h2>
|
||
|
(table-lookup <i>table</i> <i>key</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>This primitive checks whether an object is stored in the given
|
||
|
<i>table
|
||
|
</i>under the specified
|
||
|
<i>key</i>,
|
||
|
and if so, returns the object.<tt> </tt>
|
||
|
If no object is stored under
|
||
|
<i>key</i>,
|
||
|
<i>table-lookup
|
||
|
</i>returns #f.<tt> </tt>
|
||
|
<h2>
|
||
|
(table-remove! <i>table</i> <i>key</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Removes the entry selected by
|
||
|
<i>key
|
||
|
</i>from the specified table.<tt> </tt>
|
||
|
<h2>13. <tt> </tt>Miscellaneous Primitives
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>The first two primitives described in this section are not essential,
|
||
|
as the same function could be achieved with pipe streams,
|
||
|
although with greater overhead.<tt> </tt>
|
||
|
The remaining primitives perform a number of troff-specific operations
|
||
|
and are only useful in a few specialized contexts.<tt> </tt>
|
||
|
<h2>
|
||
|
(shell-command <i>command</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Runs the specified
|
||
|
<i>command
|
||
|
</i>(which must be a string) as a shell command by passing it to a call to
|
||
|
<i>system</i>(3).<tt> </tt>
|
||
|
The return value is that of
|
||
|
<i>system()
|
||
|
</i>(an integer).<tt> </tt>
|
||
|
<h2>
|
||
|
(remove-file <i>filename</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Removes the specified file;
|
||
|
<i>filename
|
||
|
</i>must be a string or a symbol.<tt> </tt>
|
||
|
<h2>
|
||
|
(troff-compatible?)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>This predicate returns #t if troff compatibility mode has been
|
||
|
enabled (i.e. if the option
|
||
|
<b>-C
|
||
|
</b>has been given), otherwise #f.<tt> </tt>
|
||
|
<h2>
|
||
|
(set-escape! <i>char</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Sets the troff escape character (initially `\') to the specified
|
||
|
character argument.<tt> </tt>
|
||
|
This primitive is used to implement the ``.ec'' request.<tt> </tt>
|
||
|
<h2>
|
||
|
<a name=".filter-eqn-line">(filter-eqn-line <i>string</i>)</a></h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>This primitive scans the string argument (which is supposed to
|
||
|
be passed to the
|
||
|
<i>eqn
|
||
|
</i>preprocessor afterwards) for occurrences of the ``delim'' directive.<tt> </tt>
|
||
|
If a ``delim'' directive is found, the current inline equation
|
||
|
delimiters maintained by the parser are changed or disabled as specified by
|
||
|
the directive.<tt> </tt>
|
||
|
The primitive returns #f if
|
||
|
<i>string
|
||
|
</i>is empty or consists just of white space, or if it contains
|
||
|
a valid ``delim'' or ``define'' directive, otherwise #t.<tt> </tt>
|
||
|
The inline equation delimiters are disabled initially.<tt> </tt>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>The primitive is supposed to be used by implementations of
|
||
|
the request ``.EQ'' and inline equation event handlers to intercept the
|
||
|
<i>eqn
|
||
|
</i>input.<tt> </tt>
|
||
|
In this case, the
|
||
|
<i>eqn
|
||
|
</i>preprocessor need only be invoked if
|
||
|
<i>filter-eqn-line
|
||
|
</i>returned #t at least once.<tt> </tt>
|
||
|
<h2>
|
||
|
(skip-group)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>This primitive reads input lines from the current input stream
|
||
|
and scans them for the escape sequences `\{' and `\}' until
|
||
|
the nesting level of conditional input is balanced (i.e. until
|
||
|
a matching closing brace for an initial opening brace has been found).<tt> </tt>
|
||
|
The primitive is only useful for the implementation of the
|
||
|
troff requests for conditional input.<tt> </tt>
|
||
|
<h2>14. <tt> </tt>File Insertions
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>The primitive
|
||
|
<i>file-insertions
|
||
|
</i>is a general-purpose utility for inserting strings into files
|
||
|
at specified locations in a fast and robust way.<tt> </tt>
|
||
|
One application is to resolve forward references of any kind among
|
||
|
a group of files when all files have been processed.<tt> </tt>
|
||
|
In this case, the insertions would be executed by an
|
||
|
<i>exit
|
||
|
</i>event handler.<tt> </tt>
|
||
|
<h2>
|
||
|
<a name=".file-insertions">(file-insertions <i>insertions</i>)</a></h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt><i>insertions
|
||
|
</i>is a list specifying the parameters for the file insertions.<tt> </tt>
|
||
|
Each element of the list is itself a list consisting
|
||
|
of a file name (a string),
|
||
|
a file offset (an integer between zero and the size of the file),
|
||
|
and a string to be inserted in the given file at the given offset.<tt> </tt>
|
||
|
<i>file-insertions
|
||
|
</i>sorts the list to ensure that each file is only processed once
|
||
|
and that the offsets for each file are in increasing order.<tt> </tt>
|
||
|
Then each file is copied to a temporary file
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
<i>filename</i>.new
|
||
|
</pre>
|
||
|
</dl>
|
||
|
(where
|
||
|
<i>filename
|
||
|
</i>is the original file name), and the specified insertions are
|
||
|
carried out as the file is copied.<tt> </tt>
|
||
|
When processing of a file is finished, the temporary file is
|
||
|
renamed to its original name.<tt> </tt>
|
||
|
If there exist links to a file, a warning is displayed and the
|
||
|
insertion is skipped.<tt> </tt>
|
||
|
<h2>15. <tt> </tt>Utilities for Back-Ends
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Writers of new back-ends (either for new output formats or for new
|
||
|
troff macro packages) can benefit from a number of Scheme procedures
|
||
|
and macros that are exported by the file ``scm/troff.scm'' which is
|
||
|
loaded from the library directory on startup.<tt> </tt>
|
||
|
The first two,
|
||
|
<i>eval-if-mode
|
||
|
</i>and
|
||
|
<i>set-option!
|
||
|
</i>are exceptions in that they are typically used by the user's
|
||
|
initialization file ``~/.unroff'' to customize
|
||
|
<i>unroff</i>,
|
||
|
rather than by programmers of
|
||
|
<i>unroff</i>.<tt> </tt>
|
||
|
<h2>
|
||
|
(set-option! <i>name</i> <i>value</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>This procedure assigns
|
||
|
<i>value
|
||
|
</i>to the option
|
||
|
<i>name</i>.<tt> </tt>
|
||
|
The value must be appropriate for the option's type.<tt> </tt>
|
||
|
<h2>
|
||
|
(eval-if-mode <i>mode</i> <i>.</i> <i>forms</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>This macro is typically used to evaluate a sequence of expressions,
|
||
|
<i>forms</i>,
|
||
|
depending on the output format and macro package specified in
|
||
|
the command line.<tt> </tt>
|
||
|
<i>mode
|
||
|
</i>is a list of two symbols, an output format and a macro package
|
||
|
name; the wildcard `*' can be used for both elements.<tt> </tt>
|
||
|
The
|
||
|
<i>forms
|
||
|
</i>are evaluated if the first symbol matches the value of the option
|
||
|
<b>-f
|
||
|
</b>and the second symbol matches the value of the option
|
||
|
<b>-m</b>;
|
||
|
in this case the result of the last sub-expression is returned.<tt> </tt>
|
||
|
Otherwise the forms are ignored and #f is returned.<tt> </tt>
|
||
|
Example:
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
(eval-if-mode (* html)
|
||
|
(set-option! 'mail-address "net@cs.tu-berlin.de"))
|
||
|
</pre>
|
||
|
</dl>
|
||
|
<h2>
|
||
|
(quit <i>message</i> <i>.</i> <i>args</i>)
|
||
|
<br>
|
||
|
(warn <i>message</i> <i>.</i> <i>args</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>These procedures print
|
||
|
<i>message
|
||
|
</i>and the optional
|
||
|
<i>args
|
||
|
</i>on the port returned by
|
||
|
<i>error-port
|
||
|
</i>using the primitive
|
||
|
<i>format</i>.<tt> </tt>
|
||
|
The message is prefixed by the program name, current input file
|
||
|
name and line number, and, in case of
|
||
|
<i>warn</i>,
|
||
|
the word ``warning''.<tt> </tt>
|
||
|
A newline is appended.<tt> </tt>
|
||
|
<i>quit
|
||
|
</i>causes the program to exit with an exit code of 1, and
|
||
|
<i>warn
|
||
|
</i>returns the empty string (and can therefore be used as the last
|
||
|
form in event procedures).<tt> </tt>
|
||
|
<h2>
|
||
|
<a name=".options">(option <i>name</i>)</a></h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Returns the value of the specified option.<tt> </tt>
|
||
|
<h2>
|
||
|
(define-option <i>name</i> <i>type</i> <i>initial</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Defines a new option with the specified name, type, and initial
|
||
|
value.<tt> </tt>
|
||
|
<i>name
|
||
|
</i>and
|
||
|
<i>type
|
||
|
</i>are strings or symbols.<tt> </tt>
|
||
|
There exist a number of predefined, basic option types as
|
||
|
described in the
|
||
|
<a href="./unroff.1.html">manual page</a>
|
||
|
<i>unroff</i>(1).<tt> </tt>
|
||
|
The initial value need not match the option's type; for example,
|
||
|
the following expression is valid:
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
(define-option 'author 'string #f)
|
||
|
</pre>
|
||
|
</dl>
|
||
|
<h2>
|
||
|
(define-option-type <i>name</i> <i>pre-check</i> <i>pre-msg</i> <i>converter</i> <i>post-check</i> <i>post-msg</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>This procedure defines a new option type named
|
||
|
<i>name
|
||
|
</i>which can then be used in calls to
|
||
|
<i>define-option</i>.<tt> </tt>
|
||
|
If an option of this type is specified in the command line,
|
||
|
the procedure
|
||
|
<i>pre-check
|
||
|
</i>is applied to the option's value (a string).<tt> </tt>
|
||
|
In this case, if
|
||
|
<i>pre-check
|
||
|
</i>returns #f,
|
||
|
<i>quit
|
||
|
</i>is called with an error message including the string
|
||
|
<i>pre-msg</i>,
|
||
|
which should describe the expected option value format
|
||
|
(e.g. ``a character'').<tt> </tt>
|
||
|
If the check succeeds, the procedure
|
||
|
<i>converter
|
||
|
</i>is called with the option's current value and with the string as given
|
||
|
in the command line.<tt> </tt>
|
||
|
The job of the converter procedure is to convert the option value
|
||
|
from a string representation to a Scheme object matching the option's
|
||
|
actual Scheme type.<tt> </tt>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Finally, the predicate
|
||
|
<i>post-check
|
||
|
</i>is applied either to the result of
|
||
|
<i>converter
|
||
|
</i>or, if the option was set through a call to
|
||
|
<i>set-option!</i>,
|
||
|
to this procedure's argument.<tt> </tt>
|
||
|
If the predicate returns #f, a error is signaled with an error
|
||
|
message including
|
||
|
<i>post-msg
|
||
|
</i>as described in the previous paragraph.<tt> </tt>
|
||
|
For example, the predefined option type ``boolean'' is defined as
|
||
|
follows:
|
||
|
<dl><dt><dd>
|
||
|
<pre>
|
||
|
(define-option-type 'boolean
|
||
|
(lambda (x) (member x '("0" "1"))) "0 or 1"
|
||
|
(lambda (old new) (string=? new "1"))
|
||
|
boolean? "a boolean")
|
||
|
</pre>
|
||
|
</dl>
|
||
|
<h2>
|
||
|
(with-input-from-stream <i>target</i> <i>.</i> <i>forms</i>)
|
||
|
<br>
|
||
|
(with-output-to-stream <i>target</i> <i>.</i> <i>forms</i>)
|
||
|
<br>
|
||
|
(with-output-appended-to-stream <i>target</i> <i>.</i> <i>forms</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>These macros open an input stream (first macro) or output stream to the
|
||
|
specified target and assign it to the current input stream (first
|
||
|
macro) or current output stream.<tt> </tt>
|
||
|
Then the specified
|
||
|
<i>forms
|
||
|
</i>are evaluated, the stream is reassigned its previous value, and
|
||
|
the result of the last sub-expression in
|
||
|
<i>forms
|
||
|
</i>is returned.<tt> </tt>
|
||
|
The macros recur on the primitives
|
||
|
<i>open-input-stream</i>,
|
||
|
<i>open-output-stream</i>,
|
||
|
and
|
||
|
<i>append-output-stream</i>,
|
||
|
respectively.<tt> </tt>
|
||
|
<h2>
|
||
|
(skip-lines <i>stop</i>)
|
||
|
</h2>
|
||
|
<p>
|
||
|
 <tt> </tt> <tt> </tt> <tt> </tt>Reads input lines using
|
||
|
<i>read-line-expand
|
||
|
</i>until either end-of-stream is reached (in this case a warning
|
||
|
is displayed) or a line matching the string argument
|
||
|
<i>stop
|
||
|
</i>is encountered.<tt> </tt>
|
||
|
<h2>Footnotes</h2>
|
||
|
<p>
|
||
|
<b><a name="footnote1">[1]</a></b> <tt> </tt>Although the result of specific event handlers defined for
|
||
|
strings is not rescanned, the handler for `\*' that is supplied by
|
||
|
<i>unroff
|
||
|
</i>to implement user-defined strings does rescan the contents of
|
||
|
a string when it is expanded.<tt> </tt>
|
||
|
<p>
|
||
|
<b><a name="footnote2">[2]</a></b> <tt> </tt>While #f indicates ``standard output'' when assigned to
|
||
|
the current output stream, it is an error to call an input primitive
|
||
|
after #f has been assigned to the current
|
||
|
<i>input
|
||
|
</i>stream.<tt> </tt>
|
||
|
This may be considered a mis-feature; the current input and
|
||
|
output streams should be treated similarly with respect to
|
||
|
standard input and standard output.<tt> </tt>
|
||
|
<p>
|
||
|
<b><a name="footnote3">[3]</a></b> <tt> </tt><i>stream->string
|
||
|
</i>is a misnomer, because the argument of the primitive is not
|
||
|
a stream, nor does the primitive actually
|
||
|
<i>convert
|
||
|
</i>a stream to a string as suggested by the `->' sign.<tt> </tt>
|
||
|
<p>
|
||
|
<b><a name="footnote4">[4]</a></b> <tt> </tt>The primitive
|
||
|
<i>error-port
|
||
|
</i>should actually be provided by Elk proper to avoid having to
|
||
|
reinvent it for each extensible application.<tt> </tt>
|
||
|
<p>
|
||
|
<b><a name="footnote5">[5]</a></b> <tt> </tt>The primitive
|
||
|
<i>parse-triple
|
||
|
</i>should probably return a proper list rather than an improper list.<tt> </tt>
|
||
|
<p><hr>
|
||
|
Markup created by <em>unroff</em> 1.0, <tt> </tt> <tt> </tt>March 21, 1996, <tt> </tt> <tt> </tt>net@informatik.uni-bremen.de</body>
|
||
|
</html>
|