GNU troff
supports strings primarily for user convenience.
Conventionally, if one would define a macro only to interpolate a small
amount of text, without invoking requests or calling any other macros,
one defines a string instead. Only one string is predefined by the
language.
\*[.T]
¶Contains the name of the output device (for example, ‘utf8’ or ‘pdf’).
The ds
request creates a string with a specified name and
contents and the \*
escape sequence dereferences its name,
interpolating its contents. If the string named by the \*
escape
sequence does not exist, it is defined as empty, nothing is
interpolated, and a warning in category ‘mac’ is emitted.
See Warnings, regarding the enablement and suppression of warnings.
.ds
name ["
][contents] ¶.ds1
name ["
][contents] ¶\*
n
¶\*(
nm
¶\*[
name [arg1 arg2 …]]
¶Define a string called name with contents contents. If
name already exists as an alias, the target of the alias is
redefined; see als
and rm
below. If ds
is called
with only one argument, name is defined as an empty string.
Otherwise, GNU troff
stores contents in copy
mode.
\*
is itself interpreted even in copy mode.105
The \*
escape sequence interpolates a previously defined string
name (one-character name n, two-character name
nm). The bracketed interpolation form accepts arguments that are
handled as macro arguments are; recall Calling Macros. In
contrast to macro calls, however, if a closing bracket ‘]’ occurs
in a string argument, that argument must be enclosed in double quotes.
When defining strings, argument interpolations must be escaped if they
are to reference parameters from the calling context; see
Parameters.
.ds cite (\\$1, \\$2) Gray codes are explored in \*[cite Morgan 1998]. ⇒ Gray codes are explored in (Morgan, 1998).
Caution:
The
ds
request treats the remainder of the input line as its second argument,
including trailing spaces,
up to a newline or comment escape sequence.
Ending string definitions
(and appendments)
with a comment,
even an empty one,
prevents unwanted space from creeping into them during source document
maintenance.
.ds H2O H\v'+.3m'\s'-2'2\v'-.3m'\s0O \" water
Instead, place the comment on another line or put the comment escape sequence immediately adjacent to the last character of the string.
.ds H2O H\v'+.3m'\s'-2'2\v'-.3m'\s0O\" water
Ending string definitions (and appendments) with a comment, even an empty one, prevents unwanted space from creeping into them during source document maintenance.
.ds author Alice Pleasance Liddell\" .ds friends \" empty; append to with .as
The formatter removes a leading neutral double quote "
in
contents to permit the embedding of leading spaces. Any other
"
is interpreted literally, but it is wise to use the special
character escape sequence \[dq]
instead if the string might be
interpolated as part of a macro argument; see Calling Macros.
.ds salutation " Yours in a white wine sauce,\" .ds c-var-defn " char mydate[]=\[dq]2020-07-29\[dq];\"
Strings are not limited to a single input line of text.
\RET
works just as it does elsewhere. The resulting string
is stored without the newlines. When filling is disabled, care
is required to avoid overrunning the line length when interpolating
strings.
.ds foo This string contains \ text on multiple lines \ of input.
Conversely, when filling is enabled, it is not necessary to append
\c
to a string interpolation to prevent a break afterward, as
might be required in a macro argument. Nor does a string require use of
the GNU troff
chop
request to excise a trailing newline
as is often done with diversions.
It is not possible to embed a newline in a string that will be
interpreted as such when the string is interpolated. To achieve that
effect, use \*
to interpolate a macro instead; see Punning Names.
Because strings are similar to macros, they too can be defined so as to
suppress AT&T troff
compatibility mode when used; see
Writing Macros and Compatibility Mode. The ds1
request defines a string such that compatibility mode is off when the
string is later interpolated. To be more precise, a compatibility
save token is inserted at the beginning of contents, and a
compatibility restore token at the end.
.nr xxx 12345 .ds aa The value of xxx is \\n[xxx]. .ds1 bb The value of xxx is \\n[xxx]. . .cp 1 . \*(aa error→ warning: register '[' not defined ⇒ The value of xxx is 0xxx]. \*(bb ⇒ The value of xxx is 12345.
.as
name ["
][contents] ¶.as1
name ["
][contents] ¶The as
request is similar to ds
but appends contents
to the string stored as name instead of redefining it. If
name doesn’t exist yet, it is created. If as
is called
with only one argument, no operation is performed (beyond dereferencing
the string).
.as salutation " with shallots, onions and garlic,\"
The as1
request works as does as
, but like ds1
, it
brackets contents with compatibility save and
restore tokens.
Several requests exist to perform rudimentary string operations.
Strings can be queried (length
) and modified (chop
,
substring
, stringup
, stringdown
), and their names
can be manipulated through renaming, removal, and aliasing (rn
,
rm
, als
).
.length
reg contents ¶Compute the number of characters in contents and store the count in the register reg. If reg doesn’t exist, it is created.
A leading neutral double quote in the argument is stripped from it, allowing embedded leading spaces in contents, which is read to the end of the input line in copy mode.
.ds xxx abcd\h'3i'efgh .length yyy \*[xxx] \n[yyy] ⇒ 14
Caution:
The
length
request treats the remainder of the input line as its second argument,
including trailing spaces,
up to a newline or comment escape sequence.
See the discussion of the
ds
request above.
.chop
object ¶Remove the last character from the macro, string, or diversion named
object. This is useful for removing the newline from the end of a
diversion that is to be interpolated as a string. This request can be
used repeatedly on the same object; see gtroff
Internals,
for details on nodes inserted additionally by GNU troff
.
.substring
str start [end] ¶Replace the string named str with its substring bounded by the indices start and end, inclusively. The first character in the string has index 0. If end is omitted, it is implicitly set to the largest valid value (the string length minus one). Negative indices count backward from the end of the string: the last character has index −1, the character before the last has index −2, and so on.
.ds xxx abcdefgh .substring xxx 1 -4 \*[xxx] ⇒ bcde .substring xxx 2 \*[xxx] ⇒ de
.stringdown
str ¶.stringup
str ¶Alter the string named str by replacing each of its bytes with its
lowercase (stringdown
) or uppercase (stringup
) version (if
one exists). Special characters in the string will often transform in
the expected way due to the regular naming convention for accented
characters. When they do not, use substrings and/or catenation.
.ds resume R\['e]sum\['e]\" \*[resume] .stringdown resume \*[resume] .stringup resume \*[resume] ⇒ Résumé résumé RÉSUMÉ
.rn
old new ¶Rename the request, macro, diversion, or string old to new.
.rm
name … ¶Remove each request, macro, diversion, or string name. GNU
troff
treats subsequent invocations as if the name had never
been defined.
This request is incorrectly documented in the AT&T
troff
manual as accepting only one argument.
.als
new-name existing-name ¶Create alias
(additional name)
new-name
of request,
string,
macro,
or diversion
existing-name,
causing the names to refer to the same stored object.
If
new-name
already exists,
its contents are lost unless already aliased.
If
existing-name
is undefined,
GNU
troff
produces a warning in category
‘mac’
and ignores the request.
See Warnings,
regarding the enablement and suppression of warnings.
To understand how the als
request works, consider two different
storage pools: one for objects (macros, strings, etc.), and another
for names. As soon as an object is defined, GNU troff
adds it to
the object pool, adds its name to the name pool, and creates a link
between them. When als
creates an alias, it adds a new name to
the name pool that gets linked to the same object as the old name.
Now consider this example.
.de foo .. . .als bar foo . .de bar . foo .. . .bar error→ input stack limit exceeded (probable infinite error→ loop)
In the above, bar
remains an alias—another name
for—the object referred to by foo
, which the second de
request replaces. Alternatively, imagine that the de
request
dereferences its argument before replacing it. Either way, the
result of calling bar
is a recursive loop that finally leads to
an error. See Writing Macros.
To remove an alias,
call
rm
on its name.
The object itself is not destroyed until it has no more names.
When a request, macro, string, or diversion is aliased redefinitions and appendments “write through” alias names. To replace an alias with a separately defined object, remove its name first.