groff/troff macros: ms, mm, me or mom
This is a brief explanation of how to choose which macro package to use with the Unix typesetting system troff (or groff). I assume you are familiar with Linux or Unix.
The short answer is: use ms, unless you’re writing a novel (then use mom) or a structured document (then use mm—and find a good reference book for it).
What are troff and groff?
Troff is the original Unix typesetting software. Troff is not like a modern word processor, where the pages of your document appear on-screen just as they will appear on paper and you edit them with a mouse. With troff, your document is a plain-text file mixing text with embedded formatting commands. To see what your document looks like, you process the plain-text file with troff to generate a PDF file, then open the PDF and check to see if you got what you wanted.
An example of a troff formatting command is “
.ce”, which centers the next line of text. These simple commands are called “requests.” The other kind of formatting command is called a “macro,” which is essentially a bundle of formatting commands. You could bundle together commands for indenting text, making the font bold and printing sequential numbers, all into a single macro. Then you could use this macro to automatically number and format the headings in your document.
Macros help you separate formatting from text, which can make it easier to change the formatting or the text. If you decide that instead of indenting your headings, you want to center them, you could simply change the “heading” macro instead of manually changing the formatting of each heading in your document. Macros also mean that you can easily copy text from one troff document into another. In a word processor, on the other hand, copied text will carry along formatting from the original document, and unless the two documents have exactly the same styles, you’ll probably need to reformat the copied text from scratch.
One of the greatest Unix programmers, W. Richard Stevens, used troff to typeset all of his books. But even he agreed that troff is not easy to use, saying, “Troff is an industrial strength package that I have spent years of my life learning.” But despite its difficulty, troff can be more efficient to use than a word processor.
- Technical writing can be faster because the entire troff document is written in plain text, including the commands to make tables, diagrams, math equations etc. In a word processor, it might be necessary to manually construct diagrams and math equations using a mouse or to create them in a separate program altogether, which takes more time. This was W. Richard Stevens’ reason for using troff.
- Reformatting a document is faster because it only requires changing a few macros. An author writing a book for publication will need to reformat the book several times, which can take an enormous amount of time in a word processor. This was the reason for Peter Schaffter, who created the macro package mom.
- Having the entire troff document in plain text makes it easy to parameterize in software. For example, it is easy to use troff to create a batch of letters in PDF format for multiple people. Or, if you have written a computer program, you might use troff to enable your program to print, without having to directly generate PDF files or rely on non-standard APIs.
Troff was created by Bell Labs in the early 1970’s and came with AT&T Unix for decades. But AT&T Unix is now almost completely obsolete, so you are not likely to find a copy of troff. Instead you are likely to find groff, which is a clone of troff published by the GNU Project. Just about everything above also applies to groff and from here I will only refer to groff unless the distinction is important.
What are ms, mm, me and mom?
You can, if you want, write a groff document entirely from scratch. This would mean defining your own macros for headings, footnotes, bullet lists, and so on. But there is an easier way. There are standard macro packages, each with dozens of useful macros. Four of them are called ms, mm, me and mom.
Bell Labs made the first macro package, ms, for internal use, writing technical papers and reports. It’s pretty easy to use and doesn’t have many weird surprises. You can mix up groff requests and ms macros, which is helpful if you have a clear vision for how you want your document to look. W. Richard Stevens used a customized version of ms for the books he wrote. But ms is more limited than mm or mom, so you need to use groff requests for even basic formatting such as numbered lists. The online documentation for ms is adequate but not great.
At one time, Unix was the most advanced typesetting system in the world, using the mm macro package. This macro package is a lot more full-featured than ms. For example, it has numbered lists (in arabic numerals, roman numerals or letters) built-in. It also supports cross-references, which are essential for structured documents such as technical books. Unfortunately, mm is a little less intuitive than ms and the documentation on the Internet for mm is abysmal. However, there are excellent books on mm from the glory days of Unix typesetting, which you can buy used for cheap.
A developer at the University of California, Berkeley wrote the me macro package in the 1980s. It is more complete than ms, but me’s creator has not worked on it for decades and the documentation is limited to two short papers written by its creator. I do not recommend using me.
The most modern of the four is mom, created by a novelist. It has advanced typographical features and is about as powerful as mm. It is designed for ease-of-use and has excellent online documentation. For many users, mom is the right choice. However for some uses, it may be practically impossible to use mom, and it lacks a few specific features that mm has.
There is also man, which you do not want to use for creating ordinary documents. It is used by the man command to display man pages.
Invoking groff and troff
If you’re wondering why the names of the macro packages all start with “m,” it’s because the “-m” command line argument for groff is used to choose the macro package, for example “groff -ms letter.ms”. The Bell macro packages are abbreviations for “manuscript” and “memorandum.” It seems that “me” is a joke name (as in, Eric P. Allman wrote it himself), and according to its home page, so is “mom” (meaning, it’s a friendlier macro package).
To invoke groff on the input file example.troff, run “groff example.troff > example.ps” (without a macro package) or “groff -ms example.ms > example.ps” (with the macro package ms). This produces a Postscript file. You may also have pdfroff installed, which produces a PDF file instead.
The only AT&T troff I have is the one from Solaris 11. It is more arcane to use. To invoke troff on the input file example.troff, run “troff example.troff | /usr/lib/lp/postscript/dpost > example.ps” (without a macro package) or “troff -ms example.ms | /usr/lib/lp/postscript/dpost > example.ps” (with the macro package ms). This produces a Postscript file.
A simple example
It can be a little tricky to start with groff, so here are simple examples using bare groff, ms, mm and mom.
The plain groff file prints “Hello, world!” with a one-inch top margin (“
.sp 1i” means “vertical space one inch”) and a one-inch left margin (the default). The rest of the page is blank. I’ve included this example so you can see that using plain groff is a viable option for simple one-page documents. This lets you avoid the frustration that comes along with using the macro packages as a beginner.
The ms file prints “Hello, world!” with one-inch top and left margins (the default). The rest of the page is blank. The “
.LP” macro tells groff that the next line begins a left-flush paragraph. Notice also that groff is case-sensitive. Usually, macros are in uppercase and requests are in lowercase.
The mm file prints a page number in the header. So “Hello, world!” has a 0.963-inch (the default) left margin and a seven lines top margin, putting it slightly lower on the page. (If you are wondering why the default left margin is 0.963 inches in mm, this is 26/27 inches rounded to three decimal places. If you are wondering why 27 is significant, the C/A/T typesetter for which troff was designed had a resolution of 27×16=432 dpi.)
The mom file prints a page number in the footer, rather than the header, and prints “Hello, world!” even lower on the page than mm does. It also uses a larger font than the other three examples. The macros are quite different from ms or mm; I will talk more about this below.
A more realistic example in ms
Let’s say you want a document that has a title, one wide column at the top of the first page and the rest of the document as two columns. It could be a scientific paper or a legal contract, for example. Here I explain just enough about groff to create such a document in ms.
The most confusing part about groff to a beginner is how the paragraph macros (like “
.LP” or “
.PP”) work. Groff has no notion of a paragraph; it just fills lines on the page with text, one after another, until it has a reason to stop. What the paragraph macros in ms do is tell groff to stop filling lines, to reset certain parameters and to move a little down the page. These parameters include whether the text is centered, so putting “
.ce” immediately before “
.LP” means the “
.ce” request is overridden by the “
.LP” macro and therefore has no effect. This is different from a word processor, where it doesn’t matter if you tell the word processor to center text then start a new paragraph or vice-versa.
Next, fonts. As mentioned above, the paragraph macros reset certain groff parameters, and one of those parameters is what the font currently is. In older versions of AT&T troff, this means every paragraph would be set in Times roman unless specifically changed. However, groff added the concept of a font family (typeface) and the request “
.fam” to change the current font family. By putting “
.fam H” at the top of the document, for example, your whole document will be in Helvetica with no need to change the font in every paragraph. Another benefit of “
.fam” is that it lets you use “
B” and “
I” to refer to bold and italic versions of the current typeface. Otherwise, if your document was set in Helvetica, every time you set a word in bold or italic you would need to ask for Helvetica bold (“
HB”) or Helvetica italic (“
HI”) specifically to avoid getting Times roman. By the way, fonts in groff can be changed either through a request or an “escape sequence.” An escape sequence is like a request, but it occurs in the middle of text instead of on its own line. For example, “
\fB” and “
\fR” do the same thing as the requests “
.ft B” and “
.ft R”, respectively.
Like many computer languages, groff has variables. Numeric variables are called “registers.” You set a register with the “
.nr” request and you print a register with the escape sequence “
\n” if the register has a one-letter name. For example, “
.nr k 42” sets the register “
k” to 42, and afterwards “
\nk” is replaced by “
42” in the document. Macro packages use some registers which you can change to alter formatting. For example, in ms the “
HM” register refers to the size of the header margin (i.e., the top margin of the page). As mentioned briefly above, these formatting registers can include suffixes to indicate units of measurement, such as “
i” for “inch” or “
v” for vertical lines. Therefore, in ms, “
.nr HM 1i” sets the header margin (top margin) to one inch. Another useful feature is setting a register to auto-increment, which means that with a single escape sequence you can automatically increase (or decrease) the register by specified amount and print the value of the register. You use the same request “
.nr” to set the initial value and the step count, the amount by which the register will increase or decrease. Then you use the escape sequence “
\n+” to increment and print the register. For example, “
.nr k 0 1” sets the register “
k” to zero and the step count to 1. Then “
\n+k\n+k\n+k” would be replaced by “
123” in the document.
String variables are called “strings” and the request “
.ds” is used to define a string. As you might expect, one common use for strings is for unchanging blobs of text to be inserted several times in a document, such as the name of the addressee in a letter. Strings can also include escape sequences for registers (including auto-increment registers) and formatting. You might need to use extra backslashes when putting an escape sequence into a string (consult a reference for more information). To insert a string you use the escape sequence “
\*” if the string has a one character name. For example, “
\*N” is replaced by “
answer” if “
.ds N answer” appears earlier in the document.
|I’m defining a string named “|
|I want to reduce the margins to 0.75 inches on each side. So I’ve set the ms registers for header margin, footer margin and page offset (i.e., left margin) to 0.75 inches. There is no right-margin register in ms. Instead, ms has a line-length register, the amount of text on each line (i.e., the page width minus the left margin minus the right margin). I’ve set the line length to seven inches.|
|The document will be set in Helvetica. I’ve set the point-size and vertical spacing (leading) ms registers to 12 and 14. The request “|
|I’ve centered and set in bold the next line of text (not counting request and macro lines), which is the title, “BABY SHARK.” I’m setting the register “|
Next we print the intro paragraph.
|Now I set the interword spacing and point size to 10 and the vertical spacing to 12.|
|Left flush paragraph, print the text as one paragraph. I don’t need to change the font to not-bold because “|
Next we print the numbered paragraphs.
|I don’t use “|
|Same thing. Repeat several times.|
Next we print the end, where the signatures would go in a contract. This shows how tabs work in groff.
|The request “|
Some complications with ms
In “A simple example,” I moved my text down the page in plain groff by using the “
.sp” request. I could also have inserted blank lines. But this would not have worked with the ms macro package. The reason is that at the top of every page, ms enables “no-space mode,” which gobbles up space from blank lines or “
.sp” requests, until a new paragraph starts. To turn off no-space mode, you use the requests “
.fl” and “
.rs” (if you’re working with the first page) or “
.rs” (if you’re working on any other page). Consult a reference for more information.
You might think from my examples that ms does not number its pages. In fact it does number its pages. But because ms was created for writing technical papers and reports at Bell Labs, it assumes that the first page is a cover page which should not have a number. In this section’s example, I created a one-page document so ms’s default behavior is what I wanted. If you want a page number on the first page, you will need to redefine the page title “
.PT” macro at the top of your input document. Again, consult a reference for more information.
This is more of an obscure issue, but groff ms is not fully initialized until one of the following macros is called:
.XS. If you are finding that a macro is mysteriously not defined, this could be the problem. Modern troff ms does not have the same issue.
The same example in mm
It’s a little more cumbersome to do the same example (“Baby Shark,” formatted as a one-page contract) using mm instead of ms. The biggest difference is that mm does not allow reducing the margins after the mm macros have been read. Therefore, we set the left margin, page length and line length registers from the command line: “
groff -mm -rO0.75 -rP9.5i -rW7i babyshark.mm > babyshark.ps”.
The changes in the input file are minor. First the title:
|There is no easy-to-use header-margin macro in mm. To reduce the top margin, I redefine the “|
Next the intro paragraph.
|Unlike the ms macros, “|
Next we print the numbered paragraphs.
|Unlike ms, mm does not insert any space when changing the number of columns. So instead of taking away unwanted space, I add space.|
And the end.
The same example in mom
As for mom, this file is actually impossible in any practical way. To set the number of columns in mom, it is necessary to do so before the “
.START” macro, however that precludes printing the title and introductory paragraph in single-column mode. You could avoid using the “
.START” macro (i.e., not use the mom document processing macros and only the typesetting macros) but then you would not have a way to automatically put the text into columns. Overall, mom is a terrific, well-documented package but not the right choice for every situation.