Hi Russ, At 2022-12-23T14:42:42-0800, Russ Allbery wrote: > Incidentally, the rules for the second argument to .ds appear to not > follow the normal rules for macro arguments. > > .ds C` "" > > defines \*(C` to a single double-quote, but: > > .ds C` """" > > defines \*(C` to """, not to " as one might expect if that were > interpreted as a quoted argument and then adjacent doublequotes become > a literal double quote. > > So far as I can tell, the correct rule for escaping the second > argument to .ds is that you should double any *leading* double quote, > but leave all the other double quotes alone. > > .ds C` " > > appears to define \*(C` to the empty string.
These are all correct statements. There are two major points to make here. 1. Request invocations are not macro calls. So all that stuff about double quotes we were talking about doesn't apply here. :( Sorry about that. That was a language design decision made literally before I was born. 2. `ds` and related requests (like `as`) are unusual even among requests in that they treat the entire remainder of the input line as a single argument. > (I'm not sure where this all might be documented.) Would it surprise you to learn that I've rewritten parts of groff's Texinfo manual to discuss these matters in detail? ;-) --snip-- 5.1.7 Requests and Macros ------------------------- We have now encountered almost all of the syntax there is in the 'roff' language, with an exception already noted in passing. A "request" is an instruction to the formatter that occurs after a "control character", which is recognized at the beginning of an input line. The regular control character is a dot ('.'). Its counterpart, the "no-break control character", a neutral apostrophe ('''), suppresses the break that is implied by some requests. These characters were chosen because it is uncommon for lines of text in natural languages to begin with them. If you require a formatted period or apostrophe (closing single quotation mark) where GNU 'troff' is expecting a control character, prefix the dot or neutral apostrophe with the non-printing input break escape sequence, '\&'. An input line beginning with a control character is called a "control line". Every line of input that is not a control line is a "text line".(1) (*note Requests and Macros-Footnote-1::) Requests often take "arguments", words (separated from the request name and each other by spaces) that specify details of the action GNU 'troff' is expected to perform. If a request is meaningless without arguments, it is typically ignored. GNU 'troff''s requests and escape sequences comprise the control language of the formatter. Of key importance are the requests that define macros. Macros are invoked like requests, enabling the request repertoire to be extended or overridden.(2) (*note Requests and Macros-Footnote-2::) [...] (1) The <\RET> escape sequence can alter how an input line is classified; see *note Line Continuation::. (2) Argument handling in macros is more flexible but also more complex. *Note Calling Macros::. [...] 5.6.2 Invoking Requests ----------------------- A control character is optionally followed by tabs and/or spaces and then an identifier naming a request or macro. The invocation of an unrecognized request is interpreted as a macro call. Defining a macro with the same name as a request replaces the request. Deleting a request name with the 'rm' request makes it unavailable. The 'als' request can alias requests, permitting them to be wrapped or non-destructively replaced. *Note Strings::. There is no general limit on argument length or quantity. Most requests take one or more arguments, and ignore any they do not expect. A request may be separated from its arguments by tabs or spaces, but only spaces can separate an argument from its successor. Only one between arguments is necessary; any excess is ignored. GNU 'troff' does not allow tabs for argument separation.(1) (*note Invoking Requests-Footnote-1::) Generally, a space _within_ a request argument is not relevant, not meaningful, or is supported by bespoke provisions, as with the 'tl' request's delimiters (*note Page Layout::). Some requests, like 'ds', interpret the remainder of the control line as a single argument. *Note Strings::. Spaces and tabs immediately after a control character are ignored. Commonly, authors structure the source of documents or macro files with them. [...] (1) In compatibility mode, a space is not necessary after a request or macro name of two characters' length. Also, Plan 9 'troff' allows tabs to separate arguments. [...] 5.22 Strings ============ GNU 'troff' supports strings primarily for user convenience. Conventionally, if a macro definition needs only to interpolate text, without invoking any requests or calling any other macros, a string is defined instead. Only one string is predefined by the language. -- 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 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. *Note Warnings::, for information about the enablement and suppression of warnings. -- 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. If NAME already exists, it is removed first (see 'rm' below). If 'ds' is called with only one argument, NAME is defined as an empty string. The '\*' escape sequence interpolates a previously defined string variable NAME (one-character name N, two-character name NM). The bracketed interpolation form accepts arguments that are handled as macro arguments are; recall *note 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. '\\*' is interpreted even in copy mode (*note Copy Mode::). When defining strings, argument interpolations must be escaped if they are to reference parameters from the calling context; *Note Parameters::. .ds cite (\\$1, \\$2) Gray codes are explored in \*[cite Morgan 1998]. => Gray codes are explored in (Morgan, 1998). *Caution:* Unlike other requests, the second argument to the 'ds' request consumes the remainder of the input line, including trailing spaces. This means that comments on a line with such a request can introduce unwanted space into a string when they are set off from the material they annotate, as is conventional. .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 empty \" might be appended to later with .as An initial neutral double quote '"' in CONTENTS is stripped to allow embedding of leading spaces. .ds salutation " Yours in a white wine sauce,\" .ds c-var-defn " char build_date[]="2020-07-29";\" .ds sucmd sudo sh -c "fdisk -l /dev/sda > partitions"\" 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. .ds foo This string contains \ text on multiple lines \ of input. 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 *note Punning Names::. [...stuff about compatibility mode and the `ds1` request...] -- 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 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,\" [...stuff about compatibility mode and the `as1` request...] 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'). --snip-- As I noted in a previous mail, some will claim that no factual aspect of the above presentation is absent from CSTR #54 (apart from groff "deviations"). I invite the reader to test such claims for themselves. Regards, Branden
signature.asc
Description: PGP signature