Path: utzoo!attcan!uunet!mcvax!ukc!warwick!anduk!lee From: lee@anduk.co.uk (Liam R. Quin) Newsgroups: comp.text Subject: Troff Macro Programming A: Part 1 [repost] Keywords: troff nroff SoftQuad Unixsys macro programming course Message-ID: <18@nx32s.anduk.co.uk> Date: 15 May 89 18:50:56 GMT Distribution: comp Organization: Unixsys (UK) Ltd, Warrington, England Lines: 270 This is the first in the promised series. There is also an introduction, including both a PostScript and a text file (which I re-posted yesterday). [Anduk's gateway fell over at the weekend sorry if this gets out twice] ============================================ Lightening Introduction to Troff Programming Copyright (c) 1989 Liam R. Quin I am including this article for those people who find the troff documentation particularly difficult. In order to understand the rest of the material, you'll have to be prepared to dive into your documentation, so this is simply to help you get started. It is very terse..... The examples all work, if you have the same version of troff that I do. For what it's worth, I'm using ``SoftQuad Publishing Software'' Release 2.9. I have marked with a side-bar where there are most likely to be differences | | old troff: | Like this. These are mostly to do with long variable names and error handling. If you have an older release of sqtroff, see NOTE 1 near the end of this article. If you are likely to give courses in the future, see NOTE 2 at the en. Lee ============================== 0. Lightening Overview Troff has number registers, strings macros and diversions. 0.0 Number registers hold arbitrary *integer* expressions. You can set them with .nr register-name expression where register-name is a string of letters, numbers or punctuation expression is a numeric expression. Old versions of troff limit all names to 1 or 2 names. You use them with \nX 1-character name \n(XX 2-character name \n[xxx] 1, 2, or longer- character name 0.1 Strings hold a single word or phrase. In other words, you can't put a newline into a string, because it's the string terminator. You set them with .ds string-name "anything you like here You use them with \*[xxx] (as for number registers. but with a * instead of an n). 0.2 macros hold multiple lines of unformatted (input) text. You make a macro with .de macro-name text (which can include pretty much anything) .. where the dots have to be at the start of the line (but if I put them there, old news and mail software will fall over!). You use the macro with .macro-name in exactly the same way that you would use a normal request (.ps for example). 0.3 diversions hold formatted (output) text. You make them with .di diversion-name text .di and use them with .diversion-name Typically when you use a diversion, you need to do .in 0 .nf .diversion-name You will see why later. Do not worry about the difference between macros and diversions at this stage [but I am not going to explain it in much detail on the net. See TF:TR 5-14ff. if you have it, or look at your troff documentation.] 1.0 Interpolation Troff reads its input (conceptually) a character at a time. Strings and registers are ``interpolated'' as soon as they are seen in the input. | Old versions of troff: In other words, if you do | .ds Name "Simon | .ds Na "Simon Hello, \*[Name], how are you? | Hello, \*(Na, how are you? what troff actually sees is Hello, Simon, how are you? Similarly, if you do | .nr Age 12+(300/12) | .nr A 12+(300/12) Simon is \n[Age] years old. | Simon is \nA years old. troff sees Simon is 37 years old. This means that you can use strings and number registers anywhere you like. It also means that you sometimes have to take special pains to avoid troff from `interpolating' things. For example, if you want to print a backslash (\), you can't simply include it in your text, because troff will look for a following * or n! There are other things that you can put after a \, however, and one of them is `e'. \e tells troff to print the current ``escape'' character; this is normally the backslash. The troff manual has a compete list of these things; this introduction is to give you the general flavour of how things work. [omitted: activity break involving creating a file containing strings, registers and macros. You can go have a play if you want!! try making a letter with the recipient's name in strings, perhaps, using a macro for the address.] 1.3 Common problems: * if you forget the .. or the .di at the end of a macro or diversion, all of the rest of the input will go into it, and of course won't be printed. Troff will give you an error message: sqtroff:filename:223:Diversion (diversion-name) not closed or sqtroff:filename:255:de:Macro definition not closed including the filename and line number, sometimes or simply "(wrapup)" if the error isn't detected until the end of all the input. | old troff: | there is no error message. | The rest of your document | will simply vanish. * If you get the name of a string or register wrong, nothing will happen. (sqtroff will give a warning if you have the warning level set appropriately). 2.0 [awfully terse summary] Remove a register with .rr .rr regname [name2 ...] remove a macro or string with .rm name [name....] Strings and macros share the same name-space. In other words, if you do .ds Name "Marion | .ds Na Marion .de Name | .de Na Here is My Name | Here is My Name .. | .. the .de first removes the string before defining a macro with the same name. You do not get a warning. Worse, if you do .de de you can no longer use the built-in `.de'! (But sqtroff will give a warning). In order to define your own version of `de', you have to do .rn de old-de \" rename the built-in request .old-de de whatever you want .. Also, macro-aliasing does not notice that you | Old troff doesn't have have redefined the request: | aliasing, so this does .alias nr set-register | not affect you, except .de nr | maybe to make you . tm nr obsolete | jealous! :-) .. | then .set-register will continue to behave as .nr used to. ============================== Good. Summary: number registers expressions [see your manual, sorry] strings macros diversions Actions: creating removing renaming aliasing Other Key Words: name-space interpolation ================== NOTE 1 on sqtroff: Some older versions used : instead of ., but only for lines involving long names. I suggest that you create a file called `tmac.acc', and put it in your macro directory (probably /usr/lib/tmac). It contains: :acc . ;ac2 ' .ev 1 :acc . ;ac2 ' .ev .ev 2 :acc . ;ac2 ' .ev with the leading spaces/tabs removed, and NO BLANK LINES. Then do sqtroff -macc other-arguments-to-troff If you're still on 2.6 or older, you may have to put an explicit .so /usr/lib/tmac/tmac.acc (or wherever you put it) into each of your files. If you can't put things in /usr/lib/tr\mac, you'll have to do that anyway). The examples will then work for you. ==================== NOTE 2 on copyright: Please ask me before charging people to learn troff from you with any of this stuff. I will say almost certainly say yes, but I'd like to know if it's being used! In any case, you should acknowledge that you got the material from me. Lee End Of Part A Part B @ will start at ``Tricks With Names'' @ will show how to build stacks, arrays and so on. @ will have an example set of macros to do bullet-lists (like this one), which 1. nest (like this) 2. can use numbers (like this) 3. can use the special characters from part C, that are featured in the PostScript example. @ will be posted in a day or two. -- Lee Russell Quin, Unixsys UK Ltd, The Genesis Centre, Birchwood, Warrington, ENGLAND, WA3 7BH; Tel. +44 925 828181, Fax +44 925 827834 lee%anduk.uucp@ai.toronto.edu; {utzoo,uunet}!utai!anduk!lee UK: uu.warwick.ac.uk!anduk.co.uk!lee