4

Is it possible to perform arithmetic using groff?
Say I want to calculate what page is the current one, and I currently am on page 2. I can get the next page's number by using:

.PP
Next page is number \n[.pn]

Which will compile as Next page is number 3.

How can I perform arithmetic to render instead:

.PP
Current page is ((\n[.pn]-1))

into Current page is 2 ?

0
3

The current page number is \n% .

To interpolate the result of an arithmetic expression, I think you'll need to put it in a number register first.

Here's a macro (not exhaustively tested) that takes an expression as its argument, assigns the result to a (presumably unused) register named __, then interpolates the contents of the register.

Current page is \n%.
.br
.\" EI - eval and interpolate
.\" $1 is an expression to evaluate
.\" $2 (optional) is a string to append to the interpolated expression,
.\"    without any intervening whitespace
.de EI
.nr __ \\$1
\&\\n(__\\$2
..
.nr x 4
4 times 3 minus 5 is
'EI (\nx*3-5)
\&.
.br
Here there's no space before the period:
'EI (\nx*3-5) .
.br

After running through nroff:

Current page is 1.
4 times 3 minus 5 is 7 .
Here there's no space before the period: 7.

This seems like such a common thing to do that there may be a macro like it already in the standard macro packages, but I don't know.

1
  • Yes exactly, I have been looking in the man page and different tutorials on groff, troff, several macro packages, and none seem to provide a simple solution. I'll definitely use your solution in a project now. It also taught me a lot about arguments in groff which isn't very clear for a beginner. Thanks a lot – Soulthym Aug 1 '19 at 20:07
2

Yes, groff can perform arithmetic. This is documented in the full groff manual, which is available online or in GNU Info format (use info groff, or pinfo groff to see the full manual)....as with many GNU programs, the man page is just a quick reference, full docs are in Info format.

From https://www.gnu.org/software/groff/manual/html_node/Expressions.html

gtroff has most arithmetic operators common to other languages:

  • Arithmetic: ‘+’ (addition), ‘-’ (subtraction), ‘/’ (division), ‘*’ (multiplication), ‘%’ (modulo).

gtroff only provides integer arithmetic. The internal type used for computing results is ‘int’, which is usually a 32-bit signed integer.

  • Comparison: ‘<’ (less than), ‘>’ (greater than), ‘<=’ (less than or equal), ‘>=’ (greater than or equal), ‘=’ (equal), ‘==’ (the same as ‘=’).

  • Logical: ‘&’ (logical and), ‘:’ (logical or).

  • Unary operators: ‘-’ (negating, i.e. changing the sign), ‘+’ (just for completeness; does nothing in expressions), ‘!’ (logical not; this works only within if and while requests). See below for the use of unary operators in motion requests.

The logical not operator, as described above, works only within if and while requests. Furthermore, it may appear only at the beginning of an expression, and negates the entire expression.

Attempting to insert the ‘!’ operator within the expression results in a ‘numeric expression expected’ warning. This maintains compatibility with old versions of troff.

Example:

.nr X 1
.nr Y 0
.\" This does not work as expected
.if (\n[X])&(!\n[Y]) .nop X only
.
.\" Use this construct instead
.if (\n[X]=1)&(\n[Y]=0) .nop X only

BTW, info is the standard GNU Info document viewer. pinfo is an alternative viewer that provides a more "browser-like" UI, similar to a text web browser like lynx. I personally can't stand info and use pinfo instead. It's available pre-packaged for most distros and source code is available in the pinfo link above.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.