groff: Strings

 
 5.19 Strings
 ============
 
 'gtroff' has string variables, which are entirely for user convenience
 (i.e. there are no built-in strings exept '.T', but even this is a
 read-write string variable).
 
    Although the following requests can be used to create strings, simply
 using an undefined string will cause it to be defined as empty.  See
 Identifiers.
 
  -- Request: .ds name [string]
  -- Request: .ds1 name [string]
  -- Escape: \*n
  -- Escape: \*(nm
  -- Escape: \*[name arg1 arg2 ...]
      Define and access a string variable NAME (one-character name N,
      two-character name NM).  If NAME already exists, 'ds' overwrites
      the previous definition.  Only the syntax form using brackets can
      take arguments that are handled identically to macro arguments; the
      single exception is that a closing bracket as an argument must be
      enclosed in double quotes.  SeeRequest and Macro Arguments,
      and SeeParameters.
 
      Example:
 
           .ds foo a \\$1 test
           .
           This is \*[foo nice].
               => This is a nice test.
 
      The '\*' escape "interpolates" (expands in-place) a
      previously-defined string variable.  To be more precise, the stored
      string is pushed onto the input stack, which is then parsed by
      'gtroff'.  Similar to number registers, it is possible to nest
      strings, i.e., string variables can be called within string
      variables.
 
      If the string named by the '\*' escape does not exist, it is
      defined as empty, and a warning of type 'mac' is emitted (see See
      Debugging, for more details).
 
      *Caution:* Unlike other requests, the second argument to the 'ds'
      request takes up the entire line including trailing spaces.  This
      means that comments on a line with such a request can introduce
      unwanted space into a string.
 
           .ds UX \s-1UNIX\s0\u\s-3tm\s0\d \" UNIX trademark
 
      Instead the comment should be put on another line or have the
      comment escape adjacent with the end of the string.
 
           .ds UX \s-1UNIX\s0\u\s-3tm\s0\d\"  UNIX trademark
 
      To produce leading space the string can be started with a double
      quote.  No trailing quote is needed; in fact, any trailing quote is
      included in your string.
 
           .ds sign "           Yours in a white wine sauce,
 
      Strings are not limited to a single line of text.  A string can
      span several lines by escaping the newlines with a backslash.  The
      resulting string is stored _without_ the newlines.
 
           .ds foo lots and lots \
           of text are on these \
           next several lines
 
      It is not possible to have real newlines in a string.  To put a
      single double quote character into a string, use two consecutive
      double quote characters.
 
      The 'ds1' request turns off compatibility mode while interpreting a
      string.  To be more precise, a "compatibility save" input token is
      inserted at the beginning of the string, and a "compatibility
      restore" input token at the end.
 
           .nr xxx 12345
           .ds aa The value of xxx is \\n[xxx].
           .ds1 bb The value of xxx ix \\n[xxx].
           .
           .cp 1
           .
           \*(aa
               => warning: number register `[' not defined
               => The value of xxx is 0xxx].
           \*(bb
               => The value of xxx ix 12345.
 
      Strings, macros, and diversions (and boxes) share the same name
      space.  Internally, even the same mechanism is used to store them.
      This has some interesting consequences.  For example, it is
      possible to call a macro with string syntax and vice versa.
 
           .de xxx
           a funny test.
           ..
           This is \*[xxx]
               => This is a funny test.
 
           .ds yyy a funny test
           This is
           .yyy
               => This is a funny test.
 
      In particular, interpolating a string does not hide existing macro
      arguments.  Thus in a macro, a more efficient way of doing
 
           .xx \\$@
 
      is
 
           \\*[xx]\\
 
      Note that the latter calling syntax doesn't change the value of
      '\$0', which is then inherited from the calling macro.
 
      Diversions and boxes can be also called with string syntax.
 
      Another consequence is that you can copy one-line diversions or
      boxes to a string.
 
           .di xxx
           a \fItest\fR
           .br
           .di
           .ds yyy This is \*[xxx]\c
           \*[yyy].
               => This is a test.
 
      As the previous example shows, it is possible to store formatted
      output in strings.  The '\c' escape prevents the insertion of an
      additional blank line in the output.
 
      Copying diversions longer than a single output line produces
      unexpected results.
 
           .di xxx
           a funny
           .br
           test
           .br
           .di
           .ds yyy This is \*[xxx]\c
           \*[yyy].
               => test This is a funny.
 
      Usually, it is not predictable whether a diversion contains one or
      more output lines, so this mechanism should be avoided.  With UNIX
      'troff', this was the only solution to strip off a final newline
      from a diversion.  Another disadvantage is that the spaces in the
      copied string are already formatted, making them unstretchable.
      This can cause ugly results.
 
      A clean solution to this problem is available in GNU 'troff', using
      the requests 'chop' to remove the final newline of a diversion, and
      'unformat' to make the horizontal spaces stretchable again.
 
           .box xxx
           a funny
           .br
           test
           .br
           .box
           .chop xxx
           .unformat xxx
           This is \*[xxx].
               => This is a funny test.
 
      SeeGtroff Internals, for more information.
 
  -- Request: .as name [string]
  -- Request: .as1 name [string]
      The 'as' request is similar to 'ds' but appends STRING to the
      string stored as NAME instead of redefining it.  If NAME doesn't
      exist yet, it is created.
 
           .as sign " with shallots, onions and garlic,
 
      The 'as1' request is similar to 'as', but compatibility mode is
      switched off while the appended string is interpreted.  To be more
      precise, a "compatibility save" input token is inserted at the
      beginning of the appended string, and a "compatibility restore"
      input token at the end.
 
    Rudimentary string manipulation routines are given with the next two
 requests.
 
  -- Request: .substring str n1 [n2]
      Replace the string named STR with the substring defined by the
      indices N1 and N2.  The first character in the string has index 0.
      If N2 is omitted, it is implicitly set to the largest valid value
      (the string length minus one).  If the index value N1 or N2 is
      negative, it is counted from the end of the string, going
      backwards: The last character has index -1, the character before
      the last character has index -2, etc.
 
           .ds xxx abcdefgh
           .substring xxx 1 -4
           \*[xxx]
               => bcde
           .substring xxx 2
           \*[xxx]
               => de
 
  -- Request: .length reg str
      Compute the number of characters of STR and return it in the number
      register REG.  If REG doesn't exist, it is created.  'str' is read
      in copy mode.
 
           .ds xxx abcd\h'3i'efgh
           .length yyy \*[xxx]
           \n[yyy]
               => 14
 
  -- Request: .rn xx yy
      Rename the request, macro, diversion, or string XX to YY.
 
  -- Request: .rm xx
      Remove the request, macro, diversion, or string XX.  'gtroff'
      treats subsequent invocations as if the object had never been
      defined.
 
  -- Request: .als new old
      Create an alias named NEW for the request, string, macro, or
      diversion object named OLD.  The new name and the old name are
      exactly equivalent (it is similar to a hard rather than a soft
      link).  If OLD is undefined, 'gtroff' generates a warning of type
      'mac' and ignores the request.
 
      To understand how the 'als' request works it is probably best to
      think of two different pools: one pool for objects (macros,
      strings, etc.), and another one for names.  As soon as an object is
      defined, 'gtroff' 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
               => input stack limit exceeded
 
      The definition of macro 'bar' replaces the old object this name is
      linked to.  However, the alias to 'foo' is still active!  In other
      words, 'foo' is still linked to the same object as 'bar', and the
      result of calling 'bar' is an infinite, recursive loop that finally
      leads to an error.
 
      To undo an alias, simply call 'rm' on the aliased name.  The object
      itself is not destroyed until there are no more aliases.
 
  -- Request: .chop xx
      Remove (chop) the last character from the macro, string, or
      diversion named XX.  This is useful for removing the newline from
      the end of diversions that are to be interpolated as strings.  This
      command can be used repeatedly; see SeeGtroff Internals, for
      details on nodes inserted additionally by 'gtroff'.
 
    SeeIdentifiers, and SeeComments.