Next: , Previous: , Up: GNU troff Reference   [Contents][Index]


5.22 Strings

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. The language prefedines only one string.

String: \*[.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, as appends to a string, and the \* escape sequence dereferences a string, interpolating its contents. If the string named by the \* escape sequence does not exist, the formatter defines it as empty and interpolates nothing.233

Request: .ds name [["]contents]
Request: .ds1 name [["]contents]
Escape sequence: \*n
Escape sequence: \*(nm
Escape sequence: \*[name [arg1 arg2 …]]

Define a string called name with contents contents. In GNU troff, if name already exists as an alias, the request replaces the contents of the alias’s target; see als and rm below. Omitting contents defines name as an empty string. Otherwise, the formatter reads contents in copy mode. \* is itself interpreted even in copy mode.234

The \* escape sequence interpolates a previously defined string name (one-character name n, two-character name nm). Its 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.235

.ds cite (\\$1, \\$2)
Gray codes are explored in \*[cite Morgan 1998].
    ⇒ Gray codes are explored in (Morgan, 1998).

Caution: After the formatter has read the space character that ends the first argument, it treats the remainder of the input line as the second argument, including any 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 Si silicon \" use chemical symbol
My tricorder indicates a \*[Si]-based life form.
    ⇒ My tricorder indicates a silicon -based life form.

Instead, place the comment on another line or put the comment escape sequence immediately adjacent to the last character of the string.

.ds Si silicon\" use chemical symbol
My tricorder indicates a \*[Si]-based life form.
    ⇒ My tricorder indicates a silicon-based life form.

Because the first space after the string name separates the arguments, you can retain it while using a comment to document an empty string.

.ds author Alice Pleasance Liddell\"
.ds friends \" empty; append to with .as

The formatter removes a leading neutral double quote ‘"’ from contents, permitting initial embedded spaces in it. It interprets any other ‘"’ literally, but the wise author uses the special character escape sequence \[dq] instead if the string might be interpolated as part of a macro argument; recall 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 oversetting the line 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 GNU troff’s chop request to excise a trailing newline as is often done with diversions.236

It is not possible to embed a newline in a string that the formatter interprets as such when interpolating it. To achieve that effect, use \* to interpolate a macro instead.237

Because strings are similar to macros, they too can be defined so as to suppress AT&T troff compatibility mode when used.238 The ds1 request defines a string such that compatibility mode is off when the string is later interpolated. To be more precise, GNU troff inserts a compatibility save token at the beginning of contents, and a compatibility restore token at the end.239

.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.
Request: .as name [["]contents]
Request: .as1 name [["]contents]

The as request is similar to ds, but appends contents to the string stored as name instead of repopulating it. If name does not already exist, the formatter creates it. Omitting contents performs no operation, beyond dereferencing (and thus possibly creating) the string.

.as salutation " with shallots, onions and garlic,\"

Caution: The formatter reads the second argument to the end of the line in copy mode, omitting any leading neutral double quote ‘"’ character. See the discussion of the ds request above.

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).

Request: .length reg [["]contents]

Compute the number of characters in contents and store the count in the register reg. If reg doesn’t exist, GNU troff creates it.

GNU troff removes a leading neutral double quote ‘"’ from contents, permitting initial embedded spaces in it, and reads it to the end of the input line in copy mode.240

.ds xxx abcd\h'3i'efgh
.length yyy \*[xxx]
\n[yyy]
    ⇒ 14

Caution: The formatter reads the second argument to the end of the line in copy mode, omitting any leading neutral double quote ‘"’ character. See the discussion of the ds request above.

Caution: If you interpolate a macro or diversion in contents,241 the length request counts characters (or nodes) only up to the first newline, and leaves the rest on the input stream. In conventional circumstances, that means the remainder is interpreted, and may be formatted. To discover the length of any string, macro, or diversion, use the pm request.242

Request: .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. You can apply chop repeatedly to the same object.243

Request: .substring str start [end]

Replace the string named str with its substring bounded by the indices start and end, inclusively. The first element of the string has index 0. Omitting end implies the largest valid value (the string length minus one). Negative indices count backward from the end of the string: the last element has index -1, the element before the last has index -2, and so on. If both start and end lie outside the string, GNU troff ignores the request.244

.ds xxx abcdefgh
.substring xxx 1 -4
\*[xxx]
    ⇒ bcde
.substring xxx 2
\*[xxx]
    ⇒ de

Compatibility save and restore tokens do not count for the purpose of index computation, even though they appear in string contents reported by the pm request and figure in the value computed by the length request.

Request: .stringdown str
Request: .stringup str

Alter the string named str by replacing each of its bytes with its lowercase (stringdown) or uppercase (stringup) version (if one exists). GNU troff’s built-in special characters often transform in the expected way due to the regular naming convention for accented characters.245 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É
Request: .rn old new

Rename the request, macro, diversion, or string old to new.

Request: .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.

Request: .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 existing-name is undefined, the formatter ignores the request.246 If new-name already exists, its contents are lost unless already aliased.

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.247

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.


Next: , Previous: , Up: GNU troff Reference   [Contents][Index]