# troffcvt Action Reference

Paul DuBois
dubois@primate.wisc.edu

Wisconsin Regional Primate Research Center
Revision date: 11 April 1997

## Introduction

When troffcvt executes, it reads one or more action files which instruct it how to interpret troff requests. The default action file is named actions; this file is read before any other action files or any macro packages named on the command line. You should understand the format of action files if you want to modify the default action file or if you want to write your own action files.

This document describes the syntax of action files, and discusses how actions work. This includes argument parsing and transmission of argument values. It also includes a list of the available actions.

## General Syntax

Action files are plain text files. Blank lines are ignored, as are lines beginning with "#" in column 1, which are taken as comments. Other lines should begin with imm or req and have the following syntax:

   imm immediate-actions
req request-name parsing-actions eol post-parsing-actions

imm and req lines may be continued onto the next line with a "\" as the last character.

An imm line specifies actions to be executed as soon as they are read from an action file. (No output can be generated from imm lines because troffcvt turns off output while action files are being read.)

A req line describes what troffcvt should do when a given request occurs in the input. request-name is the name of the request (without the leading period). parsing-actions is either empty or a list of actions to perform to parse the request arguments. eol is mandatory and causes troffcvt to skip to the end of the request line. post-parsing-actions is either empty of a list of actions to perform after the request arguments have been parsed; typically these actions process the arguments parsed by the parsing arguments.

To include whitespace in an argument that is passed to an action, you can surround it with either single or double quote characters. For example:

   push-string ".tm this is an argument with whitespace\n"
push-string '.tm this is an argument with whitespace\n'

To include a quote within such an argument, you must quote it with the other quote character. For example:
   push-string ".tm this is a single-quote: '\n"
push-string '.tm this is a double-quote: "\n'


## Argument Processing

### Argument Collection

Several actions are available to parse various kinds of request line arguments, e.g., numbers, macro arguments, single characters. Most parsing routines read arguments from the request line, store them in the request argument vector rargv[], and bump the request argument count rargc. Arguments stored this way are available to other actions, which refer to them as $1,$2, etc.

A few parsing routines do not store the arguments in rargv[] but instead act on them directly. For example, parse-tab-stops reads the tab values and sets the current stops directly. parse-condition reads and tests the condition, then executes or skips the rest of the conditional request line.

### Argument Transmission -- General

Before an argument is passed to an action, it is examined to see whether it contains references to request arguments or to escape sequences. The legal references and sequences are shown below along with their meanings:

   $n Becomes the n-th request argument, empty if unavailable $$Becomes the number of arguments parsed from request line * Becomes a string consisting of all arguments, space-separated @ Like *, but arguments are double-quoted as well \\ Becomes \ \n Becomes a linefeed \t Becomes a tab \X Becomes X, for any character not listed above  An empty string is substituted for a request argument if n is not a digit, if there is no such argument, if the argument was empty, or if the action occurs in an immediate action list. Note that * and @ produce a single string, and thus count as a single argument when passed to an action. Quotes may be used around an action argument to include whitespace in the argument. However, as noted in the "General Syntax" section, to include a single quote within an argument, you must quote the argument with double quotes, and vice-versa. Example: The following has defines a string as the second argument if the first argument isn't empty:  push-string '.if !"1"" .ds 1 "2\n'  ### Argument Transmission -- Numeric Arguments The parse-num action is used to parse a number from the request line. It takes one argument, a scaling indicator used to scale numbers in request argument expressions that don't have explicit scaling indicators. For example, the .sp request can be specified like this:  req sp parse-num v eol break space 1  In this case parse-num uses v's as the default scaling. Then the arguments to the requests  .sp 1 .sp 1i .sp 1i+1  will be interpreted as "1v", "1i" and "1i+1v", respectively. (The "i", where present, overrides the default of v). In each case, after parse-num finishes evaluating the expression, the result is converted into basic units, and that is what is stored in the request argument vector. If the resolution is 432 units/inch and a v is 72 units, the arguments for the three requests above would be stored as the strings "72", "432" and "504". In other words, the value stored may not look much like the value on the request line. Allowable scaling indicators are i (inches), c (centimeters), P (picas), m (ems), n (ens), p (points), v (vertical spacing units), u (basic units) and x (ignore scaling). The x specifier is special; it means there is no default, numbers are interpreted without scaling, and the result stored in the request argument vector is not converted to basic units. This is appropriate for requests such as .ce or .ls, which may be specified like so:  req ce parse-num x eol center 1 req ls parse-num x eol line-spacing 1  If a request parsing action attempts to parse an argument that is not present on the request line or that does not conform to what the action is looking for, the request-parsing action stores an empty string in the rargv[] array. Functions for actions that allow arguments to be missing (empty) must be written to test for that case. Actions that take numeric parameters usually expect that the number be given in basic units, unless an explicit scaling indicator is appended. The reason for this is that numeric arguments to actions are generally obtained from parsing actions earlier in the action list, and those will usually have been converted to basic units. This means that even for actions used in imm lines, the same convention must be followed. Thus, the two lines following have very different results:  imm space 12 Set spacing to 12 units imm space 12p Set spacing to 12 points  ### Argument Transmission -- Relative-Change Requests Some requests allow parameter values to be changed either to an absolute value, or relatively by a specified amount. Examples:  .ps 3 Set point size to 3 points .ps +3 ... to 3 points greater than current value .nr x 4 Define number register with initial value 4 .nr x +4 ...with initial value 4 greater than current value  This kind of request is handled with the parse-absrel-num action. parse-absrel-num is like parse-num in that it takes a default scaling indicator, but it also takes a second argument which specifies the current value of the relevant parameter. Since you can't specify the current value literally in an action file (the current value is a volatile value), you can refer to the parameter symbolically. The parameters which may be referred to this way are point-size, spacing, line-spacing, indent, line-length, page-length, title-length and offset. Example: the current indent may be set absolutely or relative to the current value, so it may be specified like this:  req in parse-absrel-num m indent eol break indent 1  If the argument on an .in request begins with a plus or minus sign, the sign is stripped, the rest of the argument is evaluated to produce a number, and the result is the current indent modified up or down by that number. (The result does not modify the current indent; it is simply stored in rargv[].) If there is no initial sign, the request argument is an absolute number and the parse result is simply the value of the argument (the current indent value is ignored). In the example above, the result goes into 1. The second reference to indent is as an action, which is what actually sets the indentation (to the value of 1). As a special-case hack, if the current-value argument to parse-absrel-num begins with a backslash, the rest of the argument is taken as the name of a number register, and the value of the register is used. This is used in relation to the .nr request, which allows a register to be redefined relative to its current value. .nr can be specified in an action file as:  req nr parse-name parse-absrel-num u \\1 parse-num x eol define-register 1 2 3  It is necessary that parse-num and parse-absrel-num both exist, because an expression such as "-10+10" means "0" as an absolute number, but "decrease by 20" as a relative number. ## Action Descriptions Each action is discussed below. Action descriptions are accompanied by one or more of the following indicators to specify the allowable contexts in which the action can be used:  imm Allowable in imm lines p Allowable in argument parsing section of req lines pp Allowable in post-parsing section of req lines  Whenever you specify an action in an action list, you must specify all the arguments that it expects. However, an argument often can be the empty string. Thus escape-char @ sets the escape character to "@" while escape-char "" restores the default escape character. abort string (pp, imm) Aborts troffcvt after printing string on stderr. If string is empty, "User abort" is printed instead. adjust c (pp, imm) Turns on output line adjusting, with mode c, which can be l (left), c (center), r (right), b or n (both), or a number previously obtained from the .j register. An adjustment indicator is written to the output if the request changes the current adjustment and centering is off and filling is on. If c is empty, adjustment is turned on with whatever the current mode is. alias-macro xx yy (pp, imm) Create the name xx as an alias for macro, string, or request yy. This implements the groff .als request. The two names become equivalent. .xx continues to exist even if .yy is removed. If .yy is redefined, .xx becomes redefined as well. Actually, there is one difference between aliased names, which is that \0 in the macro refers to the actual name under which the macro was invoked, not the name under which it was first created. alias-register xx yy (pp, imm) Like alias-macro but for number registers. This implements the groff .aln request. append-macro xx yy (pp) Like define-macro but appends to an existing macro definition. append-string xx value (pp, imm) Like define-string but appends to an existing string. begin-page N (pp, imm) If N is empty, writes \begin-page. Otherwise, writes \begin-page N and sets the current page number and register % to N. break (pp, imm) Causes a break (writes a \break line) unless the no-break control character was given on the request or unless the current output line doesn't have anything on it. None of the action functions do a break except that for break itself, so it should be specified in the action list for any request that normally causes a break. The reason for this is to make sure complete control over when a break occurs is in the action file, not inside troffcvt. This is more work for the action file writer, but provides more flexibility. For instance, .sp can be specified as "req sp parse-num v eol break space 1". The function associated with space doesn't do any break itself, so the break is necessary. center N (pp, imm) Turns on centering and writes \center to the output. troffcvt will generate additional control output to turn off centering after N lines of text input have been read (1 line if N is empty). constant-width F N M (pp, imm) Treat font F as a constant-width font. See the troff manual for the interpretation of N and M. continuous-underline N (pp, imm) Turns on continuous underlining and writes \cunderline to the output. Continuous underlining is turned off after N lines of text input (1 line if N is empty). debug-flag N (p, pp, imm) Turns on debugging flag bit N. The allowable values are listed in troffcvt.h and are not of general interest. If N is empty, all flags are turned on. If N is negative, all flags are turned off. define-macro xx yy (pp) Defines a macro named xx. Reads input in copy mode until a line of the form .yy is found, at which point .yy is invoked. If yy is empty, a line of the form .. terminates the definition. define-register xx init incr (pp, imm) Defines number register xx with initial value init and increment value incr. define-string xx value (pp, imm) Defines string xx with value value. diversion-append xx (pp) Like diversion-begin but writes \diversion-append xx to the output instead. diversion-begin xx (pp) Writes \diversion-begin xx to the output. When a matching .di or .da is seen, \diversion-end xx is written. dump-bad-requests N (pp, imm) If N is non-zero, any unrecognized requests are written to the output in the form:  \other bad-req: original input line  If N is zero, this kind of output is suppressed. dump-input-stack (pp, imm) Dump information about the input stack to stderr. This is for debugging. dump-macro xx (p, pp, imm) Dumps the body of macro xx to stderr. This is for debugging. echo string (p, pp, imm) Writes string to stderr. embolden S F N (pp, imm) This request takes three arguments, but the arguments can actually be F and N rather than S, F, and N. It's necessary to examine the first argument to tell. Emboldens font F by smearing it N units. If S is present, embolden the special font by N units when the current font is F. end-input (pp) Forces input routines to return end-of-input to cause troffcvt to finish processing immediately. end-macro xx (pp, imm) Causes macro xx to be invoked after all other input has been processed. xx must be a macro, not a request. environment name (pp, imm) Enters environment name or resume previous environment if the argument is empty. eol (p) Skips to the end of the current input line. This action must terminate the parsing action section of all req lines. fill (pp, imm) Turns on fill mode. font F (pp, imm) Switches to font F, writing \font F to the output if this causes a font change. font-position N F (pp, imm) Associates font F with position N. flush (pp, imm) Flush any pending output. Similar to break, but doesn't write \break. hyphenate mode (pp, imm) Sets the hyphenation mode, which should be zero to turn off hyphenation, or a positive value as described in the troff manual. hyphen-char c (pp, imm) Sets the hyphenation character to c. ignore yy (pp, imm) Input is read in copy mode but otherwise ignored until a line of the form .yy is found, at which time .yy is invoked. If yy is empty, a line of the form .. terminates the ignore action. indent N (pp, imm) Sets indent to N. input-trap N xx (pp) Sets the input-line trap to xx, to spring after N input lines. xx must be a macro, not a request. line-length N (pp, imm) Sets line length to N. line-spacing N (pp, imm) Sets line spacing to N. need N (pp, imm) Indicate that N lines are needed on the current output page. If not that many lines are available, postprocessors that pay attention to this information typically will perform a page break. no-space c (pp, imm) Turns on no-space mode if the argument is y, off if it's n. noadjust (pp, imm) Turns off output line adjusting. noescape (pp, imm) Turns off escape processing. nofill (pp, imm) Turns on no-fill mode. offset N (pp, imm) Sets offset to N. output-control string (pp, imm) Writes string directly to the output, preceded by a \ character and followed by a newline. output-special string (pp, imm) Writes string directly to the output, preceded by a @ character and followed by a newline. output-text string (pp, imm) Writes string directly to the output. page-length N (pp, imm) Sets page length to N. page-num-char c (pp, imm) Sets the page number character (used in titles) to c. page-number N (pp, imm) Sets the current page number and the % register to N. Writes no output. parse-absrel-num c N (p) Parses a number or numeric expression from the request line, which may be absolute, or relative to N. c is the default scaling unit to be used in evaluating expressions. parse-char (p) Parses a single-character argument from the request line. parse-condition c (p) Parses a condition from the request line, tests it, and executes or skips the rest of the line depending on the result of the test. c should be y if a following else-clause should be expected later (as for .ie) or n if it should not be (as for .if). parse-embolden (p) An ugly hack used for the .bd request. Parses both forms of the request, which are:  .bd F N .bd S F N  The resulting argument vector will have either two or three elements. parse-filename (p) Parses a filename from the request line. parse-macro-args (p) Parses all remaining arguments (in copy mode) to the end of the request line. Arguments on request lines are separated by spaces, or may be double-quoted to include whitespace in an argument. Note that a numeric argument is not evaluated in the same manner as for the number-parsing actions. To get around this, you can later interpolate the argument into a string that's processed with push-string:  # assume first argument, if present, is numeric expression to set indent. req XX parse-macro-args eol push-string ".if$$>0 .in$1\n"


parse-name (p)

Parses a name of the form from the request line. This action is used to pick up single string, macro, register, etc. names. If compatibility mode is on, the name can be no more than two characters long.

parse-names (p)

Like parse-name, but parses multiple names to the end of the input line.

parse-num c (p)

Parses a number or numeric expression from the request line. c is the default scaling unit to be used in evaluating expressions.

parse-string-value c (p)

Parses a string in copy mode to the end of the input line. c should be y if a leading double quote should be stripped off (as for .ds) or n if it should not be (as for .ab and .tm).

parse-tab-stops (p)

Parses the rest of the request line for tab stop settings. If there are none, \reset-tabs is written, which should be taken as meaning reset tab stops to "every half inch". (The troff manual doesn't specify how many stops are allowed; presumably postprocessors should allow for "several".)

If explicit stops are given, the first one is written out as \first-tab N c, and any following are written as \next-tab N c. When \first-tab is seen, the postprocessor should clear any stops and begin collecting new ones. Each \next-tab setting should be added to the current list. N is specified in basic units. c is l (left), c (center) or r (right).

parse-title (p)

Parses a title of the form ´left´center´right´ from the request line into three elements of rargv[]. Missing title elements become empty arguments in rargv[].

parse-transliteration (p)

Parses a transliteration list from the request line.

point-size N (pp, imm)

Sets the point size to N. N is number of points (unscaled), not basic units.

process-condition (p)

Executes or skips conditional input. This is used for the .el request, and tests whether the preceding matching .ie succeeded or failed.

process-do (p)

This action implements the groff .do request. Parses the rest of the input line with compatibility mode disabled, then executes the line. The rest of the line must contain a request, but not begin with a control character. The control character that begins the do line (. or ´) is used to begin the request.

push-file filename (pp)

Pushes the given file onto the input stack.

push-macro-file filename (pp)

Like push-file, but looks for the file in the same directories used to find macro files. This implements the groff .mso request.

push-string string (pp, imm)

Pushes the given string onto the input stack and processes it. To push a named string onto the stack, use one of the following forms:
   \push-string "\*x"
\push-string "\*(xx"
\push-string "\*[xxx]"

To push a request or macro onto the stack, use:
   \push-string ".xx\n"

It can be dangerous to use push-string in immediate mode, since your execution environment may not yet be fully set up. That is, although you can process a string immediately using an imm line, you should make sure that any requests or macros named in the string have been defined, or they'll be ignored.

register-format xx format (pp, imm)

Assigns the given format to number register xx.

remove-name c name (pp, imm)

Removes a name. c is y if the name refers to a number register, n if the name refers to a request, string, or macro.

remove-names c name1 name2 name3 name4 name5 name6 name7 name8 name9 (pp, imm)

Multiple-name form of remove-name. There must be nine name arguments specified, but arguments may be given as empty strings if you're not removing nine names.

rename xx yy (pp, imm)

Renames request, macro, or string xx to yy.

set-compatibility N (pp, imm)

Sets compatibility mode to N, which turns the mode on if N is non-zero. When compatibility mode is off, recognition of long request, macro, string, register, and font names is suppressed. This action also sets the .C read-only register.

set-control c (pp, imm)

Sets control character to c (. if c is empty).

set-control2 c (pp, imm)

Sets no-break control character to c (´ if c is empty).

set-escape c (pp, imm)

Restores escape processing, setting escape character to c (\ if c is empty). c cannot be an escaped or \(xx special character, since then it would be recursive.

Sets field delimiter character to delim and field padding character to pad. If pad is empty, the pad character becomes space. If delim and pad are both empty, the field mechanism is turned off.

Sets leader repetition character to c or remove it if c is empty.

set-tab c (pp, imm)

Sets tab repetition character to c or remove it if c is empty.

shift-args N (pp, imm)

In a macro, shifts the arguments left by N arguments. If N is empty, the arguments are shifted left by one place. If N is negative or zero, nothing is done. If N is equal to or greater than the number of arguments the macro has, all the arguments are shifted.

space N (pp, imm)

Spaces vertically by N units (negative = upward).

space-size N (pp, imm)

Sets space size to N/36m. N is unscaled, not in basic units.

spacing N (pp, imm)

Sets vertical base-line spacing to N units. 1 v then becomes N units.

special-char xx output (pp, imm)

Defines a special character with the given name and output sequence. The name cannot be empty and must consist of plain ASCII characters. The output sequence is the string that should be written when the character is referenced. It too cannot be empty and must consist of plain ASCII characters. special-char is used in imm lines in action files to define the set of special characters that troffcvt should recognize. This set should reflect the characters known by local versions of troff.

switch-file name (pp)

Switches the current input file to name.

temp-indent N (pp, imm)

Sets the temporary indent to N.

title left middle right (pp, imm)

Processes a three-part title.

title-length N (pp, imm)

Sets the title length to N.

transliterate list (pp, imm)

list should contain pairs of characters. The first element of each pair will be transliterated into the second element on output. If the list has an odd number of characters, the last is transliterated to a space.

underline N (pp, imm)

Turns on underlining and writes \underline to the output. Underlining is turned off after N lines of text input. troffcvt will generate additional control output to turn off underlining after N lines of text input have been read (1 line if N is empty).

underline-font F (pp, imm)

Sets the underline font to F.

## Creating a New Action

If the set of actions is insufficient for your purposes, here's how to modify troffcvt to write a new one:

• Read the rest of this section, then study some of the existing actions in troffcvt source code to see how they are implemented.
• Pick a name for the action. This will be the name used in action files to refer to it.
• Decide whether the function used to implement the action should take any arguments, that is, whether the action should be followed by any arguments when used in an action file. You must also decide whether it should be allowed on imm lines and/or req lines (and if allowed on the latter, whether allowed in the post-parsing or parsing sections, or both).
• List the action in the aiTab[] array in action.c, and add an extern for the function to troffcvt.h.
• Write the action function. If the action parses arguments, the function goes in parse.c, otherwise it goes in req.c. It should be declared like this:
   int
ActionFunction (int argc, XChar **argv)
{
}

The function should perform the action and return non-zero for success, zero for failure. Possibly it should simply panic if something catastrophic (unrecoverable) happens. Note that sometimes it is useful to return non-zero for certain kinds of failures. If an action in an action list returns zero, no actions following it in an action list are executed. If you want them to execute anyway, your function should always return non-zero.
argc is the number of action arguments and argv is an array of pointers to them. (There is a NULL pointer following the last argument, i.e., argv[argc] is NULL.)
The function should make no direct reference to the request values rargc and rargv[] unless it is an argument parsing action. If your action can be used on imm lines, there won't be any request arguments available. It's also a good idea for the function to refrain from modifying the arguments passed to it. (Make copies first and modify the copies.)