aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/troff
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2004-05-15 23:24:00 +0000
committerrsc <devnull@localhost>2004-05-15 23:24:00 +0000
commit5cedca1b69d020c32466f70843a11767773d7e3b (patch)
treea15a3d84e92aa262543b0010763a5e6920c9ba24 /src/cmd/troff
parent76e6aca867e3e48ea04fbcf7284c45369a69829e (diff)
downloadplan9port-5cedca1b69d020c32466f70843a11767773d7e3b.tar.gz
plan9port-5cedca1b69d020c32466f70843a11767773d7e3b.tar.bz2
plan9port-5cedca1b69d020c32466f70843a11767773d7e3b.zip
Let's try this. It's BUGGERED.
Diffstat (limited to 'src/cmd/troff')
-rw-r--r--src/cmd/troff/FIXES821
-rw-r--r--src/cmd/troff/README31
-rw-r--r--src/cmd/troff/cvt45
-rw-r--r--src/cmd/troff/dwbinit.c313
-rw-r--r--src/cmd/troff/dwbinit.h19
-rw-r--r--src/cmd/troff/ext.h184
-rw-r--r--src/cmd/troff/find1
-rw-r--r--src/cmd/troff/fns.h384
-rw-r--r--src/cmd/troff/hytab.c126
-rw-r--r--src/cmd/troff/mbwc.c165
-rw-r--r--src/cmd/troff/mk.log136
-rw-r--r--src/cmd/troff/mkfile58
-rw-r--r--src/cmd/troff/n1.c1136
-rw-r--r--src/cmd/troff/n10.c549
-rw-r--r--src/cmd/troff/n2.c325
-rw-r--r--src/cmd/troff/n3.c954
-rw-r--r--src/cmd/troff/n4.c828
-rw-r--r--src/cmd/troff/n5.c1149
-rw-r--r--src/cmd/troff/n6.c362
-rw-r--r--src/cmd/troff/n7.c834
-rw-r--r--src/cmd/troff/n8.c540
-rw-r--r--src/cmd/troff/n9.c488
-rw-r--r--src/cmd/troff/ni.c390
-rw-r--r--src/cmd/troff/suftab.c612
-rw-r--r--src/cmd/troff/t10.c512
-rw-r--r--src/cmd/troff/t11.c255
-rw-r--r--src/cmd/troff/t6.c881
-rw-r--r--src/cmd/troff/tdef.h670
-rw-r--r--src/cmd/troff/unansi49
29 files changed, 12817 insertions, 0 deletions
diff --git a/src/cmd/troff/FIXES b/src/cmd/troff/FIXES
new file mode 100644
index 00000000..5765832c
--- /dev/null
+++ b/src/cmd/troff/FIXES
@@ -0,0 +1,821 @@
+March 11, 1994
+
+ If we are just plain old nroff (and not doing UNICODE) we should
+ only Lookup characters, not Install when we don't know them.
+ If we are troff, we Install them anyway
+
+March 8, 1994
+
+ Nroff had problems with parsing quoted white space as options or
+ character code in some terminals tables. Changed by having scanf
+ include white space when necessary as suggested by Rich.
+
+March 1, 1994
+
+ Made sanity check for terminal type depending on the trace level;
+ trace level set with -tn flag at start up
+
+22 Feb, 1994
+
+ More pointer shuffling fixes.
+
+18 Feb, 1994
+
+ More disabling of multibyte stuff. Fixed bug in n5.c: casetm didn'
+ know about the new format in the fontables.
+
+Feb 17, 1994
+
+ Removed extra include <setlocale> from n1.c
+
+ Fixed dubious pointer shuffling in n7.c, t10.c & n8.c. Thanks Rich!
+
+Feb 10, 1994
+
+ Disabled the multybyte stuff; only plan 9 will get it.
+
+Jan 24, 1994
+
+ Fixed nasty bug discovered by td, which caused core dumps on
+ \D'l-0.002775i 0i' and apparently all numbers closer to 0
+ than -.002775. Fixed in storeline() and storeword() (n7.c).
+
+Dec 16, 1993
+
+ nroff & troff -N were looking for the TYPESETTER variable, causing
+
+ troff: cannot open /sys/lib/troff/term/tab.202; line 1, file stdin
+
+ fixed my moving getenv("TYPESETTER") to t10.c in t_ptinit(void).
+
+Dec 3, 1993:
+
+ The sequence \s+2\H'+10' came sometimes out in the wrong order
+ (x H before s), so there wasn't a difference bewteen \s+2\H'+10'
+ and \H'+10'\s+2. Now the fonts bits of the CHARHT are used to
+ register the current pontsize, so we can issue a s10 in t10.c
+ if needed. A bit sneaky.
+
+ Try to prevent double slashes in path names. Especially under
+ plan9 things started to look ugly.
+
+ Exception word list now grows dynamic.
+
+Nov 30, 1993:
+
+ Allow multiple calls to .pi, requested by Rob.
+ .pi cat
+ .pi dogs
+ is now equivalent with
+ .pi cat | dogs
+
+
+ .ab now takes also optional error code:
+ .ab [n] [string]
+ If n and string, n is exit code, string is message
+ If n, n is exit code, ``User Abort, exit code n" is message
+ If !n and string, standard exit code, string is message
+ If !n and ! string, standard exit code, "User Abort" is message
+
+Nov 24, 1993:
+
+ Reordered code to keep the UNASNI scripts happy.
+
+ Nroff dumped core reading terminal tables: apparenty under plan 9,
+ scanf includes the '\n'; added test for '\0' in parse in n10.c.
+
+ Relative tab settings (.ta +1C +2C) didn't work; anding the
+ previous value with TABMASK fixes this (caseta).
+
+Nov 23, 1993:
+
+ Included code, originally done by bwk for plan 9, to handle
+ multi-byte characters.
+
+Nov 3, 1993:
+
+ ``pair internal'' two char names by shifting 16 bits. Will allow
+ the use of 16 bit characters sets (Unicode in plan9 etc.) for
+ macro's etc.
+
+Oct 20, 1993:
+
+ Word & line buffers are now dynamic: No more word or line overflow
+ unless when we run out of memory.
+
+Oct 11, 1993:
+
+ lost diversion warning pops up regularly with man macro's. Due
+ to a possible macro coding problem. Triggered by something like
+ troff -man:
+ .TP
+ .TP
+ foo
+ .ex
+ Minimal code:
+ .di aa
+ throw away this diversion (aa) while being defined.
+ .rm aa
+ .br
+ .di
+
+ Fixed by disallowing .rm to throw away current diversion. The
+ rn request will complain with:
+
+ cannot remove diversion aa during definition; etc.
+
+Sep 29, 1993:
+
+ Some long standing fixes which never went back in the source.
+ Thanks to Janet & Rich.
+
+Sep 28, 1993:
+
+ Changed getach() (n1.c), so it does't consider truncated
+ special characters as (8-bit) ascii. STX ETX ENQ ACK and BELL
+ are still allowed for the ultimate backwards compatibility.
+
+ Some code changes, so real ANSI compilers like the SGI version
+ (acc from Sun is a poor excuse for an ANSI compiler) don't
+ barf. Some compromises (static Tchar wbuf in n9.c) allowed so
+ the unansified stuff for non-ansi compilers (cc on Sun's) will
+ work as well.
+
+Sep 9, 1993:
+
+ Be nice to Gerard. Now also word spaces in .tl and after
+ tabs/fleids etc.
+
+Aug 12, 1993:
+
+ Tabs setting can now be humongous. We also allow 99 tabs to
+ accomodate tbl. As a side effect, NTM buffers are now 1K
+
+Aug 11, 1993:
+
+ .R register, now contains maximum number of addessable
+ registers minus the number actually used.
+
+ Small esthetic changes in error messages; removed a statement
+ which wasn't reached anyway.
+
+Aug 10, 1993:
+
+ Some more speed hacks: be smarter doing the linear table
+ lookups in alloc() and finds().
+
+ The real name of the det diversion size macro is now gd.
+
+Aug 9, 1993:
+
+ A much faster way to find the end of a string/macro, by
+ remembering that when defined.
+
+Aug 6, 1993:
+
+ Slightly more eficient way of skipping to the end of a
+ string/macro
+
+Aug 5, 1993:
+
+ Prevent character sign extension for 8-bit charnames diversions
+ etc. by unpair
+
+Aug 4, 1993:
+
+ Growing the dynamical macro/strings name space and registers
+ space (See the experiment of 21 July) now with bigger
+ increments. Casts added to satisfy non-ANSI compilers.
+
+Aug 3, 1993:
+
+ Should check return value in alloc (n3.c), to prevent core dump
+ when memory gets tight.
+
+July 28, 1993:
+
+ New request: .sg <div> sets the dn and dl registers to the size
+ of the diversion named in the argument. Doesn't do anything
+ when the named diversion doesn't exist. The name sg is
+ temporary until we find a better one.
+
+July 21, 1993:
+
+ Experiment: Macro space & registers name allocated
+ dynamically. Note that current reallocation occurs in
+ increments of 1, to force the code to be executed a lot; a kind
+ of stress testing. Also, eight bit characters allowed in
+ macro/string names.
+
+July 21, 1993:
+
+ Turn on the escape mode if the end macro is called.
+
+July 20, 1993:
+
+ Tracing mode now default off
+
+ Don't print s stackdump either when a file specfied on the
+ command line argument cannot be opened
+
+July 15, 1993:
+
+ Don't print useless line & current file informations when a
+ file specfied on the command line argument cannot be opened.
+
+ Sun ansi compiler doesn't default adhere to standards. Undid
+ the kludge in tdef.h
+
+July 14, 1993:
+
+ Coding error made the tab type R not function properly
+
+July 12, 1993:
+
+ Fixed a typo in the version stuff, noticed by Rich
+
+July 9, 1993:
+
+ Added the dwb home configuration stuff, thanks RIch. Also,
+ NCHARS is big enough. Added a fflush to casetm, so .fm <file>
+ will be up to date.
+
+June 25, 1993 (Rich):
+
+ -t option
+
+ reinstated for the sake of compatibility. Some old
+ shells scripts and man(1) from SunOs want this, sigh
+
+ Compiler and system dependencies
+
+ Some systems pull in sys/types.h via #include <time.h> and then
+ the compiler complains about two ushort typedefs. Therefore,
+ ushort is now Ushort (and uchar Uchar).
+
+ The SVID specifies a strdup, POSIX doesn't, anyway, troff
+ provides its own version, slightly different then the standard
+ one. A To prevent name clashes with that definion, renamed to
+ strdupl.
+
+June 24, 1993 (Rich):
+
+ -V option added for DWB3.4 (rich)
+
+May 18, 1993:
+
+ Trivial fix (.cf) request for troff -a
+
+ issuing
+
+ .cf /dev/null
+
+ with troff -a gives some spurious output:
+
+ H720
+ H720
+ s10
+ f1
+
+ fixed by checking for ascii mode it ptesc(), ptps() and
+ ptfont() in t10.c
+
+
+ Enhancement
+
+ Added a .tm request to roff. Works just like .tm, but now
+ it will do it to file. The name is coined by Carmela. Great
+ for creating indeces & toc's (we hope).
+
+May 18 1993:
+
+ Compatibilty change
+
+ Somebody complained that his favorite macro didn't work:
+ it had a BELL (^G) in the name. This was a non-documented
+ feature of earlier versions of troff (although the
+ documentation actually doesn't say that you can. (They can
+ only be used for delimiters or with the tr request), so it
+ isn't that important).
+
+ But the sake of eternal backward compatibilaty I allowed
+ some control characters like, STX, ACK, etc. also be part
+ of a macro/string name.
+
+ While at it, I made it also possible to have eight bit
+ characters be part of the name. It might be that this screws
+ up the way users think about these things. For UNICODE
+ versions, they probably want to do that as well, and that
+ won't work as easy, (because these characters are 16-bits
+ wide), so it is dubious whether we actually want this.
+
+ BTW. Now
+
+ .de \(ts\ts
+ .tm terminal sigma macro
+ ..
+ .\(ts\(ts
+
+ also works, as long the internal cookie for ts isn't more then
+ eight bits.
+
+May 12, 1993:
+
+ Syntax change
+
+ Some requests accept tabs as a separator, some don't and
+ this can be a nuisance. Now a tab is also recognized as
+ an argument separator for requests, this makes
+
+ .so /dev/null
+
+ works.
+
+ To be more precise, any motion character is allowed, so
+
+ .so\h'5i'/dev/null
+
+ will work as well, if one really wants that.
+
+ It will be a problem for users who really relied on this as in
+
+ .ds x string
+
+ and expect the tab to become part of the string a, but I haven't
+ seen any use of that (obscure trick).
+
+May 6, 1993:
+
+ Eileen count fixed
+
+ Troff sometimes went in a loop, and exited with: ``job
+ looping; check abuse of macros'' (also known as the Eileen's
+ loop). It can be forced with the next trivial programme:
+
+ .de ff
+ .di xx
+ ..
+ .wh -1 ff
+ .bp
+
+ Basically what happens is that a page transition now will
+ happen in a diversion, which doesn't make sense. Wat really
+ happens is that eject() (in n7.c) doesn't eject the frame
+ because we are in a diversion. This cause the loop in n1.c
+ (because now always stack->pname <= ejl). Adding check on
+ whether we are not in a diversion takes care of the problem.
+
+March 30, 1993:
+
+ Need request, .ne
+
+ When there is a begin of page trap set, and the first thing
+ in the file is a .ne request, the trap gets fired, but,
+ the x font R etc. cookies doen't come out, because the
+ troff thinks that the first page pseudo transition already
+ took place. Fixed by forcing the start of the first page
+ in the casene request with the same code as in casetl (which
+ caused a similar problem quite some time ago).
+
+ Change to .cf request ``Here document''
+
+ If the argument of .cf starts with a <<, the rest of it is taken
+ as an EOF token. It will reat the rest of the input until it hits
+ the EOF token and copies it to the output. This is similar as
+ the shell's ``here document'' mechanisme and put in place to
+ improve the kludgy way picasso, picpack etc. now include
+ postscript.
+
+ Using troff -TLatin1 (DWB version) and \N'...' caused core dump
+
+ In t11, in chadd, it should test on NCHARS - ALPHABET to see
+ whether we run out of table space (and we probably should beaf
+ up NCHARS for the DWB version).
+
+March 16, 1993:
+
+ Diversion rename bug fix
+
+ It is possible to get troff in an infinite loop by renaming a
+ diversion in progress, and calling it later with the
+ new name (as in .di xx, .rn xx yy, .yy). The effect depends on
+ whether troff already put stuff in the diversion or not.
+
+ Fix by having .rn also rename the current diversion (if
+ there is any and when appropriate). If the diversion calls
+ itself by the new name and given the fix made on 11 nov
+ 1992, this will now result in an error. (BTW, the fix from
+ 11 nov is improved: diversions nest, so we have to account
+ for that).
+
+December 18, 1992:
+ Some people have complete novels as comments, so we need
+ to skip comments while checking the legality of font files.
+ thaks Rixh
+
+December 16, 1992
+
+ Some people rely on the order that -r arguments are given,
+ so that troff -rC1 -rC3 ends up setting register C to 3.
+ Because cpushback() pushes things in a LIFO order back, we
+ have to do the same to get -r args in a FIFO order.
+
+Nov 17, 1992:
+
+ Giving a -rL8 option cuased the string .nr L 8 to be printed
+ on the output, using the wonderful 3b2. Some garbage was
+ left in buf[100] in main(). Fixed by setting buf[0] explicitly
+ to 0 (because some C-compilers complain about ``no automatic
+ aggregate initialization'').
+
+Nov 11, 1992:
+
+ Diversion bug fix
+
+ If a diversion was being read and the input is faulty so
+ the diversion was reading in itself, it caused troff to
+ loop undefinitely. This was easily fixed by a test in
+ control(a,b) in n1.c.
+
+ Something similar things might happen with macros causing
+ the ``eileenct problem'', but I didn't look for that. We
+ have to wait until it happens.
+
+Oct 26, 1992:
+
+ Numeric arguments:
+
+ Illegal argments are treated as missing arguments. This
+ changed the semantics of .ll, .ls, .in, .lg, .ul, .cu .lt
+ (which acted as if the argument was 0) and .ps which was
+ simply ignored with an illegal argument.
+
+ Tidied up number parsing in atoi1(). This prevents arguments
+ like .x or 1.2.3.4 being interpret as a legal number (nonumb = 0)
+
+ Numeric arguments error reporting:
+
+ Controlled by .pt, illegal numbers are now reported (default
+ trace mode is 1). This is also true for the escapes:
+ \h'..', \v'..' \H'..', \S'..', \N'..', \D'..', \l'.., \L'..
+ and \x'..'.
+
+ \D'c' is the only drawing request which doesn't take a pair
+ of numbers as arguments, so a special case is put here in
+ setdraw() (This code actually could use an overhaul to get
+ better parsing. As long as the \D'..' cookies are machine
+ generated it is low on the priority list).
+
+ Don't generate an error if the illegal argument to a request
+ is a \}. It is too painful to do right (although it can be
+ done, but it would clutter getch() and getcho() even more).
+
+ Input line numbers (.c register) bug fixes:
+
+ In not taken branches of .if or .ie, the input line #
+ (numtab[CD].val) should be raised when necessary (in eatblk()).
+
+ For concealed newlines, we still should count the line for input.
+
+ Setfield (n9.c) sometimes pushes the rest of the line back to
+ the input (including \n), without adjusting numtab[CD].val
+
+ Because .c (and so numtab[CD].val) is the number of lines read
+ and the error might actually happen in the current line
+ (before seeing the '\n), we need to apply correction in
+ errprint when nlflg set. (This correction needs to be undone
+ when inside a macro because the nlflg is set by reading the
+ args to the macro).
+
+ Line number setting (.lf) request bug fixes:
+
+ I interpret that the .c register will contain the number of
+ read lines, not including the current one.
+
+ Also, don't change the input line number when the first
+ argument of .lf is not a number.
+
+ As a net effect, the next input
+
+ .EQ
+ .EN
+ .ab
+
+ will generate the same output whether eqn has been used or not.
+
+ If request bug fix:
+
+ A ``.if page .tm foo'' caused the next line being ignored;
+ This bcause when the 2nd delimiter of a string couldn't be
+ found in cmpstr, the next line was always eaten. Solution:
+ in caseif1, if the condition is false, we should check
+ nlflg before eating a block. (Note: We might have eaten
+ \{\ as well. We could disallow the \{\ in a string to be
+ compared to prevent that but that might break other things).
+
+ Enhancement to .pt:
+
+ The .pt now pops the previous values when no argument is
+ specified. Turned out to be handy when chasing for problems.
+ Just ``bracked'' the code with .pt 7 and .pt and you get
+ a trace of only that block. The meaning of the arguments
+ is now:
+ 01 trace numeric arguments (default on)
+ 02 trace requests
+ 04 trace macros
+
+ Abort request (.ab) beautification:
+
+ Don't print the extra carriage return when .ab is called
+ without an argument.
+
+Oct 12, 1992:
+
+ (Comments & spelling errors from this day on by jaap)
+
+ replaced 32767 by INT_MAX in several places to allow for very
+ long pages (on 32-but machines).
+
+ The ``.fp 1 R \"COMMENT'' complains about ``./troff: Can't
+ open font file /usr/lib/font/devpost/h'' on some systems. It
+ sees the tab as part of the optional font file. Apparently it
+ is system dependent whether isgraph() includes the tab
+ character. Fixed by using getach() in getname() in n1.c
+ instead.
+
+Aug 28, 1992:
+ removed call to popi from rdtty(); it was eating up the
+ rest of the macro if it was used from within one. (thanks, jaap)
+
+
+Jul 21, 1992:
+ added extra test in nextfile() to pop current input file
+ only if not in .nx command. thanks to jaap.
+
+ added test in getword() to avoid hyphenating after \z character,
+ which prevents any hyphenation inside \X'...'. thanks to jaap.
+
+ added, then removed, code in getword() to prevent hyphenating
+ anything shorter than 6 characters. looks like it changed a
+ lot more than i thought.
+
+Jul 12, 1992:
+ added .pt request to trace macros and requests (from jaap).
+ .pt N Print trace of macros (N=1), requests (N=2) or both (N=3)
+
+Jun 5, 1992:
+ added tests to t.twrest and t.twinit to avoid 0 deref in
+ n2 and n10, for nroff -t xxxxx. thanks to Rich Drechsler.
+
+May 22, 1992:
+ added extern decls to e.g., void Tchar (*hmot)(void) in tdef.h
+ and added definition to ni.c, so pointers are defined explicitly.
+ makes it work on turbo c++ and probably others.
+
+ changed a couple of isdigit's and isgraph(getch()) to avoid
+ multiple evaluation (even though it shouldn't happen).
+
+ Made /usr/bin/nroff a shell script.
+
+May 12, 1992:
+ n1.c: need p++ after strrchr to skip / in program name.
+ thanks to Rich Drechsler.
+
+Apr 17, 1992:
+ casefi(), n5.c: .u register should be 0 or 1, not incremented
+ with each .fi.
+
+Apr 5, 1992:
+ fiddled n7.c and added _nmwid to the environment, to add a
+ 5th argument to .nm: the maximum number of digits in any
+ line number. default is 3, which was previously hardwired in.
+
+ added jaap's code for yet another register which actually delivers
+ a string, called .S (so it can easily go in the switch in setn()
+ in n4.c); it delivers the current tabstop and alignment modes in
+ a format suitable for a subsequent .ta \n(.S command:
+ .ds T \n(.S
+ ...
+ .ta \*T
+
+Mar 30, 1992:
+ added test in getword to avoid hyphenating things with motions
+ (and avoid a core dump sometimes too).
+
+Mar 13, 1992:
+ \n(sb initialized wrong in setwd().
+
+ TYPESETTER=foo troff -Tpost used foo instead of post.
+
+Mar 12, 1992:
+ rearranged tests in popf so that .so is closed properly before
+ moving on to the next macro package.
+
+Mar 1, 1992:
+ input mechanism rearranged to use getc() instead of stack of
+ explicit input buffers. 5-10% slowdown.
+
+Jan 28, 1992:
+ fixed .tm \(mi to print something sensible. thanks to jaap.
+
+Jan 2, 1992:
+ fiddle setfp so doesn't put out font stuff if -a turned on.
+
+Dec 17, 1991:
+ copy 3rd argument in .fp commands to x font ... lines when it contains
+ a /, for testing fonts locally.
+
+Dec 13, 1991:
+ parameterize the font directories, etc., so can be set in makefiles.
+ added -N argument to run as nroff.
+
+Nov 8, 1991:
+ add a maplow(towlower...) in n8.c to handle brain-damaged libraries.
+
+Nov 2, 1991:
+ merged nroff into troff, based on Ken's plan 9 version.
+ merged nii.c into ni.c, removed tw.h, etc. more work needed
+ to make this stuff cleaner.
+
+July 27, 1991:
+ added test in setn in n4 to fix bug that permitted things like
+ \n (ab to work "properly". thanks to jaap for finding and fixing.
+
+ added paranoid testing in t11 to make sure font files look ok.
+
+May 13, 1991:
+ moved evaluation of \(xx from copy mode to non-copy mode, so that
+ weird character names wouldn't get reevaluated in argument parsing.
+ installed july 27.
+
+May 6, 1991:
+ increased size of hyphenation exception buffer to 512 from 128
+
+Apr 14, 1991:
+ added an extra redundant call of ptfont in setfp, since it appears
+ that some versions of adobe transcript assume that an "x font" command
+ means to change the actual font as well. the fix preserves the current font.
+ thanks to david brailsford and friends for spotting the problem.
+
+ fixed up tests in alpha() in n8 to defend isalpha() against too-big inputs.
+ punct() argument had wrong type too. thanks to rich drexler and peter nelson.
+
+Mar 19, 1991:
+ fixed bug that prevented .rd from working with new corebuf organization.
+
+ fixed bug that caused .ig inside diversions to give bad storage
+ allocation. thanks to arthur david olson, whose fix was on netnews
+ 3 years earlier.
+
+Mar 5, 1991:
+ huge table sizes for kanji.
+
+Feb ??, 1991:
+ working on dealing with large alphabets, notably kanji.
+ added "defaultwidth" to font descriptions, for characters
+ not given an explicit width.
+
+Jan, 1991:
+ added tex hyphenation, using standard tex data files, but not the
+ elaborate compressed trie, which is a lot of trouble to save maybe
+ 40k bytes. this appears to run at exactly the same speed as before.
+
+ so far this stuff reads into a fixed size array; that should change.
+ it should also be possible to deal with multiple languages.
+
+ the command .ha sets the algorithm. .ha 1 => tex, with troff rules
+ if tex doesn't hyphenate; .ha 0 gives troff rules, and .ha resets
+ to the default, which is tex. the hyphenation algorithm is part of
+ the environment, a nod to a future in which i handle more than one
+ language.
+
+ replaced the fixed size corebuf array for string/macro storage by
+ a dynamic structure that can grow.
+
+ this appears to slow things down by maybe 3%. the code is about
+ the same complexity.
+
+Dec 27, 1990:
+ converted to ansi c, based on some work by ken thompson, but not
+ as thoroughly as he did. there is a shell script unansi and an awk
+ program cvt that will help you step back in time if you do not have
+ an ansi c compiler.
+
+ moved the special-name characters up to 256 instead of 128, although
+ done in terms of ALPHABET, so one can pass 8 bit characters through.
+ removed lots of 0177's and similar numbers. input is now not filtered,
+ and if a character with the 8th bit on comes in, it will go out again.
+
+ fixed t11.c to read character names in hex or octal as well as
+ single-character ascii.
+
+ unknown characters are now carried through with width = spacewidth.
+ needs a way to set widths.
+
+ removed all signal handling from troff. you signal, you die.
+
+ added -d option to print version number.
+
+Dec 7, 1990:
+ .fp 3 V VERYLONGNAME used to truncate the name to 10 chars; fixed.
+
+ increased the limit on FBUFSZ for tables with very long fields.
+
+ changed atoi1() to use double to avoid intermediate overflow.
+
+ moved filenames like /usr/lib/font into tdef.h for easy change.
+ removed some dreggish definitions.
+
+ cleaned up non-portable error printing stuff; fixed up some messages.
+
+Dec 12, 1989:
+ Removed the .! command, an undocumented synonym for .sy.
+
+Dec 4, 1989:
+ Another wart to the \X code, to try to preserve blanks in all situations.
+
+Nov 17, 1989:
+ A number of small changes preparatory to getting rid of nroff.
+ The argument -Tnroff or -Tnroff-12 changes some internal values
+ so that the predicate .if n is true and certain arithmetic operations
+ are done as if nroff. This design is not yet final.
+
+Nov 7, 1989:
+ Fixed hyphenation for nov-ice, ad-vice, de-vice, ser-vice, *-vice.
+
+Oct 11, 1989:
+ It is now permitted to do an explicit change to font S.
+ It is not clear what will break (though nothing seems to have).
+
+Oct 10, 1989:
+ Modified flush code to always put out \nH instead of sometimes h.
+ This makes it easier to parse the output for positioning.
+
+Sep 9, 1989:
+ Fixed internal representation of \D'~...' so that it
+ is immune to .tr ~ and variations. No external change.
+
+Aug 9, 1989:
+ Changed .tm so it outputs \e, \%, \-, \&, \(blank).
+ This might break indexing code.
+ Only in the new version, as are all subsequent fixes.
+
+July, 1989:
+ A major internal change: font information is read in ascii
+ instead of the weird binary format of makedev (which is now dead).
+ character names need not all appear in DESC; new names that
+ appear when a font is used become part of the set of known names.
+
+ There are some flaky bits here (it's conceivable that some \N
+ number will collide with a real name), and it's probably 10-15%
+ slower. Tant pis.
+
+ As a by-product, nroff no longer compiles. I'll probably get
+ back to this, but an alternative is to bag it once and for all.
+
+May 25, 1989:
+ Another bug in \l, this time when width is 0. Not installed,
+ since it's in the new font version.
+
+Apr 23, 1989:
+ Fixed bug in n9 that caused core dump with unterminated
+ \l command, like \l'1.5i
+
+ ptflush no longer called when -a is on.
+
+Apr 12, 1989:
+ fixed bug in n2 that failed to suppress printing of \!
+ output when a -o was in effect.
+
+Apr 5, 1989:
+ .fl and \X now cause output of size, font, hpos and vpos.
+ this is necesary for postprocessors that intend to insert
+ independent material, such as postscript.
+
+Feb 1, 1989:
+ wait for .pi pipe to empty before exiting
+
+Oct 2, 1988:
+ default is now -Tpost
+
+Sep 19, 1988:
+ added abortive code to handle built-up characters by
+ passing something through as \D'b...'. never used.
+
+Jul 4, 1988:
+ replaced the sbrk nonsense in n3.c by calls to malloc.
+
+ \N now tests against proper font size.
+
+ installed Jaap Akkerhuis's code (mutatis mutandis) for
+ permitting up to 99 fonts, swapping them into font pos 0
+ as needed. fixes the long-standing problem of having
+ multiple font changes on a single output line.
+
+Jul 2, 1988:
+ \X now preserves spaces even when contents are diverted.
+
+ \N code safer -- NTRTAB and NWIDCACHE enlarged.
+
+Jul 14, 1987:
+ Fixed obscure bug causing incorrect indentation of .mc output.
diff --git a/src/cmd/troff/README b/src/cmd/troff/README
new file mode 100644
index 00000000..6dc8fa09
--- /dev/null
+++ b/src/cmd/troff/README
@@ -0,0 +1,31 @@
+To make troff (actually a.out):
+
+ make
+
+You will also need to write a driver for your favorite output device.
+d202.c provides a model, although it is specialized to a machine no
+one has. There are also a variety of postscript drivers that are the
+best thing to use if you have a postscript device.
+
+You will also have to make a DESC file for your typesetter and some
+font description files; see dev202 for examples. These describe the
+named characters, widths, kerning information, and output codes.
+
+Nroff is the same program as troff, so you should
+
+ cp a.out /usr/bin/troff
+ ln /usr/bin/troff /usr/bin/nroff
+
+or the equivalent.
+
+You will also need terminal description files for your terminals; see
+tab.37, tab.450 and tab.lp for examples.
+
+Troff uses files that are normally stored in /usr/lib/font;
+macro packages are in /usr/lib/tmac; and nroff tables are in
+/usr/lib/term. You can edit tdef.h to change these assumptions.
+
+There have been a few features since the last version, and a number of
+significant internal changes. Not all are improvements, of course.
+Most of the more recent changes, including bug fixes, are in FIXES,
+which you should read also.
diff --git a/src/cmd/troff/cvt b/src/cmd/troff/cvt
new file mode 100644
index 00000000..3426d626
--- /dev/null
+++ b/src/cmd/troff/cvt
@@ -0,0 +1,45 @@
+
+awk '
+
+/^{/ {
+ if (prev != "") {
+ # comments can be trouble (e.g. ffree())
+ if ( (c = match(prev, /\/\*.*\*\/$/)) != 0 ) {
+ comment = substr(prev, c)
+ sub(/\/\*.*\*\/$/, "", prev)
+ } else comment = ""
+
+ x = prev
+
+ # isolate argument list
+ sub(/^[^(]*\(/, "", x)
+ sub(/\)[^)]*$/, "", x)
+
+ # find the names in it
+ n = split(x, args)
+ arglist = ""
+ for (i = 2; i <= n; i += 2)
+ arglist = arglist args[i]
+ gsub(/\(\*f\)\(Tchar\)/, "f", arglist) # special case for n4.c
+ gsub(/\[[0-9]+\]/, "", arglist) # for n8.c
+ gsub(/[*()\[\]]/, "", arglist) # discard noise characters *()[]
+ gsub(/,/, ", ", arglist) # space nicely
+ sub(/\(.*\)/, "(" arglist ")", prev) # reconstruct
+ print prev comment
+
+ # argument declarations
+ gsub(/,/, ";", x)
+ gsub(/\(\*f\)\(Tchar\)/, "(*f)()", x) # special case for n4.c
+ if (x != "")
+ print "\t" x ";"
+ }
+ prev = $0
+ next
+}
+
+{ print prev
+ prev = $0
+}
+
+END { print prev }
+' $*
diff --git a/src/cmd/troff/dwbinit.c b/src/cmd/troff/dwbinit.c
new file mode 100644
index 00000000..a63e5fde
--- /dev/null
+++ b/src/cmd/troff/dwbinit.c
@@ -0,0 +1,313 @@
+/*
+ *
+ * Pathname management routines for DWB C programs.
+ *
+ * Applications should initialize a dwbinit array with the string
+ * pointers and arrays that need to be updated, and then hand that
+ * array to DWBinit before much else happens in their main program.
+ * DWBinit calls DWBhome to get the current home directory. DWBhome
+ * uses the last definition of DWBENV (usually "DWBHOME") in file
+ * DWBCONFIG (e.g., /usr/lib/dwb3.4) or the value assigned to that
+ * variable in the environment if the DWBCONFIG file doesn't exist,
+ * can't be read, or doesn't define DWBENV.
+ *
+ * DWBCONFIG must be a simple shell script - comments, a definition
+ * of DWBHOME, and perhaps an export or echo is about all that's
+ * allowed. The parsing in DWBhome is simple and makes no attempt
+ * to duplicate the shell. It only looks for DWBHOME= as the first
+ * non-white space string on a line, so
+ *
+ * #
+ * # A sample DWBCONFIG shell script
+ * #
+ *
+ * DWBHOME=/usr/add-on/dwb3.4
+ * export DWBHOME
+ *
+ * means DWBhome would return "/usr/add-on/dwb3.4" for the DWB home
+ * directory. A DWBCONFIG file means there can only be one working
+ * copy of a DWB release on a system, which seems like a good idea.
+ * Using DWBCONFIG also means programs will always include correct
+ * versions of files (e.g., prologues or macro packages).
+ *
+ * Relying on an environment variable guarantees nothing. You could
+ * execute a version of dpost, but your environment might point at
+ * incorrect font tables or prologues. Despite the obvious problems
+ * we've also implemented an environment variable approach, but it's
+ * only used if there's no DWBCONFIG file.
+ *
+ * DWBinit calls DWBhome to get the DWB home directory prefix and
+ * then marches through its dwbinit argument, removing the default
+ * home directory and prepending the new home. DWBinit stops when
+ * it reaches an element that has NULL for its address and value
+ * fields. Pointers in a dwbinit array are reallocated and properly
+ * initialized; arrays are simply reinitialized if there's room.
+ * All pathnames that are to be adjusted should be relative. For
+ * example,
+ *
+ * char *fontdir = "lib/font";
+ * char xyzzy[25] = "etc/xyzzy";
+ *
+ * would be represented in a dwbinit array as,
+ *
+ * dwbinit allpaths[] = {
+ * &fontdir, NULL, 0,
+ * NULL, xyzzy, sizeof(xyzzy),
+ * NULL, NULL, 0
+ * };
+ *
+ * The last element must have NULL entries for the address and
+ * value fields. The main() routine would then do,
+ *
+ * #include "dwbinit.h"
+ *
+ * main() {
+ *
+ * DWBinit("program name", allpaths);
+ * ...
+ * }
+ *
+ * Debugging is enabled if DWBDEBUG is in the environment and has
+ * the value ON. Output is occasionally useful and probably should
+ * be documented.
+ *
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "dwbinit.h"
+
+#ifndef DWBCONFIG
+#define DWBCONFIG "/dev/null"
+#endif
+
+#ifndef DWBENV
+#define DWBENV "DWBHOME"
+#endif
+
+#ifndef DWBHOME
+#define DWBHOME ""
+#endif
+
+#ifndef DWBDEBUG
+#define DWBDEBUG "DWBDEBUG"
+#endif
+
+#ifndef DWBPREFIX
+#define DWBPREFIX "\\*(.P"
+#endif
+
+/*****************************************************************************/
+
+void DWBdebug(dwbinit *ptr, int level)
+{
+
+ char *path;
+ char *home;
+ static char *debug = NULL;
+
+/*
+ *
+ * Debugging output, but only if DWBDEBUG is defined to be ON in the
+ * environment. Dumps general info the first time through.
+ *
+ */
+
+ if ( debug == NULL && (debug = getenv(DWBDEBUG)) == NULL )
+ debug = "OFF";
+
+ if ( strcmp(debug, "ON") == 0 ) {
+ if ( level == 0 ) {
+ fprintf(stderr, "Environment variable: %s\n", DWBENV);
+ fprintf(stderr, "Configuration file: %s\n", DWBCONFIG);
+ fprintf(stderr, "Default home: %s\n", DWBHOME);
+ if ( (home = DWBhome()) != NULL )
+ fprintf(stderr, "Current home: %s\n", home);
+ } /* End if */
+
+ fprintf(stderr, "\n%s pathnames:\n", level == 0 ? "Original" : "Final");
+ for ( ; ptr->value != NULL || ptr->address != NULL; ptr++ ) {
+ if ( (path = ptr->value) == NULL ) {
+ path = *ptr->address;
+ fprintf(stderr, " pointer: %s\n", path);
+ } else fprintf(stderr, " array[%d]: %s\n", ptr->length, path);
+ if ( level == 0 && *path == '/' )
+ fprintf(stderr, " WARNING - absolute path\n");
+ } /* End for */
+ } /* End if */
+
+} /* End of DWBdebug */
+
+/*****************************************************************************/
+
+char *DWBhome(void)
+{
+
+ FILE *fp;
+ char *ptr;
+ char *path;
+ int len;
+ char buf[200];
+ char *home = NULL;
+
+/*
+ *
+ * Return the DWB home directory. Uses the last definition of DWBENV
+ * (usually "DWBHOME") in file DWBCONFIG (perhaps /usr/lib/dwb3.4) or
+ * the value assigned to the variable named by the DWBENV string in
+ * the environment if DWBCONFIG doesn't exist or doesn't define DWBENV.
+ * Skips the file lookup if DWBCONFIG can't be read. Returns NULL if
+ * there's no home directory.
+ *
+ */
+
+ if ( (fp = fopen(DWBCONFIG, "r")) != NULL ) {
+ len = strlen(DWBENV);
+ while ( fgets(buf, sizeof(buf), fp) != NULL ) {
+ for ( ptr = buf; isspace(*ptr); ptr++ ) ;
+ if ( strncmp(ptr, DWBENV, len) == 0 && *(ptr+len) == '=' ) {
+ path = ptr + len + 1;
+ for ( ptr = path; !isspace(*ptr) && *ptr != ';'; ptr++ ) ;
+ *ptr = '\0';
+ if ( home != NULL )
+ free(home);
+ if ( (home = malloc(strlen(path)+1)) != NULL )
+ strcpy(home, path);
+ } /* End if */
+ } /* End while */
+ fclose(fp);
+ } /* End if */
+
+ if ( home == NULL ) {
+ if ( (home = getenv(DWBENV)) == NULL ) {
+ if ( (home = DWBHOME) == NULL || *home == '\0' || *home == ' ' )
+ home = NULL;
+ } /* End if */
+ } /* End if */
+
+ while (home && *home == '/' && *(home +1) == '/') /* remove extra slashes */
+ home++;
+ return(home);
+
+} /* End of DWBhome */
+
+/*****************************************************************************/
+
+void DWBinit(char *prog, dwbinit *paths)
+{
+
+ char *prefix;
+ char *value;
+ char *path;
+ int plen;
+ int length;
+ dwbinit *opaths = paths;
+
+/*
+ *
+ * Adjust the pathnames listed in paths, using the home directory
+ * returned by DWBhome(). Stops when it reaches an element that has
+ * NULL address and value fields. Assumes pathnames are relative,
+ * but changes everything. DWBdebug issues a warning if an original
+ * path begins with a /.
+ *
+ * A non-NULL address refers to a pointer, which is reallocated and
+ * then reinitialized. A NULL address implies a non-NULL value field
+ * and describes a character array that we only reinitialize. The
+ * length field for an array is the size of that array. The length
+ * field of a pointer is an increment that's added to the length
+ * required to store the new pathname string - should help when we
+ * want to change character arrays to pointers in applications like
+ * troff.
+ *
+ */
+
+ if ( (prefix = DWBhome()) == NULL ) {
+ fprintf(stderr, "%s: no DWB home directory\n", prog);
+ exit(1);
+ } /* End if */
+
+ DWBdebug(opaths, 0);
+ plen = strlen(prefix);
+
+ for ( ; paths->value != NULL || paths->address != NULL; paths++ ) {
+ if ( paths->address == NULL ) {
+ length = 0;
+ value = paths->value;
+ } else {
+ length = paths->length;
+ value = *paths->address;
+ } /* End else */
+
+ length += plen + 1 + strlen(value); /* +1 is for the '/' */
+
+ if ( (path = malloc(length+1)) == NULL ) {
+ fprintf(stderr, "%s: can't allocate pathname memory\n", prog);
+ exit(1);
+ } /* End if */
+
+ if ( *value != '\0' ) {
+ char *eop = prefix;
+ while(*eop++)
+ ;
+ eop -= 2;
+ if (*value != '/' && *eop != '/') {
+ sprintf(path, "%s/%s", prefix, value);
+ } else if (*value == '/' && *eop == '/') {
+ value++;
+ sprintf(path, "%s%s", prefix, value);
+ } else
+ sprintf(path, "%s%s", prefix, value);
+ } else
+ sprintf(path, "%s", prefix);
+
+ if ( paths->address == NULL ) {
+ if ( strlen(path) >= paths->length ) {
+ fprintf(stderr, "%s: no room for %s\n", prog, path);
+ exit(1);
+ } /* End if */
+ strcpy(paths->value, path);
+ free(path);
+ } else *paths->address = path;
+ } /* End for */
+
+ DWBdebug(opaths, 1);
+
+} /* End of DWBinit */
+
+/*****************************************************************************/
+
+void DWBprefix( char *prog, char *path, int length)
+{
+
+ char *home;
+ char buf[512];
+ int len = strlen(DWBPREFIX);
+
+/*
+ *
+ * Replace a leading DWBPREFIX string in path by the current DWBhome().
+ * Used by programs that pretend to handle .so requests. Assumes path
+ * is an array with room for length characters. The implementation is
+ * not great, but should be good enough for now. Also probably should
+ * have DWBhome() only do the lookup once, and remember the value if
+ * called again.
+ *
+ */
+
+ if ( strncmp(path, DWBPREFIX, len) == 0 ) {
+ if ( (home = DWBhome()) != NULL ) {
+ if ( strlen(home) + strlen(path+len) < length ) {
+ sprintf(buf, "%s%s", home, path+len);
+ strcpy(path, buf); /* assuming there's room in path */
+ } else fprintf(stderr, "%s: no room to grow path %s", prog, path);
+ } /* End if */
+ } /* End if */
+
+} /* End of DWBprefix */
+
+/*****************************************************************************/
+
diff --git a/src/cmd/troff/dwbinit.h b/src/cmd/troff/dwbinit.h
new file mode 100644
index 00000000..acb1476c
--- /dev/null
+++ b/src/cmd/troff/dwbinit.h
@@ -0,0 +1,19 @@
+/*
+ *
+ * A structure used to adjust pathnames in DWB C code. Pointers
+ * set the address field, arrays use the value field and must
+ * also set length to the number elements in the array. Pointers
+ * are always reallocated and then reinitialized; arrays are only
+ * reinitialized, if there's room.
+ *
+ */
+
+typedef struct {
+ char **address;
+ char *value;
+ int length;
+} dwbinit;
+
+extern void DWBinit(char *, dwbinit *);
+extern char* DWBhome(void);
+extern void DWBprefix(char *, char *, int);
diff --git a/src/cmd/troff/ext.h b/src/cmd/troff/ext.h
new file mode 100644
index 00000000..42147880
--- /dev/null
+++ b/src/cmd/troff/ext.h
@@ -0,0 +1,184 @@
+extern int TROFF;
+
+extern int alphabet;
+extern char **argp;
+extern char *eibuf;
+extern char *ibufp;
+extern char *obufp;
+extern char *unlkp;
+extern char *xbufp;
+extern char *xeibuf;
+extern char cfname[NSO+1][NS];
+extern int trace;
+extern char devname[];
+extern char ibuf[IBUFSZ];
+extern char mfiles[NMF][NS];
+extern char nextf[];
+extern char obuf[];
+extern char termtab[];
+extern char fontdir[];
+extern Font fonts[MAXFONTS+1];
+extern char xbuf[IBUFSZ];
+extern Offset apptr;
+extern Offset ip;
+extern Offset nextb;
+extern Offset offset;
+extern Offset woff;
+extern Numerr numerr;
+extern int *pnp;
+extern int pstab[];
+extern int nsizes;
+extern int app;
+extern int ascii;
+extern int bd;
+extern int bdtab[];
+extern int ccs;
+extern char *chnames[]; /* chnames[n-ALPHABET] -> name of char n */
+extern int copyf;
+extern int cs;
+extern int dfact;
+extern int dfactd;
+extern int diflg;
+extern int dilev;
+extern int donef;
+extern int dotT;
+extern int dpn;
+extern int ds;
+extern int ejf;
+extern int em;
+extern int eqflg;
+extern int error;
+extern int esc;
+extern int eschar;
+extern int ev;
+extern int evi;
+extern int evlist[EVLSZ];
+extern int fc;
+extern int flss;
+extern int fontlab[];
+extern int hflg;
+extern int ibf;
+extern int ifi;
+extern int iflg;
+extern int init;
+extern int lead;
+extern int lg;
+extern int lgf;
+extern int macerr;
+extern int mflg;
+extern int mfont;
+extern int mlist[NTRAP];
+extern int mpts;
+extern int nchnames;
+extern int ndone;
+extern int newmn;
+extern int nflush;
+extern int nfo;
+extern int nfonts;
+extern int nform;
+extern int nhyp;
+extern int nlflg;
+extern int nlist[NTRAP];
+extern int nmfi;
+extern int nonumb;
+extern int noscale;
+extern int npn;
+extern int npnflg;
+extern int nx;
+extern int oldbits;
+extern int oldmn;
+extern int over;
+extern int padc;
+extern int pfont;
+extern int pfrom;
+extern int pipeflg;
+extern int pl;
+extern int pnlist[];
+extern int po1;
+extern int po;
+extern int ppts;
+extern int print;
+extern FILE *ptid;
+extern int pto;
+extern int quiet;
+extern int ralss;
+extern int rargc;
+extern int raw;
+extern int res;
+extern int sbold;
+extern int setwdf;
+extern int sfont;
+extern int smnt;
+extern int stdi;
+extern int stop;
+extern int sv;
+extern int tabch, ldrch;
+extern int tflg;
+extern int totout;
+extern int trap;
+extern Ushort trtab[];
+extern int tty;
+extern int ulfont;
+extern int vflag;
+extern int whichroff;
+extern int widthp;
+extern int xfont;
+extern int xpts;
+extern Stack *ejl;
+extern Stack *frame;
+extern Stack *stk;
+extern Stack *nxf;
+extern Tchar **hyp;
+extern Tchar *olinep;
+extern Tchar pbbuf[NC];
+extern Tchar *pbp;
+extern Tchar *lastpbp;
+extern Tchar ch;
+extern Tchar nrbits;
+extern Tbuf _oline;
+extern Wcache widcache[];
+extern char gchtab[];
+extern Diver d[NDI];
+extern Diver *dip;
+
+
+extern char xchname[];
+extern short xchtab[];
+extern char *codestr;
+extern char *chnamep;
+extern short *chtab;
+extern int nchtab;
+
+extern Numtab *numtabp;
+
+/* these characters are used as various signals or values
+/* in miscellaneous places.
+/* values are set in specnames in t10.c
+*/
+
+extern int c_hyphen;
+extern int c_emdash;
+extern int c_rule;
+extern int c_minus;
+extern int c_fi;
+extern int c_fl;
+extern int c_ff;
+extern int c_ffi;
+extern int c_ffl;
+extern int c_acute;
+extern int c_grave;
+extern int c_under;
+extern int c_rooten;
+extern int c_boxrule;
+extern int c_lefthand;
+extern int c_dagger;
+extern int c_isalnum;
+
+/*
+ * String pointers for DWB pathname management.
+ */
+
+extern char *DWBfontdir;
+extern char *DWBntermdir;
+extern char *DWBalthyphens;
+
diff --git a/src/cmd/troff/find b/src/cmd/troff/find
new file mode 100644
index 00000000..eccbfbdb
--- /dev/null
+++ b/src/cmd/troff/find
@@ -0,0 +1 @@
+grep $1 *.[ch]
diff --git a/src/cmd/troff/fns.h b/src/cmd/troff/fns.h
new file mode 100644
index 00000000..6bd94ada
--- /dev/null
+++ b/src/cmd/troff/fns.h
@@ -0,0 +1,384 @@
+/*
+ * other
+ */
+int pclose(FILE*);
+long filesize(int fd);
+int open(char *, int);
+int read(int, char *, int);
+int lseek(int, long, int);
+int close(int);
+int getpid(void);
+
+/*
+ * c1.c
+ */
+void init0(void);
+void init2(void);
+void cvtime(void);
+void errprint(void);
+int control(int a, int b);
+void casept(void);
+int getrq(void);
+Tchar getch(void);
+void setxon(void);
+Tchar getch0(void);
+Tchar get1ch(FILE *);
+void pushback(Tchar *b);
+void cpushback(char *b);
+int nextfile(void);
+int popf(void);
+void flushi(void);
+int getach(void);
+void casenx(void);
+int getname(void);
+void caseso(void);
+void caself(void);
+void casecf(void);
+void getline(char *s, int n);
+void casesy(void);
+void getpn(char *a);
+void setrpt(void);
+
+/*
+ * n2.c
+ */
+int pchar(Tchar i);
+void pchar1(Tchar i);
+int pchar2(Tchar i);
+int flusho(void);
+void casedone(void);
+void caseex(void);
+void done(int x);
+void done1(int x);
+void done2(int x);
+void done3(int x);
+void edone(int x);
+void casepi(void);
+
+/*
+ * c3.c
+ */
+void blockinit(void);
+char* grow(char *, int, int);
+void mnspace(void);
+void caseig(void);
+void casern(void);
+void maddhash(Contab *rp);
+void munhash(Contab *mp);
+void mrehash(void);
+void caserm(void);
+void caseas(void);
+void caseds(void);
+void caseam(void);
+void casede(void);
+int findmn(int i);
+void clrmn(int i);
+Offset finds(int mn);
+int skip(void);
+int copyb(void);
+void copys(void);
+Offset alloc(void);
+void ffree(Offset i);
+void wbf(Tchar i);
+Tchar rbf(void);
+Tchar popi(void);
+Offset pushi(Offset newip, int mname);
+void* setbrk(int x);
+int getsn(void);
+Offset setstr(void);
+void collect(void);
+void seta(void);
+void caseda(void);
+void casegd(void);
+void casedi(void);
+void casedt(void);
+void casetl(void);
+void casepc(void);
+void casepm(void);
+void stackdump(void);
+
+/*
+ * c4.c
+ */
+void setn(void);
+int wrc(Tchar i);
+void setn1(int i, int form, Tchar bits);
+void nnspace(void);
+void nrehash(void);
+void nunhash(Numtab *rp);
+int findr(int i);
+int usedr(int i);
+int fnumb(int i, int (*f)(Tchar));
+int decml(int i, int (*f)(Tchar));
+int roman(int i, int (*f)(Tchar));
+int roman0(int i, int (*f)(Tchar), char *onesp, char *fivesp);
+int abc(int i, int (*f)(Tchar));
+int abc0(int i, int (*f)(Tchar));
+long atoi0(void);
+long ckph(void);
+long atoi1(Tchar ii);
+void caserr(void);
+void casenr(void);
+void caseaf(void);
+void setaf(void);
+int vnumb(int *i);
+int hnumb(int *i);
+int inumb(int *n);
+int quant(int n, int m);
+
+/*
+ * c5.c
+ */
+void casead(void);
+void casena(void);
+void casefi(void);
+void casenf(void);
+void casers(void);
+void casens(void);
+int chget(int c);
+void casecc(void);
+void casec2(void);
+void casehc(void);
+void casetc(void);
+void caselc(void);
+void casehy(void);
+int max(int aa, int bb);
+void casenh(void);
+void casece(void);
+void casein(void);
+void casell(void);
+void caselt(void);
+void caseti(void);
+void casels(void);
+void casepo(void);
+void casepl(void);
+void casewh(void);
+void casech(void);
+int findn(int i);
+void casepn(void);
+void casebp(void);
+void casextm(void);
+void casetm(void);
+void casefm(void);
+void casetm1(int ab, FILE *out);
+void casesp(void);
+void casesp1(int a);
+void casert(void);
+void caseem(void);
+void casefl(void);
+void caseev(void);
+void envcopy(Env *e1, Env *e2);
+void caseel(void);
+void caseie(void);
+void casexif(void);
+void caseif(void);
+void caseif1(int);
+void eatblk(int inblk);
+int cmpstr(Tchar c);
+void caserd(void);
+int rdtty(void);
+void caseec(void);
+void caseeo(void);
+void caseta(void);
+void casene(void);
+void casetr(void);
+void casecu(void);
+void caseul(void);
+void caseuf(void);
+void caseit(void);
+void casemc(void);
+void casemk(void);
+void casesv(void);
+void caseos(void);
+void casenm(void);
+void getnm(int *p, int min);
+void casenn(void);
+void caseab(void);
+void save_tty(void);
+void restore_tty(void);
+void set_tty(void);
+void echo_off(void);
+void echo_on(void);
+
+/*
+ * t6.c
+ */
+int t_width(Tchar j);
+void zapwcache(int s);
+int onfont(int n, int f);
+int getcw(int i);
+void xbits(Tchar i, int bitf);
+Tchar t_setch(int c);
+Tchar t_setabs(void);
+int t_findft(int i);
+void caseps(void);
+void casps1(int i);
+int findps(int i);
+void t_mchbits(void);
+void t_setps(void);
+Tchar t_setht(void);
+Tchar t_setslant(void);
+void caseft(void);
+void t_setfont(int a);
+void t_setwd(void);
+Tchar t_vmot(void);
+Tchar t_hmot(void);
+Tchar t_mot(void);
+Tchar t_sethl(int k);
+Tchar t_makem(int i);
+Tchar getlg(Tchar i);
+void caselg(void);
+void casefp(void);
+char *strdupl(const char *);
+int setfp(int pos, int f, char *truename, int print);
+void casecs(void);
+void casebd(void);
+void casevs(void);
+void casess(void);
+Tchar t_xlss(void);
+Uchar* unpair(int i);
+void outascii(Tchar i);
+
+/*
+ * c7.c
+ */
+void tbreak(void);
+void donum(void);
+void text(void);
+void nofill(void);
+void callsp(void);
+void ckul(void);
+void storeline(Tchar c, int w);
+void newline(int a);
+int findn1(int a);
+void chkpn(void);
+int findt(int a);
+int findt1(void);
+void eject(Stack *a);
+int movword(void);
+void horiz(int i);
+void setnel(void);
+int getword(int x);
+void storeword(Tchar c, int w);
+Tchar gettch(void);
+
+/*
+ * c8.c
+ */
+void hyphen(Tchar *wp);
+int punct(Tchar i);
+int alph(int i);
+void caseha(void);
+void caseht(void);
+void casehw(void);
+int exword(void);
+int suffix(void);
+int maplow(int i);
+int vowel(int i);
+Tchar* chkvow(Tchar *w);
+void digram(void);
+int dilook(int a, int b, char t[26][13]);
+
+/*
+ * c9.c
+ */
+Tchar setz(void);
+void setline(void);
+int eat(int c);
+void setov(void);
+void setbra(void);
+void setvline(void);
+void setdraw(void);
+void casefc(void);
+Tchar setfield(int x);
+
+/*
+ * t10.c
+ */
+void t_ptinit(void);
+void t_specnames(void);
+void t_ptout(Tchar i);
+int ptout0(Tchar *pi);
+void ptchname(int);
+void ptflush(void);
+void ptps(void);
+void ptfont(void);
+void ptfpcmd(int f, char *s, char *fn);
+void t_ptlead(void);
+void ptesc(void);
+void ptpage(int n);
+void pttrailer(void);
+void ptstop(void);
+void t_ptpause(void);
+
+/*
+ * t11.c
+ */
+int getdesc(char *name);
+int getfont(char *name, int pos);
+int chadd(char *s, int, int);
+char* chname(int n);
+int getlig(FILE *fin);
+
+/*
+ * n6.c
+ */
+int n_width(Tchar j);
+Tchar n_setch(int c);
+Tchar n_setabs(void);
+int n_findft(int i);
+void n_mchbits(void);
+void n_setps(void);
+Tchar n_setht(void);
+Tchar n_setslant(void);
+void n_caseft(void);
+void n_setfont(int a);
+void n_setwd(void);
+Tchar n_vmot(void);
+Tchar n_hmot(void);
+Tchar n_mot(void);
+Tchar n_sethl(int k);
+Tchar n_makem(int i);
+void n_casefp(void);
+void n_casebd(void);
+void n_casevs(void);
+Tchar n_xlss(void);
+
+/*
+ * n10.c
+ */
+void n_ptinit(void);
+char* skipstr(char *s);
+char* getstr(char *s, char *t);
+char* getint(char *s, int *pn);
+void twdone(void);
+void n_specnames(void);
+int findch(char *s);
+void n_ptout(Tchar i);
+void ptout1(void);
+char* plot(char *x);
+void move(void);
+void n_ptlead(void);
+void n_ptpause(void);
+
+/*
+ * indirect calls on TROFF/!TROFF. these are variables!
+ */
+extern Tchar (*hmot)(void);
+extern Tchar (*makem)(int i);
+extern Tchar (*setabs)(void);
+extern Tchar (*setch)(int c);
+extern Tchar (*sethl)(int k);
+extern Tchar (*setht)(void);
+extern Tchar (*setslant)(void);
+extern Tchar (*vmot)(void);
+extern Tchar (*xlss)(void);
+extern int (*findft)(int i);
+extern int (*width)(Tchar j);
+extern void (*mchbits)(void);
+extern void (*ptlead)(void);
+extern void (*ptout)(Tchar i);
+extern void (*ptpause)(void);
+extern void (*setfont)(int a);
+extern void (*setps)(void);
+extern void (*setwd)(void);
diff --git a/src/cmd/troff/hytab.c b/src/cmd/troff/hytab.c
new file mode 100644
index 00000000..623637fc
--- /dev/null
+++ b/src/cmd/troff/hytab.c
@@ -0,0 +1,126 @@
+/*
+ * Hyphenation digram tables
+ */
+
+typedef unsigned char Uchar;
+
+
+Uchar bxh[26][13] = {
+ 0060,0000,0040,0000,0040,0000,0000,0040,0000,0000,0040,0000,0040
+};
+
+Uchar hxx[26][13] = {
+ 0006,0042,0041,0123,0021,0024,0063,0042,0002,0043,0021,0001,0022,
+ 0140,0000,0200,0003,0260,0006,0000,0160,0007,0000,0140,0000,0320,
+ 0220,0000,0160,0005,0240,0010,0000,0100,0006,0000,0200,0000,0320,
+ 0240,0000,0120,0003,0140,0000,0000,0240,0010,0000,0220,0000,0160,
+ 0042,0023,0041,0040,0040,0022,0043,0041,0030,0064,0021,0000,0041,
+ 0100,0000,0140,0000,0220,0006,0000,0140,0003,0000,0200,0000,0000,
+ 0200,0000,0120,0002,0220,0010,0000,0160,0006,0000,0140,0000,0320,
+ 0020,0000,0020,0000,0020,0000,0000,0020,0000,0000,0020,0000,0000,
+ 0043,0163,0065,0044,0022,0043,0104,0042,0061,0146,0061,0000,0007,
+ 0100,0000,0140,0000,0040,0000,0000,0100,0000,0000,0120,0000,0000,
+ 0140,0000,0040,0011,0060,0004,0001,0120,0003,0000,0140,0000,0040,
+ 0200,0000,0100,0000,0140,0000,0000,0140,0000,0000,0140,0000,0240,
+ 0200,0000,0140,0000,0160,0000,0000,0220,0000,0000,0140,0000,0240,
+ 0200,0000,0140,0000,0160,0000,0000,0220,0000,0000,0060,0000,0240,
+ 0021,0043,0041,0121,0040,0023,0042,0003,0142,0042,0061,0001,0022,
+ 0120,0000,0140,0010,0140,0010,0000,0140,0002,0000,0120,0000,0120,
+ 0000,0000,0000,0000,0360,0000,0000,0000,0000,0000,0160,0000,0000,
+ 0100,0000,0040,0005,0120,0000,0000,0100,0000,0000,0060,0000,0140,
+ 0140,0040,0100,0001,0240,0041,0000,0242,0000,0002,0140,0000,0100,
+ 0240,0000,0120,0002,0200,0000,0000,0320,0007,0000,0240,0000,0340,
+ 0101,0021,0041,0020,0040,0005,0042,0121,0002,0021,0201,0000,0020,
+ 0160,0000,0100,0000,0140,0000,0000,0160,0006,0000,0220,0000,0140,
+ 0140,0000,0020,0001,0020,0000,0000,0100,0001,0000,0300,0000,0000,
+ 0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,
+ 0106,0041,0040,0147,0040,0000,0063,0041,0001,0102,0160,0002,0002,
+ 0300,0000,0040,0017,0140,0017,0000,0240,0000,0000,0140,0000,0120,
+};
+
+Uchar bxxh[26][13] = {
+ 0005,0150,0153,0062,0062,0246,0152,0127,0146,0203,0310,0017,0206,
+ 0100,0000,0120,0000,0140,0000,0000,0100,0000,0000,0120,0000,0060,
+ 0100,0000,0040,0000,0060,0000,0000,0060,0000,0000,0220,0000,0040,
+ 0100,0000,0120,0000,0200,0000,0000,0100,0000,0000,0140,0000,0060,
+ 0043,0142,0046,0140,0062,0147,0210,0131,0046,0106,0246,0017,0111,
+ 0060,0000,0020,0000,0060,0000,0000,0040,0000,0000,0100,0000,0000,
+ 0060,0000,0040,0000,0040,0000,0000,0040,0000,0000,0100,0000,0040,
+ 0100,0000,0100,0000,0100,0000,0000,0040,0000,0000,0100,0000,0140,
+ 0066,0045,0145,0140,0000,0070,0377,0030,0130,0103,0003,0017,0006,
+ 0040,0000,0040,0000,0020,0000,0000,0040,0000,0000,0100,0000,0000,
+ 0200,0000,0020,0000,0140,0000,0000,0120,0000,0000,0120,0000,0040,
+ 0120,0000,0040,0000,0060,0000,0000,0060,0000,0000,0160,0000,0040,
+ 0120,0000,0040,0000,0120,0000,0000,0040,0000,0000,0160,0000,0040,
+ 0120,0000,0020,0000,0140,0000,0000,0120,0000,0000,0140,0000,0040,
+ 0051,0126,0150,0140,0060,0210,0146,0006,0006,0165,0003,0017,0244,
+ 0120,0000,0040,0000,0160,0000,0000,0140,0000,0000,0060,0000,0140,
+ 0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,
+ 0140,0000,0140,0000,0060,0000,0000,0100,0000,0000,0140,0000,0020,
+ 0120,0000,0020,0000,0060,0000,0000,0060,0000,0000,0060,0000,0040,
+ 0140,0000,0020,0000,0100,0000,0000,0140,0000,0000,0140,0000,0020,
+ 0070,0125,0051,0162,0120,0105,0126,0104,0006,0044,0000,0017,0052,
+ 0140,0000,0020,0000,0140,0000,0000,0060,0000,0000,0060,0000,0040,
+ 0020,0000,0000,0000,0020,0000,0000,0000,0000,0000,0000,0000,0060,
+ 0140,0000,0160,0000,0200,0000,0000,0140,0000,0000,0000,0000,0240,
+ 0065,0042,0060,0200,0000,0210,0222,0146,0006,0204,0220,0012,0003,
+ 0240,0000,0020,0000,0120,0000,0000,0200,0000,0000,0200,0000,0240,
+};
+
+Uchar xhx[26][13] = {
+ 0032,0146,0042,0107,0076,0102,0042,0146,0202,0050,0006,0000,0051,
+ 0036,0377,0057,0013,0057,0366,0377,0057,0001,0377,0057,0000,0040,
+ 0037,0377,0020,0000,0100,0022,0377,0057,0362,0116,0100,0000,0017,
+ 0057,0377,0057,0031,0137,0363,0377,0037,0362,0270,0077,0000,0117,
+ 0074,0142,0012,0236,0076,0125,0063,0165,0341,0046,0047,0000,0024,
+ 0020,0017,0075,0377,0040,0001,0377,0017,0001,0204,0020,0000,0040,
+ 0057,0017,0057,0340,0140,0362,0314,0117,0003,0302,0100,0000,0057,
+ 0057,0357,0077,0017,0100,0366,0314,0057,0342,0346,0037,0000,0060,
+ 0252,0145,0072,0157,0377,0165,0063,0066,0164,0050,0363,0000,0362,
+ 0000,0000,0020,0000,0020,0000,0000,0017,0000,0000,0020,0000,0000,
+ 0117,0017,0237,0377,0200,0354,0125,0110,0004,0257,0000,0000,0300,
+ 0057,0367,0054,0357,0157,0216,0314,0114,0217,0353,0053,0000,0057,
+ 0077,0213,0077,0077,0177,0317,0377,0114,0377,0352,0077,0000,0076,
+ 0077,0213,0077,0077,0157,0177,0377,0054,0377,0352,0117,0000,0075,
+ 0125,0230,0065,0216,0057,0066,0063,0047,0345,0126,0011,0000,0033,
+ 0057,0377,0051,0360,0120,0361,0273,0056,0001,0256,0057,0000,0060,
+ 0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,
+ 0076,0310,0056,0310,0137,0174,0273,0055,0335,0266,0033,0000,0155,
+ 0077,0157,0057,0360,0057,0063,0042,0024,0077,0206,0020,0000,0040,
+ 0057,0037,0077,0360,0100,0365,0377,0037,0362,0176,0050,0000,0026,
+ 0167,0146,0042,0112,0077,0110,0062,0254,0366,0052,0377,0000,0163,
+ 0060,0000,0040,0000,0120,0000,0377,0060,0012,0000,0037,0000,0257,
+ 0037,0232,0157,0361,0040,0003,0125,0010,0001,0256,0000,0000,0340,
+ 0377,0377,0377,0377,0377,0377,0377,0377,0377,0377,0377,0017,0277,
+ 0253,0315,0257,0216,0377,0206,0146,0306,0371,0126,0232,0000,0004,
+ 0057,0012,0100,0360,0160,0360,0000,0040,0000,0017,0157,0000,0176,
+};
+
+Uchar xxh[26][13] = {
+ 0045,0150,0154,0162,0042,0246,0210,0147,0152,0103,0230,0017,0206,
+ 0100,0000,0040,0000,0140,0000,0000,0100,0000,0021,0120,0017,0060,
+ 0100,0000,0040,0002,0140,0320,0000,0060,0000,0001,0220,0017,0040,
+ 0100,0001,0120,0001,0241,0000,0000,0100,0000,0020,0140,0017,0060,
+ 0023,0162,0046,0142,0022,0207,0210,0131,0052,0106,0250,0017,0110,
+ 0060,0000,0042,0000,0160,0000,0000,0040,0000,0212,0100,0017,0000,
+ 0140,0000,0040,0002,0140,0000,0000,0120,0000,0040,0120,0017,0040,
+ 0100,0000,0100,0000,0140,0001,0021,0140,0000,0046,0100,0017,0140,
+ 0066,0045,0025,0201,0020,0130,0146,0030,0130,0103,0025,0017,0006,
+ 0100,0000,0040,0000,0020,0000,0000,0040,0000,0000,0200,0017,0000,
+ 0200,0000,0020,0001,0140,0000,0000,0140,0000,0000,0120,0017,0040,
+ 0120,0026,0042,0020,0140,0161,0042,0143,0000,0022,0162,0017,0040,
+ 0121,0042,0060,0020,0140,0200,0000,0123,0000,0021,0220,0017,0041,
+ 0121,0042,0060,0120,0140,0200,0000,0123,0000,0021,0160,0017,0041,
+ 0051,0126,0150,0141,0060,0210,0146,0066,0026,0165,0026,0017,0247,
+ 0120,0000,0040,0003,0160,0000,0000,0140,0000,0021,0100,0017,0140,
+ 0000,0000,0000,0000,0200,0000,0000,0000,0000,0000,0000,0017,0000,
+ 0141,0023,0122,0040,0160,0143,0042,0142,0000,0047,0143,0017,0020,
+ 0120,0000,0040,0006,0140,0060,0000,0141,0000,0026,0100,0017,0040,
+ 0140,0000,0020,0007,0100,0000,0000,0140,0000,0001,0140,0017,0020,
+ 0110,0125,0051,0162,0120,0125,0127,0104,0006,0104,0000,0017,0052,
+ 0140,0000,0040,0000,0160,0000,0000,0140,0000,0000,0060,0017,0000,
+ 0040,0005,0020,0000,0040,0313,0231,0030,0000,0140,0000,0017,0056,
+ 0140,0000,0160,0000,0200,0000,0000,0140,0000,0000,0000,0017,0240,
+ 0065,0042,0060,0040,0000,0206,0231,0146,0006,0224,0220,0017,0004,
+ 0240,0000,0020,0000,0140,0000,0000,0220,0000,0000,0200,0017,0141,
+};
diff --git a/src/cmd/troff/mbwc.c b/src/cmd/troff/mbwc.c
new file mode 100644
index 00000000..66a98219
--- /dev/null
+++ b/src/cmd/troff/mbwc.c
@@ -0,0 +1,165 @@
+#include <stdlib.h>
+
+/*
+ * Use the FSS-UTF transformation proposed by posix.
+ * We define 7 byte types:
+ * T0 0xxxxxxx 7 free bits
+ * Tx 10xxxxxx 6 free bits
+ * T1 110xxxxx 5 free bits
+ * T2 1110xxxx 4 free bits
+ *
+ * Encoding is as follows.
+ * From hex Thru hex Sequence Bits
+ * 00000000 0000007F T0 7
+ * 00000080 000007FF T1 Tx 11
+ * 00000800 0000FFFF T2 Tx Tx 16
+ */
+
+int
+mblen(const char *s, size_t n)
+{
+
+ return mbtowc(0, s, n);
+}
+
+int
+mbtowc(wchar_t *pwc, const char *s, size_t n)
+{
+ int c, c1, c2;
+ long l;
+
+ if(!s)
+ return 0;
+
+ if(n < 1)
+ goto bad;
+ c = s[0] & 0xff;
+ if((c & 0x80) == 0x00) {
+ if(pwc)
+ *pwc = c;
+ if(c == 0)
+ return 0;
+ return 1;
+ }
+
+ if(n < 2)
+ goto bad;
+ c1 = (s[1] ^ 0x80) & 0xff;
+ if((c1 & 0xC0) != 0x00)
+ goto bad;
+ if((c & 0xE0) == 0xC0) {
+ l = ((c << 6) | c1) & 0x7FF;
+ if(l < 0x080)
+ goto bad;
+ if(pwc)
+ *pwc = l;
+ return 2;
+ }
+
+ if(n < 3)
+ goto bad;
+ c2 = (s[2] ^ 0x80) & 0xff;
+ if((c2 & 0xC0) != 0x00)
+ goto bad;
+ if((c & 0xF0) == 0xE0) {
+ l = ((((c << 6) | c1) << 6) | c2) & 0xFFFF;
+ if(l < 0x0800)
+ goto bad;
+ if(pwc)
+ *pwc = l;
+ return 3;
+ }
+
+ /*
+ * bad decoding
+ */
+bad:
+ return -1;
+
+}
+
+int
+wctomb(char *s, wchar_t wchar)
+{
+ long c;
+
+ if(!s)
+ return 0;
+
+ c = wchar & 0xFFFF;
+ if(c < 0x80) {
+ s[0] = c;
+ return 1;
+ }
+
+ if(c < 0x800) {
+ s[0] = 0xC0 | (c >> 6);
+ s[1] = 0x80 | (c & 0x3F);
+ return 2;
+ }
+
+ s[0] = 0xE0 | (c >> 12);
+ s[1] = 0x80 | ((c >> 6) & 0x3F);
+ s[2] = 0x80 | (c & 0x3F);
+ return 3;
+}
+
+size_t
+mbstowcs(wchar_t *pwcs, const char *s, size_t n)
+{
+ int i, d, c;
+
+ for(i=0; i < n; i++) {
+ c = *s & 0xff;
+ if(c < 0x80) {
+ *pwcs = c;
+ if(c == 0)
+ break;
+ s++;
+ } else {
+ d = mbtowc(pwcs, s, 3);
+ if(d <= 0)
+ return (size_t)((d<0) ? -1 : i);
+ s += d;
+ }
+ pwcs++;
+ }
+ return i;
+}
+
+size_t
+wcstombs(char *s, const wchar_t *pwcs, size_t n)
+{
+ int i, d;
+ long c;
+ char *p, *pe;
+ char buf[3];
+
+ p = s;
+ pe = p+n-3;
+ while(p < pe) {
+ c = *pwcs++;
+ if(c < 0x80)
+ *p++ = c;
+ else
+ p += wctomb(p, c);
+ if(c == 0)
+ return p-s;
+ }
+ while(p < pe+3) {
+ c = *pwcs++;
+ d = wctomb(buf, c);
+ if(p+d <= pe+3) {
+ *p++ = buf[0];
+ if(d > 1) {
+ *p++ = buf[2];
+ if(d > 2)
+ *p++ = buf[3];
+ }
+ }
+ if(c == 0)
+ break;
+ }
+ return p-s;
+}
+
diff --git a/src/cmd/troff/mk.log b/src/cmd/troff/mk.log
new file mode 100644
index 00000000..26b610d6
--- /dev/null
+++ b/src/cmd/troff/mk.log
@@ -0,0 +1,136 @@
+9c -c -DUNICODE -DFONTDIR="sys/lib/troff/font" -DNTERMDIR="sys/lib/troff/term/tab." -DTEXHYPHENS="#9/sys/lib/texmf/tex/generic/hyphen/hyphen.tex" -DALTHYPHENS="sys/lib/texmf/tex/generic/hyphen/hyphen.tex" -DDWBHOME="#9/" n1.c
+n1.c:51: warning: return type defaults to `int'
+n1.c: In function `getch0':
+n1.c:676: warning: unused variable `j'
+n1.c:719: warning: label `g2' defined but not used
+n1.c: In function `get1ch':
+n1.c:745: warning: `n' might be used uninitialized in this function
+n1.c:745: warning: `c' might be used uninitialized in this function
+n1.c: In function `nextfile':
+n1.c:830: warning: implicit declaration of function `unsharp'
+n1.c:830: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
+n1.c: At top level:
+n1.c:842: warning: return type defaults to `int'
+n1.c:875: warning: return type defaults to `int'
+n1.c:915: warning: return type defaults to `int'
+n1.c: In function `getname':
+n1.c:917: warning: unused variable `i'
+n1.c: In function `caseso':
+n1.c:939: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
+n1.c:935: warning: unused variable `p'
+n1.c:935: warning: unused variable `q'
+n1.c:934: warning: `fp' might be used uninitialized in this function
+n1.c: In function `casecf':
+n1.c:1008: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
+9c -c -DUNICODE n2.c
+n2.c: In function `outascii':
+n2.c:140: warning: unused variable `p'
+9c -c -DUNICODE n3.c
+n3.c: In function `grow':
+n3.c:67: warning: unused variable `new'
+n3.c: In function `finds':
+n3.c:310: warning: unused variable `j'
+n3.c: In function `copyb':
+n3.c:372: warning: `savoff' might be used uninitialized in this function
+9c -c -DUNICODE n4.c
+n4.c: In function `setn':
+n4.c:144: warning: int format, long unsigned int arg (arg 3)
+9c -c -DUNICODE n5.c
+n5.c:83: warning: return type defaults to `int'
+n5.c: In function `chget':
+n5.c:84: warning: `i' might be used uninitialized in this function
+n5.c: At top level:
+n5.c:147: warning: return type defaults to `int'
+n5.c:338: warning: return type defaults to `int'
+n5.c: In function `casefm':
+n5.c:411: warning: implicit declaration of function `unsharp'
+n5.c:411: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
+n5.c: At top level:
+n5.c:747: warning: return type defaults to `int'
+n5.c:835: warning: return type defaults to `int'
+9c -c -DUNICODE t6.c
+t6.c:18: warning: return type defaults to `int'
+t6.c:79: warning: return type defaults to `int'
+t6.c:112: warning: return type defaults to `int'
+t6.c: In function `t_setch':
+t6.c:217: warning: unused variable `j'
+t6.c: At top level:
+t6.c:288: warning: return type defaults to `int'
+t6.c:367: warning: return type defaults to `int'
+t6.c: In function `t_setps':
+t6.c:397: warning: `j' might be used uninitialized in this function
+t6.c: At top level:
+t6.c:707: warning: return type defaults to `int'
+t6.c: In function `setfp':
+t6.c:708: warning: unused variable `sl'
+t6.c: In function `casebd':
+t6.c:781: warning: `j' might be used uninitialized in this function
+9c -c -DUNICODE n6.c
+n6.c:11: warning: return type defaults to `int'
+n6.c: In function `n_casebd':
+n6.c:295: warning: `j' might be used uninitialized in this function
+9c -c -DUNICODE n7.c
+n7.c: In function `newline':
+n7.c:354: warning: `nlss' might be used uninitialized in this function
+n7.c: At top level:
+n7.c:450: warning: return type defaults to `int'
+n7.c:482: warning: return type defaults to `int'
+n7.c:509: warning: return type defaults to `int'
+n7.c:544: warning: return type defaults to `int'
+n7.c:653: warning: return type defaults to `int'
+n7.c: In function `getword':
+n7.c:654: warning: `j' might be used uninitialized in this function
+9c -c -DUNICODE -DTEXHYPHENS="#9/sys/lib/texmf/tex/generic/hyphen/hyphen.tex" n8.c
+n8.c:76: warning: return type defaults to `int'
+n8.c:87: warning: return type defaults to `int'
+n8.c:222: warning: return type defaults to `int'
+n8.c:274: warning: return type defaults to `int'
+n8.c:282: warning: return type defaults to `int'
+n8.c: In function `digram':
+n8.c:310: warning: `maxw' might be used uninitialized in this function
+n8.c: At top level:
+n8.c:346: warning: return type defaults to `int'
+n8.c: In function `readpats':
+n8.c:469: warning: implicit declaration of function `unsharp'
+n8.c:469: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
+n8.c:470: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
+9c -c -DUNICODE n9.c
+n9.c:80: warning: return type defaults to `int'
+n9.c: In function `setfield':
+n9.c:340: warning: `rchar' might be used uninitialized in this function
+9c -c -DUNICODE -DTDEVNAME="utf" t10.c
+t10.c: In function `ptout0':
+t10.c:179: warning: int format, long int arg (arg 3)
+t10.c:183: warning: int format, long unsigned int arg (arg 3)
+t10.c:303: warning: int format, long int arg (arg 3)
+t10.c:157: warning: `w' might be used uninitialized in this function
+9c -c -DUNICODE -DTDEVNAME="utf" n10.c
+n10.c: In function `getnrfont':
+n10.c:77: warning: unused variable `fin'
+n10.c:81: warning: unused variable `cmd'
+n10.c:80: warning: `code' might be used uninitialized in this function
+n10.c: In function `n_ptinit':
+n10.c:189: warning: implicit declaration of function `unsharp'
+n10.c:189: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
+n10.c:142: warning: unused variable `cp'
+9c -c -DUNICODE t11.c
+t11.c:21: warning: return type defaults to `int'
+t11.c: In function `getdesc':
+t11.c:26: warning: implicit declaration of function `unsharp'
+t11.c:26: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
+t11.c: In function `checkfont':
+t11.c:67: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
+t11.c: At top level:
+t11.c:89: warning: return type defaults to `int'
+t11.c: In function `getfont':
+t11.c:100: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
+t11.c:94: warning: `nw' might be used uninitialized in this function
+t11.c:94: warning: `code' might be used uninitialized in this function
+t11.c: At top level:
+t11.c:193: warning: return type defaults to `int'
+t11.c:235: warning: return type defaults to `int'
+9c -c -DUNICODE -DTMACDIR="sys/lib/tmac/tmac." ni.c
+9c -c -DUNICODE hytab.c
+9c -c -DUNICODE suftab.c
+9c -c -DUNICODE -DDWBHOME="#9/" dwbinit.c
+9l -o o.troff n1.o n2.o n3.o n4.o n5.o t6.o n6.o n7.o n8.o n9.o t10.o n10.o t11.o ni.o hytab.o suftab.o dwbinit.o /usr/local/plan9/lib/libbio.a /usr/local/plan9/lib/lib9.a
diff --git a/src/cmd/troff/mkfile b/src/cmd/troff/mkfile
new file mode 100644
index 00000000..c02084e7
--- /dev/null
+++ b/src/cmd/troff/mkfile
@@ -0,0 +1,58 @@
+<$PLAN9/src/mkhdr
+
+TARG=troff
+OFILES=n1.$O\
+ n2.$O\
+ n3.$O\
+ n4.$O\
+ n5.$O\
+ t6.$O\
+ n6.$O\
+ n7.$O\
+ n8.$O\
+ n9.$O\
+ t10.$O\
+ n10.$O\
+ t11.$O\
+ ni.$O\
+ hytab.$O\
+ suftab.$O\
+ dwbinit.$O\
+ mbwc.$O
+
+HFILES=tdef.h\
+ fns.h\
+ ext.h\
+ dwbinit.h\
+
+
+SHORTLIB=bio 9
+<$PLAN9/src/mkone
+CFLAGS=-c -DUNICODE
+
+TMACDIR='"tmac/tmac."'
+FONTDIR='"troff/font"'
+NTERMDIR='"troff/term/tab."'
+ALTHYPHENS='"lib/hyphen.tex"'
+TEXHYPHENS='"#9/lib/hyphen.tex"'
+DWBHOME='"#9/"'
+TDEVNAME='"utf"'
+NDEVNAME='"utf"'
+
+ni.$O: ni.c $HFILES
+ $CC $CFLAGS -DTMACDIR=$TMACDIR ni.c
+
+t10.$O: t10.c $HFILES
+ $CC $CFLAGS -DTDEVNAME=$TDEVNAME t10.c
+
+n1.$O: n1.c $HFILES
+ $CC $CFLAGS -DFONTDIR=$FONTDIR -DNTERMDIR=$NTERMDIR -DTEXHYPHENS=$TEXHYPHENS -DALTHYPHENS=$ALTHYPHENS -DDWBHOME=$DWBHOME n1.c
+
+n10.$O: n10.c $HFILES
+ $CC $CFLAGS -DTDEVNAME=$NDEVNAME n10.c
+
+n8.$O: n8.c $HFILES
+ $CC $CFLAGS -DTEXHYPHENS=$TEXHYPHENS n8.c
+
+dwbinit.$O: dwbinit.c
+ $CC $CFLAGS -DDWBHOME=$DWBHOME dwbinit.c
diff --git a/src/cmd/troff/n1.c b/src/cmd/troff/n1.c
new file mode 100644
index 00000000..d0949fe2
--- /dev/null
+++ b/src/cmd/troff/n1.c
@@ -0,0 +1,1136 @@
+/*
+ * n1.c
+ *
+ * consume options, initialization, main loop,
+ * input routines, escape function calling
+ */
+
+#include "tdef.h"
+#include "fns.h"
+#include "ext.h"
+#include "dwbinit.h"
+
+#undef MB_CUR_MAX
+#define MB_CUR_MAX 3
+
+#include <setjmp.h>
+#include <time.h>
+
+char *Version = "March 11, 1994";
+
+#ifndef DWBVERSION
+#define DWBVERSION "???"
+#endif
+
+char *DWBfontdir = FONTDIR;
+char *DWBntermdir = NTERMDIR;
+char *DWBalthyphens = ALTHYPHENS;
+char *DWBhomedir = "";
+
+dwbinit dwbpaths[] = {
+ &DWBfontdir, NULL, 0,
+ &DWBntermdir, NULL, 0,
+ &DWBalthyphens, NULL, 0,
+ &DWBhomedir, NULL, 0,
+ NULL, nextf, NS,
+ NULL, NULL, 0
+};
+
+int TROFF = 1; /* assume we started in troff... */
+
+jmp_buf sjbuf;
+Offset ipl[NSO];
+
+static FILE *ifile;
+static FILE *ifl[NSO]; /* open input file pointers */
+char cfname[NSO+1][NS] = { "stdin" }; /* file name stack */
+int cfline[NSO]; /* input line count stack */
+char *progname; /* program name (troff or nroff) */
+
+int trace = 0; /* tracing mode: default off */
+int trace1 = 0;
+
+main(int argc, char *argv[])
+{
+ char *p;
+ int j;
+ Tchar i;
+ char buf[100];
+
+ ifile = stdin;
+ ptid = stdout;
+
+ buf[0] = '\0'; /* make sure it's empty (silly 3b2) */
+ progname = argv[0];
+ if ((p = strrchr(progname, '/')) == NULL)
+ p = progname;
+ else
+ p++;
+ DWBinit(progname, dwbpaths);
+ if (strcmp(p, "nroff") == 0)
+ TROFF = 0;
+#ifdef UNICODE
+ alphabet = 128; /* unicode for plan 9 */
+#endif /*UNICODE*/
+ mnspace();
+ nnspace();
+ mrehash();
+ nrehash();
+ numtabp[NL].val = -1;
+
+ while (--argc > 0 && (++argv)[0][0] == '-')
+ switch (argv[0][1]) {
+
+ case 'N': /* ought to be used first... */
+ TROFF = 0;
+ break;
+ case 'd':
+ fprintf(stderr, "troff/nroff version %s\n", Version);
+ break;
+ case 'F': /* switch font tables from default */
+ if (argv[0][2] != '\0') {
+ strcpy(termtab, &argv[0][2]);
+ strcpy(fontdir, &argv[0][2]);
+ } else {
+ argv++; argc--;
+ strcpy(termtab, argv[0]);
+ strcpy(fontdir, argv[0]);
+ }
+ break;
+ case 0:
+ goto start;
+ case 'i':
+ stdi++;
+ break;
+ case 'n':
+ npn = atoi(&argv[0][2]);
+ break;
+ case 'u': /* set emboldening amount */
+ bdtab[3] = atoi(&argv[0][2]);
+ if (bdtab[3] < 0 || bdtab[3] > 50)
+ bdtab[3] = 0;
+ break;
+ case 's':
+ if (!(stop = atoi(&argv[0][2])))
+ stop++;
+ break;
+ case 'r':
+ sprintf(buf + strlen(buf), ".nr %c %s\n",
+ argv[0][2], &argv[0][3]);
+ /* not yet cpushback(buf);*/
+ /* dotnr(&argv[0][2], &argv[0][3]); */
+ break;
+ case 'm':
+ if (mflg++ >= NMF) {
+ ERROR "Too many macro packages: %s", argv[0] WARN;
+ break;
+ }
+ strcpy(mfiles[nmfi], nextf);
+ strcat(mfiles[nmfi++], &argv[0][2]);
+ break;
+ case 'o':
+ getpn(&argv[0][2]);
+ break;
+ case 'T':
+ strcpy(devname, &argv[0][2]);
+ dotT++;
+ break;
+ case 'a':
+ ascii = 1;
+ break;
+ case 'h':
+ hflg++;
+ break;
+ case 'e':
+ eqflg++;
+ break;
+ case 'q':
+ quiet++;
+ save_tty();
+ break;
+ case 'V':
+ fprintf(stdout, "%croff: DWB %s\n",
+ TROFF ? 't' : 'n', DWBVERSION);
+ exit(0);
+ case 't':
+ if (argv[0][2] != '\0')
+ trace = trace1 = argv[0][2];
+ break; /* for the sake of compatibility */
+ default:
+ ERROR "unknown option %s", argv[0] WARN;
+ done(02);
+ }
+
+start:
+ /*
+ * cpushback maintains a LIFO, so push pack the -r arguments
+ * in reverse order to maintain a FIFO in case someone did -rC1 -rC3
+ */
+ if (buf[0]) {
+ char *p = buf;
+ while(*p++)
+ ;
+ while(p > buf) {
+ while(strncmp(p, ".nr", 3) != 0)
+ p--;
+ cpushback(p);
+ *p-- = '\0';
+ }
+ }
+ argp = argv;
+ rargc = argc;
+ nmfi = 0;
+ init2();
+ setjmp(sjbuf);
+loop:
+ copyf = lgf = nb = nflush = nlflg = 0;
+ if (ip && rbf0(ip) == 0 && ejf && frame->pframe <= ejl && dip == d) {
+ nflush++;
+ trap = 0;
+ eject((Stack *)0);
+ goto loop;
+ }
+ i = getch();
+ if (pendt)
+ goto Lt;
+ if ((j = cbits(i)) == XPAR) {
+ copyf++;
+ tflg++;
+ while (cbits(i) != '\n')
+ pchar(i = getch());
+ tflg = 0;
+ copyf--;
+ goto loop;
+ }
+ if (j == cc || j == c2) {
+ if (j == c2)
+ nb++;
+ copyf++;
+ while ((j = cbits(i = getch())) == ' ' || j == '\t')
+ ;
+ ch = i;
+ copyf--;
+ control(getrq(), 1);
+ flushi();
+ goto loop;
+ }
+Lt:
+ ch = i;
+ text();
+ if (nlflg)
+ numtabp[HP].val = 0;
+ goto loop;
+}
+
+
+
+void init2(void)
+{
+ int i;
+ char buf[100];
+
+ for (i = NTRTAB; --i; )
+ trtab[i] = i;
+ trtab[UNPAD] = ' ';
+ iflg = 0;
+ obufp = obuf;
+ if (TROFF)
+ t_ptinit();
+ else
+ n_ptinit();
+ mchbits();
+ cvtime();
+ numtabp[PID].val = getpid();
+ numtabp[HP].val = init = 0;
+ numtabp[NL].val = -1;
+ nfo = 0;
+ copyf = raw = 0;
+ sprintf(buf, ".ds .T %s\n", devname);
+ cpushback(buf);
+ sprintf(buf, ".ds .P %s\n", DWBhomedir);
+ cpushback(buf);
+ numtabp[CD].val = -1; /* compensation */
+ nx = mflg;
+ frame = stk = (Stack *)setbrk(STACKSIZE);
+ dip = &d[0];
+ nxf = frame + 1;
+ for (i = 1; i < NEV; i++) /* propagate the environment */
+ envcopy(&env[i], &env[0]);
+ for (i = 0; i < NEV; i++) {
+ if ((env[i]._word._bufp = (Tchar *)calloc(WDSIZE, sizeof(Tchar))) == NULL) {
+ ERROR "not enough room for word buffers" WARN;
+ done2(1);
+ }
+ env[i]._word._size = WDSIZE;
+ if ((env[i]._line._bufp = (Tchar *)calloc(LNSIZE, sizeof(Tchar))) == NULL) {
+ ERROR "not enough room for line buffers" WARN;
+ done2(1);
+ }
+ env[i]._line._size = LNSIZE;
+ }
+ if ((oline = (Tchar *)calloc(OLNSIZE, sizeof(Tchar))) == NULL) {
+ ERROR "not enough room for line buffers" WARN;
+ done2(1);
+ }
+ olinep = oline;
+ olnsize = OLNSIZE;
+ blockinit();
+}
+
+void cvtime(void)
+{
+ long tt;
+ struct tm *ltime;
+
+ time(&tt);
+ ltime = localtime(&tt);
+ numtabp[YR].val = ltime->tm_year % 100;
+ numtabp[YR].fmt = 2;
+ numtabp[MO].val = ltime->tm_mon + 1; /* troff uses 1..12 */
+ numtabp[DY].val = ltime->tm_mday;
+ numtabp[DW].val = ltime->tm_wday + 1; /* troff uses 1..7 */
+}
+
+
+
+char errbuf[200];
+
+void errprint(void) /* error message printer */
+{
+ int savecd = numtabp[CD].val;
+
+ if (!nlflg)
+ numtabp[CD].val++;
+
+ fprintf(stderr, "%s: ", progname);
+ fputs(errbuf, stderr);
+ if (cfname[ifi][0])
+ fprintf(stderr, "; %s:%d", cfname[ifi], numtabp[CD].val);
+ fputs("\n", stderr);
+ if (cfname[ifi][0])
+ stackdump();
+ numtabp[CD].val = savecd;
+}
+
+
+int control(int a, int b)
+{
+ int j, k;
+ extern Contab *contabp;
+
+ numerr.type = RQERR;
+ numerr.req = a;
+ if (a == 0 || (j = findmn(a)) == -1)
+ return(0);
+ if (contabp[j].f == 0) {
+ if (trace & TRMAC)
+ fprintf(stderr, "invoke macro %s\n", unpair(a));
+ if (dip != d)
+ for (k = dilev; k; k--)
+ if (d[k].curd == a) {
+ ERROR "diversion %s invokes itself during diversion",
+ unpair(a) WARN;
+ edone(0100);
+ }
+ nxf->nargs = 0;
+ if (b)
+ collect();
+ flushi();
+ return pushi(contabp[j].mx, a); /* BUG??? all that matters is 0/!0 */
+ }
+ if (b) {
+ if (trace & TRREQ)
+ fprintf(stderr, "invoke request %s\n", unpair(a));
+ (*contabp[j].f)();
+ }
+ return(0);
+}
+
+void casept(void)
+{
+ int i;
+
+ noscale++;
+ if (skip())
+ i = trace1;
+ else {
+ i = max(inumb(&trace), 0);
+ if (nonumb)
+ i = trace1;
+ }
+ trace1 = trace;
+ trace = i;
+ noscale = 0;
+}
+
+
+int getrq(void)
+{
+ int i, j;
+
+ if ((i = getach()) == 0 || (j = getach()) == 0)
+ goto rtn;
+ i = PAIR(i, j);
+rtn:
+ return(i);
+}
+
+/*
+ * table encodes some special characters, to speed up tests
+ * in getch, viz FLSS, RPT, f, \b, \n, fc, tabch, ldrch
+ */
+
+char gchtab[NCHARS] = {
+ 000,004,000,000,010,000,000,000, /* fc, ldr */
+ 001,002,001,000,001,000,000,000, /* \b, tab, nl, RPT */
+ 000,000,000,000,000,000,000,000,
+ 000,001,000,001,000,000,000,000, /* FLSS, ESC */
+ 000,000,000,000,000,000,000,000,
+ 000,000,000,000,000,000,000,000,
+ 000,000,000,000,000,000,000,000,
+ 000,000,000,000,000,000,000,000,
+ 000,000,000,000,000,000,000,000,
+ 000,000,000,000,000,000,000,000,
+ 000,000,000,000,000,000,000,000,
+ 000,000,000,000,000,000,000,000,
+ 000,000,000,000,000,000,001,000, /* f */
+ 000,000,000,000,000,000,000,000,
+ 000,000,000,000,000,000,000,000,
+ 000,000,000,000,000,000,000,000,
+};
+
+int realcbits(Tchar c) /* return character bits, or MOTCH if motion */
+{
+ if (ismot(c))
+ return MOTCH;
+ else
+ return c & 0xFFFF;
+}
+
+Tchar getch(void)
+{
+ int k;
+ Tchar i, j;
+
+g0:
+ if (ch) {
+ i = ch;
+ if (cbits(i) == '\n')
+ nlflg++;
+ ch = 0;
+ return(i);
+ }
+
+ if (nlflg)
+ return('\n');
+ i = getch0();
+ if (ismot(i))
+ return(i);
+ k = cbits(i);
+ if (k >= sizeof(gchtab)/sizeof(gchtab[0]) || gchtab[k] == 0) /* nothing special */
+ return(i);
+ if (k != ESC) {
+ if (k == '\n') {
+ nlflg++;
+ if (ip == 0)
+ numtabp[CD].val++; /* line number */
+ return(k);
+ }
+ if (k == FLSS) {
+ copyf++;
+ raw++;
+ i = getch0();
+ if (!fi)
+ flss = i;
+ copyf--;
+ raw--;
+ goto g0;
+ }
+ if (k == RPT) {
+ setrpt();
+ goto g0;
+ }
+ if (!copyf) {
+ if (k == 'f' && lg && !lgf) {
+ i = getlg(i);
+ return(i);
+ }
+ if (k == fc || k == tabch || k == ldrch) {
+ if ((i = setfield(k)) == 0)
+ goto g0;
+ else
+ return(i);
+ }
+ if (k == '\b') {
+ i = makem(-width(' ' | chbits));
+ return(i);
+ }
+ }
+ return(i);
+ }
+
+ k = cbits(j = getch0());
+ if (ismot(j))
+ return(j);
+
+ switch (k) {
+ case 'n': /* number register */
+ setn();
+ goto g0;
+ case '$': /* argument indicator */
+ seta();
+ goto g0;
+ case '*': /* string indicator */
+ setstr();
+ goto g0;
+ case '{': /* LEFT */
+ i = LEFT;
+ goto gx;
+ case '}': /* RIGHT */
+ i = RIGHT;
+ goto gx;
+ case '"': /* comment */
+ while (cbits(i = getch0()) != '\n')
+ ;
+ if (ip == 0)
+ numtabp[CD].val++; /* line number */
+ nlflg++;
+ return(i);
+
+/* experiment: put it here instead of copy mode */
+ case '(': /* special char name \(xx */
+ case 'C': /* \C'...' */
+ if ((i = setch(k)) == 0)
+ goto g0;
+ goto gx;
+
+ case ESC: /* double backslash */
+ i = eschar;
+ goto gx;
+ case 'e': /* printable version of current eschar */
+ i = PRESC;
+ goto gx;
+ case '\n': /* concealed newline */
+ numtabp[CD].val++;
+ goto g0;
+ case ' ': /* unpaddable space */
+ i = UNPAD;
+ goto gx;
+ case '\'': /* \(aa */
+ i = ACUTE;
+ goto gx;
+ case '`': /* \(ga */
+ i = GRAVE;
+ goto gx;
+ case '_': /* \(ul */
+ i = UNDERLINE;
+ goto gx;
+ case '-': /* current font minus */
+ i = MINUS;
+ goto gx;
+ case '&': /* filler */
+ i = FILLER;
+ goto gx;
+ case 'c': /* to be continued */
+ i = CONT;
+ goto gx;
+ case '!': /* transparent indicator */
+ i = XPAR;
+ goto gx;
+ case 't': /* tab */
+ i = '\t';
+ return(i);
+ case 'a': /* leader (SOH) */
+/* old: *pbp++ = LEADER; goto g0; */
+ i = LEADER;
+ return i;
+ case '%': /* ohc */
+ i = OHC;
+ return(i);
+ case 'g': /* return format of a number register */
+ setaf(); /* should this really be in copy mode??? */
+ goto g0;
+ case '.': /* . */
+ i = '.';
+gx:
+ setsfbits(i, sfbits(j));
+ return(i);
+ }
+ if (copyf) {
+ *pbp++ = j;
+ return(eschar);
+ }
+ switch (k) {
+
+ case 'f': /* font indicator */
+ setfont(0);
+ goto g0;
+ case 's': /* size indicator */
+ setps();
+ goto g0;
+ case 'v': /* vert mot */
+ numerr.type = numerr.escarg = 0; numerr.esc = k;
+ if (i = vmot()) {
+ return(i);
+ }
+ goto g0;
+ case 'h': /* horiz mot */
+ numerr.type = numerr.escarg = 0; numerr.esc = k;
+ if (i = hmot())
+ return(i);
+ goto g0;
+ case '|': /* narrow space */
+ if (NROFF)
+ goto g0;
+ return(makem((int)(EM)/6));
+ case '^': /* half narrow space */
+ if (NROFF)
+ goto g0;
+ return(makem((int)(EM)/12));
+ case 'w': /* width function */
+ setwd();
+ goto g0;
+ case 'p': /* spread */
+ spread++;
+ goto g0;
+ case 'N': /* absolute character number */
+ numerr.type = numerr.escarg = 0; numerr.esc = k;
+ if ((i = setabs()) == 0)
+ goto g0;
+ return i;
+ case 'H': /* character height */
+ numerr.type = numerr.escarg = 0; numerr.esc = k;
+ return(setht());
+ case 'S': /* slant */
+ numerr.type = numerr.escarg = 0; numerr.esc = k;
+ return(setslant());
+ case 'z': /* zero with char */
+ return(setz());
+ case 'l': /* hor line */
+ numerr.type = numerr.escarg = 0; numerr.esc = k;
+ setline();
+ goto g0;
+ case 'L': /* vert line */
+ numerr.type = numerr.escarg = 0; numerr.esc = k;
+ setvline();
+ goto g0;
+ case 'D': /* drawing function */
+ numerr.type = numerr.escarg = 0; numerr.esc = k;
+ setdraw();
+ goto g0;
+ case 'X': /* \X'...' for copy through */
+ setxon();
+ goto g0;
+ case 'b': /* bracket */
+ setbra();
+ goto g0;
+ case 'o': /* overstrike */
+ setov();
+ goto g0;
+ case 'k': /* mark hor place */
+ if ((k = findr(getsn())) != -1) {
+ numtabp[k].val = numtabp[HP].val;
+ }
+ goto g0;
+ case '0': /* number space */
+ return(makem(width('0' | chbits)));
+ case 'x': /* extra line space */
+ numerr.type = numerr.escarg = 0; numerr.esc = k;
+ if (i = xlss())
+ return(i);
+ goto g0;
+ case 'u': /* half em up */
+ case 'r': /* full em up */
+ case 'd': /* half em down */
+ return(sethl(k));
+ default:
+ return(j);
+ }
+ /* NOTREACHED */
+}
+
+void setxon(void) /* \X'...' for copy through */
+{
+ Tchar xbuf[NC];
+ Tchar *i;
+ Tchar c;
+ int delim, k;
+
+ if (ismot(c = getch()))
+ return;
+ delim = cbits(c);
+ i = xbuf;
+ *i++ = XON | chbits;
+ while ((k = cbits(c = getch())) != delim && k != '\n' && i < xbuf+NC-1) {
+ if (k == ' ')
+ setcbits(c, WORDSP);
+ *i++ = c | ZBIT;
+ }
+ *i++ = XOFF | chbits;
+ *i = 0;
+ pushback(xbuf);
+}
+
+
+char ifilt[32] = { 0, 001, 002, 003, 0, 005, 006, 007, 010, 011, 012 };
+
+Tchar getch0(void)
+{
+ int j;
+ Tchar i;
+
+again:
+ if (pbp > lastpbp)
+ i = *--pbp;
+ else if (ip) {
+ /* i = rbf(); */
+ i = rbf0(ip);
+ if (i == 0)
+ i = rbf();
+ else {
+ ++ip;
+ if (pastend(ip)) {
+ --ip;
+ rbf();
+ }
+ }
+ } else {
+ if (donef || ndone)
+ done(0);
+ if (nx || 1) { /* BUG: was ibufp >= eibuf, so EOF test is wrong */
+ if (nfo < 0)
+ ERROR "in getch0, nfo = %d", nfo WARN;
+ if (nfo == 0) {
+g0:
+ if (nextfile()) {
+ if (ip)
+ goto again;
+ }
+ }
+ nx = 0;
+#ifdef UNICODE
+ if (MB_CUR_MAX > 1)
+ i = get1ch(ifile);
+ else
+#endif /*UNICODE*/
+ i = getc(ifile);
+ if (i == EOF)
+ goto g0;
+ if (ip)
+ goto again;
+ }
+g2:
+ if (i >= 040) /* zapped: && i < 0177 */
+ goto g4;
+ i = ifilt[i];
+ }
+ if (cbits(i) == IMP && !raw)
+ goto again;
+ if (i == 0 && !init && !raw) { /* zapped: || i == 0177 */
+ goto again;
+ }
+g4:
+ if (ismot(i))
+ return i;
+ if (copyf == 0 && sfbits(i) == 0)
+ i |= chbits;
+ if (cbits(i) == eschar && !raw)
+ setcbits(i, ESC);
+ return(i);
+}
+
+
+#ifdef UNICODE
+Tchar get1ch(FILE *fp) /* get one "character" from input, figure out what alphabet */
+{
+ wchar_t wc;
+ char buf[100], *p;
+ int i, n, c;
+
+ for (i = 0, p = buf; i < MB_CUR_MAX; i++) {
+ if ((c = getc(fp)) == EOF)
+ return c;
+ *p++ = c;
+ if ((n = mbtowc(&wc, buf, p-buf)) >= 0)
+ break;
+ }
+ if (n == 1) /* real ascii, presumably */
+ return wc;
+ if (n == 0)
+ return p[-1]; /* illegal, but what else to do? */
+ if (c == EOF)
+ return EOF;
+ *p = 0;
+ return chadd(buf, MBchar, Install); /* add name even if haven't seen it */
+}
+#endif /*UNICODE*/
+
+void pushback(Tchar *b)
+{
+ Tchar *ob = b;
+
+ while (*b++)
+ ;
+ b--;
+ while (b > ob && pbp < &pbbuf[NC-3])
+ *pbp++ = *--b;
+ if (pbp >= &pbbuf[NC-3]) {
+ ERROR "pushback overflow" WARN;
+ done(2);
+ }
+}
+
+void cpushback(char *b)
+{
+ char *ob = b;
+
+ while (*b++)
+ ;
+ b--;
+ while (b > ob && pbp < &pbbuf[NC-3])
+ *pbp++ = *--b;
+ if (pbp >= &pbbuf[NC-3]) {
+ ERROR "cpushback overflow" WARN;
+ done(2);
+ }
+}
+
+int nextfile(void)
+{
+ char *p;
+
+n0:
+ if (ifile != stdin)
+ fclose(ifile);
+ if (ifi > 0 && !nx) {
+ if (popf())
+ goto n0; /* popf error */
+ return(1); /* popf ok */
+ }
+ if (nx || nmfi < mflg) {
+ p = mfiles[nmfi++];
+ if (*p != 0)
+ goto n1;
+ }
+ if (rargc-- <= 0) {
+ if ((nfo -= mflg) && !stdi) {
+ done(0);
+}
+ nfo++;
+ numtabp[CD].val = stdi = mflg = 0;
+ ifile = stdin;
+ strcpy(cfname[ifi], "stdin");
+ return(0);
+ }
+ p = (argp++)[0];
+ if (rargc >= 0)
+ cfname[ifi][0] = 0;
+n1:
+ numtabp[CD].val = 0;
+ if (p[0] == '-' && p[1] == 0) {
+ ifile = stdin;
+ strcpy(cfname[ifi], "stdin");
+ } else if ((ifile = fopen(unsharp(p), "r")) == NULL) {
+ ERROR "cannot open file %s", p WARN;
+ nfo -= mflg;
+ done(02);
+ } else
+ strcpy(cfname[ifi],p);
+ nfo++;
+ return(0);
+}
+
+
+popf(void)
+{
+ --ifi;
+ if (ifi < 0) {
+ ERROR "popf went negative" WARN;
+ return 1;
+ }
+ numtabp[CD].val = cfline[ifi]; /* restore line counter */
+ ip = ipl[ifi]; /* input pointer */
+ ifile = ifl[ifi]; /* input FILE * */
+ return(0);
+}
+
+
+void flushi(void)
+{
+ if (nflush)
+ return;
+ ch = 0;
+ copyf++;
+ while (!nlflg) {
+ if (donef && frame == stk)
+ break;
+ getch();
+ }
+ copyf--;
+}
+
+/*
+ * return 16-bit, ascii/alphabetic character, ignore chars with more bits,
+ * (internal names), spaces and special cookies (below 040).
+ * Leave STX ETX ENQ ACK and BELL in to maintain compatibility with v7 troff.
+ */
+getach(void)
+{
+ Tchar i;
+ int j;
+
+ lgf++;
+ j = cbits(i = getch());
+ if (ismot(i)
+ || j > SHORTMASK
+ || (j <= 040 && j != 002 /*STX*/
+ && j != 003 /*ETX*/
+ && j != 005 /*ENQ*/
+ && j != 006 /*ACK*/
+ && j != 007)) { /*BELL*/
+ ch = i;
+ j = 0;
+ }
+ lgf--;
+ return j;
+}
+
+
+void casenx(void)
+{
+ lgf++;
+ skip();
+ getname();
+ nx++;
+ if (nmfi > 0)
+ nmfi--;
+ strcpy(mfiles[nmfi], nextf);
+ nextfile();
+ nlflg++;
+ ip = 0;
+ pendt = 0;
+ frame = stk;
+ nxf = frame + 1;
+}
+
+
+getname(void)
+{
+ int j, k;
+ Tchar i;
+
+ lgf++;
+ for (k = 0; k < NS - 1; k++) {
+ j = getach();
+ if (!j)
+ break;
+ nextf[k] = j;
+ }
+ nextf[k] = 0;
+ lgf--;
+ return(nextf[0]);
+}
+
+
+void caseso(void)
+{
+ FILE *fp;
+ char *p, *q;
+
+ lgf++;
+ nextf[0] = 0;
+ if (skip() || !getname() || (fp = fopen(unsharp(nextf), "r")) == NULL || ifi >= NSO) {
+ ERROR "can't open file %s", nextf WARN;
+ done(02);
+ }
+ strcpy(cfname[ifi+1], nextf);
+ cfline[ifi] = numtabp[CD].val; /*hold line counter*/
+ numtabp[CD].val = 0;
+ flushi();
+ ifl[ifi] = ifile;
+ ifile = fp;
+ ipl[ifi] = ip;
+ ip = 0;
+ nx++;
+ nflush++;
+ ifi++;
+}
+
+void caself(void) /* set line number and file */
+{
+ int n;
+
+ if (skip())
+ return;
+ n = atoi0();
+ if (!nonumb)
+ cfline[ifi] = numtabp[CD].val = n - 1;
+ if (!skip())
+ if (getname()) { /* eats '\n' ? */
+ strcpy(cfname[ifi], nextf);
+ if (!nonumb)
+ numtabp[CD].val--;
+ }
+}
+
+void cpout(FILE *fin, char *token)
+{
+ int n;
+ char buf[1024];
+
+ if (token) { /* BUG: There should be no NULL bytes in input */
+ char *newl = buf;
+ while ((fgets(buf, sizeof buf, fin)) != NULL) {
+ if (newl) {
+ numtabp[CD].val++; /* line number */
+ if (strcmp(token, buf) == 0)
+ return;
+ }
+ newl = strchr(buf, '\n');
+ fputs(buf, ptid);
+ }
+ } else {
+ while ((n = fread(buf, sizeof *buf, sizeof buf, fin)) > 0)
+ fwrite(buf, n, 1, ptid);
+ fclose(fin);
+ }
+}
+
+void casecf(void)
+{ /* copy file without change */
+ FILE *fd;
+ char *eof, *p;
+ extern int hpos, esc, po;
+
+ /* this may not make much sense in nroff... */
+
+ lgf++;
+ nextf[0] = 0;
+ if (!skip() && getname()) {
+ if (strncmp("<<", nextf, 2) != 0) {
+ if ((fd = fopen(unsharp(nextf), "r")) == NULL) {
+ ERROR "can't open file %s", nextf WARN;
+ done(02);
+ }
+ eof = (char *) NULL;
+ } else { /* current file */
+ if (pbp > lastpbp || ip) {
+ ERROR "casecf: not reading from file" WARN;
+ done(02);
+ }
+ eof = &nextf[2];
+ if (!*eof) {
+ ERROR "casecf: missing end of input token" WARN;
+ done(02);
+ }
+ p = eof;
+ while(*++p)
+ ;
+ *p++ = '\n';
+ *p = 0;
+ fd = ifile;
+ }
+ } else {
+ ERROR "casecf: no argument" WARN;
+ lgf--;
+ return;
+ }
+ lgf--;
+
+ /* make it into a clean state, be sure that everything is out */
+ tbreak();
+ hpos = po;
+ esc = 0;
+ ptesc(); /* to left margin */
+ esc = un;
+ ptesc();
+ ptlead();
+ ptps();
+ ptfont();
+ flusho();
+ cpout(fd, eof);
+ ptps();
+ ptfont();
+}
+
+void getline(char *s, int n) /* get rest of input line into s */
+{
+ int i;
+
+ lgf++;
+ copyf++;
+ skip();
+ for (i = 0; i < n-1; i++)
+ if ((s[i] = cbits(getch())) == '\n' || s[i] == RIGHT)
+ break;
+ s[i] = 0;
+ copyf--;
+ lgf--;
+}
+
+void casesy(void) /* call system */
+{
+ char sybuf[NTM];
+
+ getline(sybuf, NTM);
+ system(sybuf);
+}
+
+
+void getpn(char *a)
+{
+ int n, neg;
+
+ if (*a == 0)
+ return;
+ neg = 0;
+ for ( ; *a; a++)
+ switch (*a) {
+ case '+':
+ case ',':
+ continue;
+ case '-':
+ neg = 1;
+ continue;
+ default:
+ n = 0;
+ if (isdigit(*a)) {
+ do
+ n = 10 * n + *a++ - '0';
+ while (isdigit(*a));
+ a--;
+ } else
+ n = 9999;
+ *pnp++ = neg ? -n : n;
+ neg = 0;
+ if (pnp >= &pnlist[NPN-2]) {
+ ERROR "too many page numbers" WARN;
+ done3(-3);
+ }
+ }
+ if (neg)
+ *pnp++ = -9999;
+ *pnp = -INT_MAX;
+ print = 0;
+ pnp = pnlist;
+ if (*pnp != -INT_MAX)
+ chkpn();
+}
+
+
+void setrpt(void)
+{
+ Tchar i, j;
+
+ copyf++;
+ raw++;
+ i = getch0();
+ copyf--;
+ raw--;
+ if ((long) i < 0 || cbits(j = getch0()) == RPT)
+ return;
+ while (i > 0 && pbp < &pbbuf[NC-3]) {
+ i--;
+ *pbp++ = j;
+ }
+}
diff --git a/src/cmd/troff/n10.c b/src/cmd/troff/n10.c
new file mode 100644
index 00000000..0183cadc
--- /dev/null
+++ b/src/cmd/troff/n10.c
@@ -0,0 +1,549 @@
+/*
+n10.c
+
+Device interfaces
+*/
+
+#include "tdef.h"
+#include "ext.h"
+#include "fns.h"
+#include <ctype.h>
+
+Term t; /* terminal characteristics */
+
+int dtab;
+int plotmode;
+int esct;
+
+enum { Notype = 0, Type = 1 };
+
+static char *parse(char *s, int typeit) /* convert \0, etc to nroff driving table format */
+{ /* typeit => add a type id to the front for later use */
+ static char buf[100], *t, *obuf;
+ int quote = 0;
+ wchar_t wc;
+
+ obuf = typeit == Type ? buf : buf+1;
+#ifdef UNICODE
+ if (mbtowc(&wc, s, strlen(s)) > 1) { /* it's multibyte, */
+ buf[0] = MBchar;
+ strcpy(buf+1, s);
+ return obuf;
+ } /* so just hand it back */
+#endif /*UNICODE*/
+ buf[0] = Troffchar;
+ t = buf + 1;
+ if (*s == '"') {
+ s++;
+ quote = 1;
+ }
+ for (;;) {
+ if (quote && *s == '"') {
+ s++;
+ break;
+ }
+ if (!quote && (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\0'))
+ break;
+ if (*s != '\\')
+ *t++ = *s++;
+ else {
+ s++; /* skip \\ */
+ if (isdigit(s[0]) && isdigit(s[1]) && isdigit(s[2])) {
+ *t++ = (s[0]-'0')<<6 | (s[1]-'0')<<3 | s[2]-'0';
+ s += 2;
+ } else if (isdigit(s[0])) {
+ *t++ = *s - '0';
+ } else if (*s == 'b') {
+ *t++ = '\b';
+ } else if (*s == 'n') {
+ *t++ = '\n';
+ } else if (*s == 'r') {
+ *t++ = '\r';
+ } else if (*s == 't') {
+ *t++ = '\t';
+ } else {
+ *t++ = *s;
+ }
+ s++;
+ }
+ }
+ *t = '\0';
+ return obuf;
+}
+
+
+static int getnrfont(FILE *fp) /* read the nroff description file */
+{
+ FILE *fin;
+ Chwid chtemp[NCHARS];
+ static Chwid chinit;
+ int i, nw, n, wid, code, type;
+ char buf[100], ch[100], s1[100], s2[100], cmd[300];
+ wchar_t wc;
+
+
+ chinit.wid = 1;
+ chinit.str = "";
+ for (i = 0; i < ALPHABET; i++) {
+ chtemp[i] = chinit; /* zero out to begin with */
+ chtemp[i].num = chtemp[i].code = i; /* every alphabetic character is itself */
+ chtemp[i].wid = 1; /* default ascii widths */
+ }
+ skipline(fp);
+ nw = ALPHABET;
+ while (fgets(buf, sizeof buf, fp) != NULL) {
+ sscanf(buf, "%s %s %[^\n]", ch, s1, s2);
+ if (!eq(s1, "\"")) { /* genuine new character */
+ sscanf(s1, "%d", &wid);
+ } /* else it's a synonym for prev character, */
+ /* so leave previous values intact */
+
+ /* decide what kind of alphabet it might come from */
+
+ if (strlen(ch) == 1) { /* it's ascii */
+ n = ch[0]; /* origin includes non-graphics */
+ chtemp[n].num = ch[0];
+ } else if (ch[0] == '\\' && ch[1] == '0') {
+ n = strtol(ch+1, 0, 0); /* \0octal or \0xhex */
+ chtemp[n].num = n;
+#ifdef UNICODE
+ } else if (mbtowc(&wc, ch, strlen(ch)) > 1) {
+ chtemp[nw].num = chadd(ch, MBchar, Install);
+ n = nw;
+ nw++;
+#endif /*UNICODE*/
+ } else {
+ if (strcmp(ch, "---") == 0) { /* no name */
+ sprintf(ch, "%d", code);
+ type = Number;
+ } else
+ type = Troffchar;
+/* BUG in here somewhere when same character occurs twice in table */
+ chtemp[nw].num = chadd(ch, type, Install);
+ n = nw;
+ nw++;
+ }
+ chtemp[n].wid = wid;
+ chtemp[n].str = strdupl(parse(s2, Type));
+ }
+ t.tfont.nchars = nw;
+ t.tfont.wp = (Chwid *) malloc(nw * sizeof(Chwid));
+ if (t.tfont.wp == NULL)
+ return -1;
+ for (i = 0; i < nw; i++)
+ t.tfont.wp[i] = chtemp[i];
+ return 1;
+}
+
+
+void n_ptinit(void)
+{
+ int i;
+ char *p, *cp;
+ char opt[50], cmd[100];
+ FILE *fp;
+
+ hmot = n_hmot;
+ makem = n_makem;
+ setabs = n_setabs;
+ setch = n_setch;
+ sethl = n_sethl;
+ setht = n_setht;
+ setslant = n_setslant;
+ vmot = n_vmot;
+ xlss = n_xlss;
+ findft = n_findft;
+ width = n_width;
+ mchbits = n_mchbits;
+ ptlead = n_ptlead;
+ ptout = n_ptout;
+ ptpause = n_ptpause;
+ setfont = n_setfont;
+ setps = n_setps;
+ setwd = n_setwd;
+
+ if ((p = getenv("NROFFTERM")) != 0)
+ strcpy(devname, p);
+ if (termtab[0] == 0)
+ strcpy(termtab,DWBntermdir);
+ if (fontdir[0] == 0)
+ strcpy(fontdir, "");
+ if (devname[0] == 0)
+ strcpy(devname, NDEVNAME);
+ pl = 11*INCH;
+ po = PO;
+ hyf = 0;
+ ascii = 1;
+ lg = 0;
+ fontlab[1] = 'R';
+ fontlab[2] = 'I';
+ fontlab[3] = 'B';
+ fontlab[4] = PAIR('B','I');
+ fontlab[5] = 'D';
+ bdtab[3] = 3;
+ bdtab[4] = 3;
+
+ /* hyphalg = 0; /* for testing */
+
+ strcat(termtab, devname);
+ if ((fp = fopen(unsharp(termtab), "r")) == NULL) {
+ ERROR "cannot open %s", termtab WARN;
+ exit(-1);
+ }
+
+
+/* this loop isn't robust about input format errors. */
+/* it assumes name, name-value pairs..., charset */
+/* god help us if we get out of sync. */
+
+ fscanf(fp, "%s", cmd); /* should be device name... */
+ if (!is(devname) && trace)
+ ERROR "wrong terminal name: saw %s, wanted %s", cmd, devname WARN;
+ for (;;) {
+ fscanf(fp, "%s", cmd);
+ if (is("charset"))
+ break;
+ fscanf(fp, " %[^\n]", opt);
+ if (is("bset")) t.bset = atoi(opt);
+ else if (is("breset")) t.breset = atoi(opt);
+ else if (is("Hor")) t.Hor = atoi(opt);
+ else if (is("Vert")) t.Vert = atoi(opt);
+ else if (is("Newline")) t.Newline = atoi(opt);
+ else if (is("Char")) t.Char = atoi(opt);
+ else if (is("Em")) t.Em = atoi(opt);
+ else if (is("Halfline")) t.Halfline = atoi(opt);
+ else if (is("Adj")) t.Adj = atoi(opt);
+ else if (is("twinit")) t.twinit = strdupl(parse(opt, Notype));
+ else if (is("twrest")) t.twrest = strdupl(parse(opt, Notype));
+ else if (is("twnl")) t.twnl = strdupl(parse(opt, Notype));
+ else if (is("hlr")) t.hlr = strdupl(parse(opt, Notype));
+ else if (is("hlf")) t.hlf = strdupl(parse(opt, Notype));
+ else if (is("flr")) t.flr = strdupl(parse(opt, Notype));
+ else if (is("bdon")) t.bdon = strdupl(parse(opt, Notype));
+ else if (is("bdoff")) t.bdoff = strdupl(parse(opt, Notype));
+ else if (is("iton")) t.iton = strdupl(parse(opt, Notype));
+ else if (is("itoff")) t.itoff = strdupl(parse(opt, Notype));
+ else if (is("ploton")) t.ploton = strdupl(parse(opt, Notype));
+ else if (is("plotoff")) t.plotoff = strdupl(parse(opt, Notype));
+ else if (is("up")) t.up = strdupl(parse(opt, Notype));
+ else if (is("down")) t.down = strdupl(parse(opt, Notype));
+ else if (is("right")) t.right = strdupl(parse(opt, Notype));
+ else if (is("left")) t.left = strdupl(parse(opt, Notype));
+ else
+ ERROR "bad tab.%s file, %s %s", devname, cmd, opt WARN;
+ }
+
+ getnrfont(fp);
+ fclose(fp);
+
+ sps = EM;
+ ics = EM * 2;
+ dtab = 8 * t.Em;
+ for (i = 0; i < 16; i++)
+ tabtab[i] = dtab * (i + 1);
+ pl = 11 * INCH;
+ po = PO;
+ spacesz = SS;
+ lss = lss1 = VS;
+ ll = ll1 = lt = lt1 = LL;
+ smnt = nfonts = 5; /* R I B BI S */
+ n_specnames(); /* install names like "hyphen", etc. */
+ if (eqflg)
+ t.Adj = t.Hor;
+}
+
+
+void n_specnames(void)
+{
+
+ int i;
+
+ for (i = 0; spnames[i].n; i++)
+ *spnames[i].n = chadd(spnames[i].v, Troffchar, Install);
+ if (c_isalnum == 0)
+ c_isalnum = NROFFCHARS;
+}
+
+void twdone(void)
+{
+ if (!TROFF && t.twrest) {
+ obufp = obuf;
+ oputs(t.twrest);
+ flusho();
+ if (pipeflg) {
+ pclose(ptid);
+ }
+ restore_tty();
+ }
+}
+
+
+void n_ptout(Tchar i)
+{
+ *olinep++ = i;
+ if (olinep >= &oline[LNSIZE])
+ olinep--;
+ if (cbits(i) != '\n')
+ return;
+ olinep--;
+ lead += dip->blss + lss - t.Newline;
+ dip->blss = 0;
+ esct = esc = 0;
+ if (olinep > oline) {
+ move();
+ ptout1();
+ oputs(t.twnl);
+ } else {
+ lead += t.Newline;
+ move();
+ }
+ lead += dip->alss;
+ dip->alss = 0;
+ olinep = oline;
+}
+
+
+void ptout1(void)
+{
+ int k;
+ char *codep;
+ int w, j, phyw;
+ Tchar *q, i;
+ static int oxfont = FT; /* start off in roman */
+
+ for (q = oline; q < olinep; q++) {
+ i = *q;
+ if (ismot(i)) {
+ j = absmot(i);
+ if (isnmot(i))
+ j = -j;
+ if (isvmot(i))
+ lead += j;
+ else
+ esc += j;
+ continue;
+ }
+ if ((k = cbits(i)) <= ' ') {
+ switch (k) {
+ case ' ': /*space*/
+ esc += t.Char;
+ break;
+ case '\033':
+ case '\007':
+ case '\016':
+ case '\017':
+ oput(k);
+ break;
+ }
+ continue;
+ }
+ phyw = w = t.Char * t.tfont.wp[k].wid;
+ if (iszbit(i))
+ w = 0;
+ if (esc || lead)
+ move();
+ esct += w;
+ xfont = fbits(i);
+ if (xfont != oxfont) {
+ switch (oxfont) {
+ case ULFONT: oputs(t.itoff); break;
+ case BDFONT: oputs(t.bdoff); break;
+ case BIFONT: oputs(t.itoff); oputs(t.bdoff); break;
+ }
+ switch (xfont) {
+ case ULFONT:
+ if (*t.iton & 0377) oputs(t.iton); break;
+ case BDFONT:
+ if (*t.bdon & 0377) oputs(t.bdon); break;
+ case BIFONT:
+ if (*t.bdon & 0377) oputs(t.bdon);
+ if (*t.iton & 0377) oputs(t.iton);
+ break;
+ }
+ oxfont = xfont;
+ }
+ if ((xfont == ulfont || xfont == BIFONT) && !(*t.iton & 0377)) {
+ for (j = w / t.Char; j > 0; j--)
+ oput('_');
+ for (j = w / t.Char; j > 0; j--)
+ oput('\b');
+ }
+ if (!(*t.bdon & 0377) && ((j = bdtab[xfont]) || xfont == BDFONT || xfont == BIFONT))
+ j++;
+ else
+ j = 1; /* number of overstrikes for bold */
+ if (k < ALPHABET) { /* ordinary ascii */
+ oput(k);
+ while (--j > 0) {
+ oput('\b');
+ oput(k);
+ }
+ } else if (k >= t.tfont.nchars) { /* BUG -- not really understood */
+/* fprintf(stderr, "big char %d, name %s\n", k, chname(k)); /* */
+ oputs(chname(k)+1); /* BUG: should separate Troffchar and MBchar... */
+ } else if (t.tfont.wp[k].str == 0) {
+/* fprintf(stderr, "nostr char %d, name %s\n", k, chname(k)); /* */
+ oputs(chname(k)+1); /* BUG: should separate Troffchar and MBchar... */
+ } else if (t.tfont.wp[k].str[0] == MBchar) { /* parse() puts this on */
+/* fprintf(stderr, "MBstr char %d, name %s\n", k, chname(k)); /* */
+ oputs(t.tfont.wp[k].str+1);
+ } else {
+ int oj = j;
+/* fprintf(stderr, "str char %d, name %s\n", k, chname(k)); /* */
+ codep = t.tfont.wp[k].str+1; /* Troffchar by default */
+ while (*codep != 0) {
+ if (*codep & 0200) {
+ codep = plot(codep);
+ oput(' ');
+ } else {
+ if (*codep == '%') /* escape */
+ codep++;
+ oput(*codep);
+ if (*codep == '\033')
+ oput(*++codep);
+ else if (*codep != '\b')
+ for (j = oj; --j > 0; ) {
+ oput('\b');
+ oput(*codep);
+ }
+ codep++;
+ }
+ }
+ }
+ if (!w)
+ for (j = phyw / t.Char; j > 0; j--)
+ oput('\b');
+ }
+}
+
+
+char *plot(char *x)
+{
+ int i;
+ char *j, *k;
+
+ oputs(t.ploton);
+ k = x;
+ if ((*k & 0377) == 0200)
+ k++;
+ for (; *k; k++) {
+ if (*k == '%') { /* quote char within plot mode */
+ oput(*++k);
+ } else if (*k & 0200) {
+ if (*k & 0100) {
+ if (*k & 040)
+ j = t.up;
+ else
+ j = t.down;
+ } else {
+ if (*k & 040)
+ j = t.left;
+ else
+ j = t.right;
+ }
+ if ((i = *k & 037) == 0) { /* 2nd 0200 turns it off */
+ ++k;
+ break;
+ }
+ while (i--)
+ oputs(j);
+ } else
+ oput(*k);
+ }
+ oputs(t.plotoff);
+ return(k);
+}
+
+
+void move(void)
+{
+ int k;
+ char *i, *j;
+ char *p, *q;
+ int iesct, dt;
+
+ iesct = esct;
+ if (esct += esc)
+ i = "\0";
+ else
+ i = "\n\0";
+ j = t.hlf;
+ p = t.right;
+ q = t.down;
+ if (lead) {
+ if (lead < 0) {
+ lead = -lead;
+ i = t.flr;
+ /* if(!esct)i = t.flr; else i = "\0";*/
+ j = t.hlr;
+ q = t.up;
+ }
+ if (*i & 0377) {
+ k = lead / t.Newline;
+ lead = lead % t.Newline;
+ while (k--)
+ oputs(i);
+ }
+ if (*j & 0377) {
+ k = lead / t.Halfline;
+ lead = lead % t.Halfline;
+ while (k--)
+ oputs(j);
+ } else { /* no half-line forward, not at line begining */
+ k = lead / t.Newline;
+ lead = lead % t.Newline;
+ if (k > 0)
+ esc = esct;
+ i = "\n";
+ while (k--)
+ oputs(i);
+ }
+ }
+ if (esc) {
+ if (esc < 0) {
+ esc = -esc;
+ j = "\b";
+ p = t.left;
+ } else {
+ j = " ";
+ if (hflg)
+ while ((dt = dtab - (iesct % dtab)) <= esc) {
+ if (dt % t.Em)
+ break;
+ oput(TAB);
+ esc -= dt;
+ iesct += dt;
+ }
+ }
+ k = esc / t.Em;
+ esc = esc % t.Em;
+ while (k--)
+ oputs(j);
+ }
+ if ((*t.ploton & 0377) && (esc || lead)) {
+ oputs(t.ploton);
+ esc /= t.Hor;
+ lead /= t.Vert;
+ while (esc--)
+ oputs(p);
+ while (lead--)
+ oputs(q);
+ oputs(t.plotoff);
+ }
+ esc = lead = 0;
+}
+
+
+void n_ptlead(void)
+{
+ move();
+}
+
+
+void n_ptpause(void )
+{
+ char junk;
+
+ flusho();
+ read(2, &junk, 1);
+}
diff --git a/src/cmd/troff/n2.c b/src/cmd/troff/n2.c
new file mode 100644
index 00000000..8164c038
--- /dev/null
+++ b/src/cmd/troff/n2.c
@@ -0,0 +1,325 @@
+/*
+ * n2.c
+ *
+ * output, cleanup
+ */
+
+#include "tdef.h"
+#include "fns.h"
+#include "ext.h"
+#include <setjmp.h>
+
+#ifdef STRICT
+ /* not in ANSI or POSIX */
+FILE* popen(char*, char*);
+#endif
+
+
+extern jmp_buf sjbuf;
+int toolate;
+int error;
+
+char obuf[2*BUFSIZ];
+char *obufp = obuf;
+
+ /* pipe command structure; allows redicously long commends for .pi */
+struct Pipe {
+ char *buf;
+ int tick;
+ int cnt;
+} Pipe;
+
+
+int xon = 0; /* records if in middle of \X */
+
+int pchar(Tchar i)
+{
+ int j;
+ static int hx = 0; /* records if have seen HX */
+
+ if (hx) {
+ hx = 0;
+ j = absmot(i);
+ if (isnmot(i)) {
+ if (j > dip->blss)
+ dip->blss = j;
+ } else {
+ if (j > dip->alss)
+ dip->alss = j;
+ ralss = dip->alss;
+ }
+ return 0;
+ }
+ if (ismot(i)) {
+ pchar1(i);
+ return 0;
+ }
+ switch (j = cbits(i)) {
+ case 0:
+ case IMP:
+ case RIGHT:
+ case LEFT:
+ return 0;
+ case HX:
+ hx = 1;
+ return 0;
+ case XON:
+ xon++;
+ break;
+ case XOFF:
+ xon--;
+ break;
+ case PRESC:
+ if (!xon && !tflg && dip == &d[0])
+ j = eschar; /* fall through */
+ default:
+ setcbits(i, trtab[j]);
+ }
+ if (NROFF & xon) /* rob fix for man2html */
+ return 0;
+ pchar1(i);
+ return 0;
+}
+
+
+void pchar1(Tchar i)
+{
+ int j;
+
+ j = cbits(i);
+ if (dip != &d[0]) {
+ wbf(i);
+ dip->op = offset;
+ return;
+ }
+ if (!tflg && !print) {
+ if (j == '\n')
+ dip->alss = dip->blss = 0;
+ return;
+ }
+ if (j == FILLER && !xon)
+ return;
+ if (tflg) { /* transparent mode, undiverted */
+ if (print) /* assumes that it's ok to print */
+ /* OUT "%c", j PUT; /* i.e., is ascii */
+ outascii(i);
+ return;
+ }
+ if (TROFF && ascii)
+ outascii(i);
+ else
+ ptout(i);
+}
+
+
+void outweird(int k) /* like ptchname() but ascii */
+{
+ char *chn = chname(k);
+
+ switch (chn[0]) {
+ case MBchar:
+ OUT "%s", chn+1 PUT; /* \n not needed? */
+ break;
+ case Number:
+ OUT "\\N'%s'", chn+1 PUT;
+ break;
+ case Troffchar:
+ if (strlen(chn+1) == 2)
+ OUT "\\(%s", chn+1 PUT;
+ else
+ OUT "\\C'%s'", chn+1 PUT;
+ break;
+ default:
+ OUT " %s? ", chn PUT;
+ break;
+ }
+}
+
+void outascii(Tchar i) /* print i in best-guess ascii */
+{
+ char *p;
+ int j = cbits(i);
+
+/* is this ever called with NROFF set? probably doesn't work at all. */
+
+ if (ismot(i))
+ oput(' ');
+ else if (j < ALPHABET && j >= ' ' || j == '\n' || j == '\t')
+ oput(j);
+ else if (j == DRAWFCN)
+ oputs("\\D");
+ else if (j == HYPHEN)
+ oput('-');
+ else if (j == MINUS) /* special pleading for strange encodings */
+ oputs("\\-");
+ else if (j == PRESC)
+ oputs("\\e");
+ else if (j == FILLER)
+ oputs("\\&");
+ else if (j == UNPAD)
+ oputs("\\ ");
+ else if (j == OHC) /* this will never occur; stripped out earlier */
+ oputs("\\%");
+ else if (j == XON)
+ oputs("\\X");
+ else if (j == XOFF)
+ oputs(" ");
+ else if (j == LIG_FI)
+ oputs("fi");
+ else if (j == LIG_FL)
+ oputs("fl");
+ else if (j == LIG_FF)
+ oputs("ff");
+ else if (j == LIG_FFI)
+ oputs("ffi");
+ else if (j == LIG_FFL)
+ oputs("ffl");
+ else if (j == WORDSP) { /* nothing at all */
+ if (xon) /* except in \X */
+ oput(' ');
+
+ } else
+ outweird(j);
+}
+
+int flusho(void)
+{
+ if (NROFF && !toolate && t.twinit)
+ fwrite(t.twinit, strlen(t.twinit), 1, ptid);
+
+ if (obufp > obuf) {
+ if (pipeflg && !toolate) {
+ /* fprintf(stderr, "Pipe to <%s>\n", Pipe.buf); */
+ if (!Pipe.buf[0] || (ptid = popen(Pipe.buf, "w")) == NULL)
+ ERROR "pipe %s not created.", Pipe.buf WARN;
+ if (Pipe.buf)
+ free(Pipe.buf);
+ }
+ if (!toolate)
+ toolate++;
+ *obufp = 0;
+ fputs(obuf, ptid);
+ fflush(ptid);
+ obufp = obuf;
+ }
+ return 1;
+}
+
+
+void caseex(void)
+{
+ done(0);
+}
+
+
+void done(int x)
+{
+ int i;
+
+ error |= x;
+ app = ds = lgf = 0;
+ if (i = em) {
+ donef = -1;
+ eschar = '\\';
+ em = 0;
+ if (control(i, 0))
+ longjmp(sjbuf, 1);
+ }
+ if (!nfo)
+ done3(0);
+ mflg = 0;
+ dip = &d[0];
+ if (woff) /* BUG!!! This isn't set anywhere */
+ wbf((Tchar)0);
+ if (pendw)
+ getword(1);
+ pendnf = 0;
+ if (donef == 1)
+ done1(0);
+ donef = 1;
+ ip = 0;
+ frame = stk;
+ nxf = frame + 1;
+ if (!ejf)
+ tbreak();
+ nflush++;
+ eject((Stack *)0);
+ longjmp(sjbuf, 1);
+}
+
+
+void done1(int x)
+{
+ error |= x;
+ if (numtabp[NL].val) {
+ trap = 0;
+ eject((Stack *)0);
+ longjmp(sjbuf, 1);
+ }
+ if (!ascii)
+ pttrailer();
+ done2(0);
+}
+
+
+void done2(int x)
+{
+ ptlead();
+ if (TROFF && !ascii)
+ ptstop();
+ flusho();
+ done3(x);
+}
+
+void done3(int x)
+{
+ error |= x;
+ flusho();
+ if (NROFF)
+ twdone();
+ if (pipeflg)
+ pclose(ptid);
+ exit(error);
+}
+
+
+void edone(int x)
+{
+ frame = stk;
+ nxf = frame + 1;
+ ip = 0;
+ done(x);
+}
+
+
+void casepi(void)
+{
+ int j;
+ char buf[NTM];
+
+ if (Pipe.buf == NULL) {
+ if ((Pipe.buf = (char *)calloc(NTM, sizeof(char))) == NULL) {
+ ERROR "No buf space for pipe cmd" WARN;
+ return;
+ }
+ Pipe.tick = 1;
+ } else
+ Pipe.buf[Pipe.cnt++] = '|';
+
+ getline(buf, NTM);
+ j = strlen(buf);
+ if (toolate) {
+ ERROR "Cannot create pipe to %s", buf WARN;
+ return;
+ }
+ Pipe.cnt += j;
+ if (j >= NTM +1) {
+ Pipe.tick++;
+ if ((Pipe.buf = (char *)realloc(Pipe.buf, Pipe.tick * NTM * sizeof(char))) == NULL) {
+ ERROR "No more buf space for pipe cmd" WARN;
+ return;
+ }
+ }
+ strcat(Pipe.buf, buf);
+ pipeflg++;
+}
diff --git a/src/cmd/troff/n3.c b/src/cmd/troff/n3.c
new file mode 100644
index 00000000..6918d06d
--- /dev/null
+++ b/src/cmd/troff/n3.c
@@ -0,0 +1,954 @@
+/*
+ * troff3.c
+ *
+ * macro and string routines, storage allocation
+ */
+
+#include "tdef.h"
+#include "fns.h"
+#include "ext.h"
+
+Tchar *argtop;
+int pagech = '%';
+int strflg;
+
+#define MHASHSIZE 128 /* must be 2**n */
+#define MHASH(x) ((x>>6)^x) & (MHASHSIZE-1)
+Contab *mhash[MHASHSIZE];
+
+
+Blockp *blist; /* allocated blocks for macros and strings */
+int nblist; /* how many there are */
+int bfree = -1; /* first (possible) free block in the list */
+
+Contab *contabp = NULL;
+#define MDELTA 500
+int nm = 0;
+
+int savname; /* name of macro/string being defined */
+int savslot; /* place in Contab of savname */
+int freeslot = -1; /* first (possible) free slot in contab */
+
+void prcontab(Contab *p)
+{
+ int i;
+ for (i = 0; i < nm; i++)
+ if (p)
+ if (p[i].rq != 0)
+ fprintf(stderr, "slot %d, %-2.2s\n", i, unpair(p[i].rq));
+ else
+ fprintf(stderr, "slot %d empty\n", i);
+ else
+ fprintf(stderr, "slot %d empty\n", i);
+}
+
+
+void blockinit(void)
+{
+ blist = (Blockp *) calloc(NBLIST, sizeof(Blockp));
+ if (blist == NULL) {
+ ERROR "not enough room for %d blocks", NBLIST WARN;
+ done2(1);
+ }
+ nblist = NBLIST;
+ blist[0].nextoff = blist[1].nextoff = -1;
+ blist[0].bp = (Tchar *) calloc(BLK, sizeof(Tchar));
+ blist[1].bp = (Tchar *) calloc(BLK, sizeof(Tchar));
+ /* -1 prevents blist[0] from being used; temporary fix */
+ /* for a design botch: offset==0 is overloaded. */
+ /* blist[1] reserved for .rd indicator -- also unused. */
+ /* but someone unwittingly looks at these, so allocate something */
+ bfree = 2;
+}
+
+
+char *grow(char *ptr, int num, int size) /* make array bigger */
+{
+ char *p, new;
+
+ if (ptr == NULL)
+ p = (char *) calloc(num, size);
+ else
+ p = (char *) realloc(ptr, num * size);
+ return p;
+}
+
+void mnspace(void)
+{
+ nm = sizeof(contab)/sizeof(Contab) + MDELTA;
+ freeslot = sizeof(contab)/sizeof(Contab) + 1;
+ contabp = (Contab *) grow((char *) contabp, nm, sizeof(Contab));
+ if (contabp == NULL) {
+ ERROR "not enough memory for namespace of %d marcos", nm WARN;
+ exit(1);
+ }
+ contabp = (Contab *) memcpy((char *) contabp, (char *)contab,
+ sizeof(contab));
+ if (contabp == NULL) {
+ ERROR "Cannot reinitialize macro/request name list" WARN;
+ exit(1);
+ }
+
+}
+
+void caseig(void)
+{
+ int i;
+ Offset oldoff = offset;
+
+ offset = 0;
+ i = copyb();
+ offset = oldoff;
+ if (i != '.')
+ control(i, 1);
+}
+
+
+void casern(void)
+{
+ int i, j, k;
+
+ lgf++;
+ skip();
+ if ((i = getrq()) == 0 || (oldmn = findmn(i)) < 0)
+ return;
+ skip();
+ clrmn(findmn(j = getrq()));
+ if (j) {
+ munhash(&contabp[oldmn]);
+ contabp[oldmn].rq = j;
+ maddhash(&contabp[oldmn]);
+ if (dip != d )
+ for (k = dilev; k; k--)
+ if (d[k].curd == i)
+ d[k].curd = j;
+ }
+}
+
+void maddhash(Contab *rp)
+{
+ Contab **hp;
+
+ if (rp->rq == 0)
+ return;
+ hp = &mhash[MHASH(rp->rq)];
+ rp->link = *hp;
+ *hp = rp;
+}
+
+void munhash(Contab *mp)
+{
+ Contab *p;
+ Contab **lp;
+
+ if (mp->rq == 0)
+ return;
+ lp = &mhash[MHASH(mp->rq)];
+ p = *lp;
+ while (p) {
+ if (p == mp) {
+ *lp = p->link;
+ p->link = 0;
+ return;
+ }
+ lp = &p->link;
+ p = p->link;
+ }
+}
+
+void mrehash(void)
+{
+ Contab *p;
+ int i;
+
+ for (i=0; i < MHASHSIZE; i++)
+ mhash[i] = 0;
+ for (p=contabp; p < &contabp[nm]; p++)
+ p->link = 0;
+ for (p=contabp; p < &contabp[nm]; p++) {
+ if (p->rq == 0)
+ continue;
+ i = MHASH(p->rq);
+ p->link = mhash[i];
+ mhash[i] = p;
+ }
+}
+
+void caserm(void)
+{
+ int j;
+ int k = 0;
+
+ lgf++;
+g0:
+ while (!skip() && (j = getrq()) != 0) {
+ if (dip != d)
+ for (k = dilev; k; k--)
+ if (d[k].curd == j) {
+ ERROR "cannot remove diversion %s during definition",
+ unpair(j) WARN;
+ goto g0;
+ }
+ clrmn(findmn(j));
+ }
+ lgf--;
+}
+
+
+void caseas(void)
+{
+ app++;
+ caseds();
+}
+
+
+void caseds(void)
+{
+ ds++;
+ casede();
+}
+
+
+void caseam(void)
+{
+ app++;
+ casede();
+}
+
+
+void casede(void)
+{
+ int i, req;
+ Offset savoff;
+
+ req = '.';
+ lgf++;
+ skip();
+ if ((i = getrq()) == 0)
+ goto de1;
+ if ((offset = finds(i)) == 0)
+ goto de1;
+ if (newmn)
+ savslot = newmn;
+ else
+ savslot = findmn(i);
+ savname = i;
+ if (ds)
+ copys();
+ else
+ req = copyb();
+ clrmn(oldmn);
+ if (newmn) {
+ if (contabp[newmn].rq)
+ munhash(&contabp[newmn]);
+ contabp[newmn].rq = i;
+ maddhash(&contabp[newmn]);
+
+ }
+ if (apptr) {
+ savoff = offset;
+ offset = apptr;
+ wbf((Tchar) IMP);
+ offset = savoff;
+ }
+ offset = dip->op;
+ if (req != '.')
+ control(req, 1);
+de1:
+ ds = app = 0;
+}
+
+
+int findmn(int i)
+{
+ Contab *p;
+
+ for (p = mhash[MHASH(i)]; p; p = p->link)
+ if (i == p->rq)
+ return(p - contabp);
+ return(-1);
+}
+
+
+void clrmn(int i)
+{
+ if (i >= 0) {
+ if (contabp[i].mx)
+ ffree(contabp[i].mx);
+ munhash(&contabp[i]);
+ contabp[i].rq = 0;
+ contabp[i].mx = 0;
+ contabp[i].emx = 0;
+ contabp[i].f = 0;
+ if (contabp[i].divsiz != NULL) {
+ free(contabp[i].divsiz);
+ contabp[i].divsiz = NULL;
+ }
+ if (freeslot > i)
+ freeslot = i;
+ }
+}
+
+void growcontab(void)
+{
+ nm += MDELTA;
+ contabp = (Contab *) grow((char *) contabp , nm, sizeof(Contab));
+ if (contabp == NULL) {
+ ERROR "Too many (%d) string/macro names", nm WARN;
+ done2(02);
+ } else {
+ memset((char *)(contabp) + (nm - MDELTA) * sizeof(Contab),
+ 0, MDELTA * sizeof(Contab));
+ mrehash();
+ }
+}
+
+
+Offset finds(int mn)
+{
+ int i;
+ Tchar j = IMP;
+ Offset savip;
+
+ oldmn = findmn(mn);
+ newmn = 0;
+ apptr = 0;
+ if (app && oldmn >= 0 && contabp[oldmn].mx) {
+ savip = ip;
+ ip = contabp[oldmn].emx;
+ oldmn = -1;
+ apptr = ip;
+ if (!diflg)
+ ip = incoff(ip);
+ nextb = ip;
+ ip = savip;
+ } else {
+ for (i = freeslot; i < nm; i++) {
+ if (contabp[i].rq == 0)
+ break;
+ }
+ if (i == nm)
+ growcontab();
+ freeslot = i + 1;
+ if ((nextb = alloc()) == -1) {
+ app = 0;
+ if (macerr++ > 1)
+ done2(02);
+ if (nextb == 0)
+ ERROR "Not enough space for string/macro names" WARN;
+ edone(04);
+ return(offset = 0);
+ }
+ contabp[i].mx = nextb;
+ if (!diflg) {
+ newmn = i;
+ if (oldmn == -1)
+ contabp[i].rq = -1;
+ } else {
+ contabp[i].rq = mn;
+ maddhash(&contabp[i]);
+ }
+ }
+ app = 0;
+ return(offset = nextb);
+}
+
+int skip(void)
+{
+ Tchar i;
+
+ while (cbits(i = getch()) == ' ' || ismot(i))
+ ;
+ ch = i;
+ return(nlflg);
+}
+
+
+int copyb(void)
+{
+ int i, j, state;
+ Tchar ii;
+ int req, k;
+ Offset savoff;
+ Uchar *p;
+
+ if (skip() || !(j = getrq()))
+ j = '.';
+ req = j;
+ p = unpair(j);
+ /* was: k = j >> BYTE; j &= BYTEMASK; */
+ j = p[0];
+ k = p[1];
+ copyf++;
+ flushi();
+ nlflg = 0;
+ state = 1;
+
+/* state 0 eat up
+ * state 1 look for .
+ * state 2 look for first char of end macro
+ * state 3 look for second char of end macro
+ */
+
+ while (1) {
+ i = cbits(ii = getch());
+ if (state == 3) {
+ if (i == k)
+ break;
+ if (!k) {
+ ch = ii;
+ i = getach();
+ ch = ii;
+ if (!i)
+ break;
+ }
+ state = 0;
+ goto c0;
+ }
+ if (i == '\n') {
+ state = 1;
+ nlflg = 0;
+ goto c0;
+ }
+ if (state == 1 && i == '.') {
+ state++;
+ savoff = offset;
+ goto c0;
+ }
+ if (state == 2 && i == j) {
+ state++;
+ goto c0;
+ }
+ state = 0;
+c0:
+ if (offset)
+ wbf(ii);
+ }
+ if (offset) {
+ offset = savoff;
+ wbf((Tchar)0);
+ }
+ copyf--;
+ return(req);
+}
+
+
+void copys(void)
+{
+ Tchar i;
+
+ copyf++;
+ if (skip())
+ goto c0;
+ if (cbits(i = getch()) != '"')
+ wbf(i);
+ while (cbits(i = getch()) != '\n')
+ wbf(i);
+c0:
+ wbf((Tchar)0);
+ copyf--;
+}
+
+
+Offset alloc(void) /* return free Offset in nextb */
+{
+ int i, j;
+
+ for (i = bfree; i < nblist; i++)
+ if (blist[i].nextoff == 0)
+ break;
+ if (i == nblist) {
+ blist = (Blockp *) realloc((char *) blist, 2 * nblist * sizeof(Blockp));
+ if (blist == NULL) {
+ ERROR "can't grow blist for string/macro defns" WARN;
+ done2(2);
+ }
+ nblist *= 2;
+ for (j = i; j < nblist; j++) {
+ blist[j].nextoff = 0;
+ blist[j].bp = 0;
+ }
+ }
+ blist[i].nextoff = -1; /* this block is the end */
+ bfree = i + 1;
+ if (blist[i].bp == 0)
+ blist[i].bp = (Tchar *) calloc(BLK, sizeof(Tchar));
+ if (blist[i].bp == NULL) {
+ ERROR "can't allocate memory for string/macro definitions" WARN;
+ done2(2);
+ }
+ nextb = (Offset) i * BLK;
+ return nextb;
+}
+
+
+void ffree(Offset i) /* free list of blocks starting at blist(o) */
+{ /* (doesn't actually free the blocks, just the pointers) */
+ int j;
+
+ for ( ; blist[j = bindex(i)].nextoff != -1; ) {
+ if (bfree > j)
+ bfree = j;
+ i = blist[j].nextoff;
+ blist[j].nextoff = 0;
+ }
+ blist[j].nextoff = 0;
+}
+
+
+void wbf(Tchar i) /* store i into offset, get ready for next one */
+{
+ int j, off;
+
+ if (!offset)
+ return;
+ j = bindex(offset);
+ if (i == 0)
+ contabp[savslot].emx = offset;
+ off = boffset(offset);
+ blist[j].bp[off++] = i;
+ offset++;
+ if (pastend(offset)) { /* off the end of this block */
+ if (blist[j].nextoff == -1) {
+ if ((nextb = alloc()) == -1) {
+ ERROR "Out of temp file space" WARN;
+ done2(01);
+ }
+ blist[j].nextoff = nextb;
+ }
+ offset = blist[j].nextoff;
+ }
+}
+
+
+Tchar rbf(void) /* return next char from blist[] block */
+{
+ Tchar i, j;
+
+ if (ip == RD_OFFSET) { /* for rdtty */
+ if (j = rdtty())
+ return(j);
+ else
+ return(popi());
+ }
+
+ i = rbf0(ip);
+ if (i == 0) {
+ if (!app)
+ i = popi();
+ return(i);
+ }
+ ip = incoff(ip);
+ return(i);
+}
+
+
+Offset xxxincoff(Offset p) /* get next blist[] block */
+{
+ p++;
+ if (pastend(p)) { /* off the end of this block */
+ if ((p = blist[bindex(p-1)].nextoff) == -1) { /* and nothing was allocated after it */
+ ERROR "Bad storage allocation" WARN;
+ done2(-5);
+ }
+ }
+ return(p);
+}
+
+
+Tchar popi(void)
+{
+ Stack *p;
+
+ if (frame == stk)
+ return(0);
+ if (strflg)
+ strflg--;
+ p = nxf = frame;
+ p->nargs = 0;
+ frame = p->pframe;
+ ip = p->pip;
+ pendt = p->ppendt;
+ lastpbp = p->lastpbp;
+ return(p->pch);
+}
+
+/*
+ * test that the end of the allocation is above a certain location
+ * in memory
+ */
+#define SPACETEST(base, size) \
+ if ((char*)base + size >= (char*)stk+STACKSIZE) \
+ ERROR "Stacksize overflow in n3" WARN
+
+Offset pushi(Offset newip, int mname)
+{
+ Stack *p;
+
+ SPACETEST(nxf, sizeof(Stack));
+ p = nxf;
+ p->pframe = frame;
+ p->pip = ip;
+ p->ppendt = pendt;
+ p->pch = ch;
+ p->lastpbp = lastpbp;
+ p->mname = mname;
+ lastpbp = pbp;
+ pendt = ch = 0;
+ frame = nxf;
+ if (nxf->nargs == 0)
+ nxf += 1;
+ else
+ nxf = (Stack *)argtop;
+ return(ip = newip);
+}
+
+
+void *setbrk(int x)
+{
+ char *i;
+
+ if ((i = (char *) calloc(x, 1)) == 0) {
+ ERROR "Core limit reached" WARN;
+ edone(0100);
+ }
+ return(i);
+}
+
+
+int getsn(void)
+{
+ int i;
+
+ if ((i = getach()) == 0)
+ return(0);
+ if (i == '(')
+ return(getrq());
+ else
+ return(i);
+}
+
+
+Offset setstr(void)
+{
+ int i, j;
+
+ lgf++;
+ if ((i = getsn()) == 0 || (j = findmn(i)) == -1 || !contabp[j].mx) {
+ lgf--;
+ return(0);
+ } else {
+ SPACETEST(nxf, sizeof(Stack));
+ nxf->nargs = 0;
+ strflg++;
+ lgf--;
+ return pushi(contabp[j].mx, i);
+ }
+}
+
+
+
+void collect(void)
+{
+ int j;
+ Tchar i, *strp, *lim, **argpp, **argppend;
+ int quote;
+ Stack *savnxf;
+
+ copyf++;
+ nxf->nargs = 0;
+ savnxf = nxf;
+ if (skip())
+ goto rtn;
+
+ {
+ char *memp;
+ memp = (char *)savnxf;
+ /*
+ * 1 s structure for the macro descriptor
+ * APERMAC Tchar *'s for pointers into the strings
+ * space for the Tchar's themselves
+ */
+ memp += sizeof(Stack);
+ /*
+ * CPERMAC = the total # of characters for ALL arguments
+ */
+#define CPERMAC 200
+#define APERMAC 9
+ memp += APERMAC * sizeof(Tchar *);
+ memp += CPERMAC * sizeof(Tchar);
+ nxf = (Stack *)memp;
+ }
+ lim = (Tchar *)nxf;
+ argpp = (Tchar **)(savnxf + 1);
+ argppend = &argpp[APERMAC];
+ SPACETEST(argppend, sizeof(Tchar *));
+ strp = (Tchar *)argppend;
+ /*
+ * Zero out all the string pointers before filling them in.
+ */
+ for (j = 0; j < APERMAC; j++)
+ argpp[j] = 0;
+ /* ERROR "savnxf=0x%x,nxf=0x%x,argpp=0x%x,strp=argppend=0x%x, lim=0x%x",
+ * savnxf, nxf, argpp, strp, lim WARN;
+ */
+ strflg = 0;
+ while (argpp != argppend && !skip()) {
+ *argpp++ = strp;
+ quote = 0;
+ if (cbits(i = getch()) == '"')
+ quote++;
+ else
+ ch = i;
+ while (1) {
+ i = getch();
+/* fprintf(stderr, "collect %c %d\n", cbits(i), cbits(i)); */
+ if (nlflg || (!quote && argpp != argppend && cbits(i) == ' '))
+ break; /* collects rest into $9 */
+ if ( quote
+ && cbits(i) == '"'
+ && cbits(i = getch()) != '"') {
+ ch = i;
+ break;
+ }
+ *strp++ = i;
+ if (strflg && strp >= lim) {
+ /* ERROR "strp=0x%x, lim = 0x%x", strp, lim WARN; */
+ ERROR "Macro argument too long" WARN;
+ copyf--;
+ edone(004);
+ }
+ SPACETEST(strp, 3 * sizeof(Tchar));
+ }
+ *strp++ = 0;
+ }
+ nxf = savnxf;
+ nxf->nargs = argpp - (Tchar **)(savnxf + 1);
+ argtop = strp;
+rtn:
+ copyf--;
+}
+
+
+void seta(void)
+{
+ int i;
+
+ i = cbits(getch()) - '0';
+ if (i > 0 && i <= APERMAC && i <= frame->nargs)
+ pushback(*(((Tchar **)(frame + 1)) + i - 1));
+}
+
+
+void caseda(void)
+{
+ app++;
+ casedi();
+}
+
+void casegd(void)
+{
+ int i, j;
+
+ skip();
+ if ((i = getrq()) == 0)
+ return;
+ if ((j = findmn(i)) >= 0) {
+ if (contabp[j].divsiz != NULL) {
+ numtabp[DN].val = contabp[j].divsiz->dix;
+ numtabp[DL].val = contabp[j].divsiz->diy;
+ }
+ }
+}
+
+#define FINDDIV(o) if ((o = findmn(dip->curd)) < 0) \
+ ERROR "lost diversion %s", unpair(dip->curd) WARN
+
+void casedi(void)
+{
+ int i, j, *k;
+
+ lgf++;
+ if (skip() || (i = getrq()) == 0) {
+ if (dip != d) {
+ FINDDIV(savslot);
+ wbf((Tchar)0);
+ }
+ if (dilev > 0) {
+ numtabp[DN].val = dip->dnl;
+ numtabp[DL].val = dip->maxl;
+ FINDDIV(j);
+ if ((contabp[j].divsiz = (Divsiz *) malloc(sizeof(Divsiz))) == NULL) {
+ ERROR "Cannot alloc diversion size" WARN;
+ done2(1);
+ } else {
+ contabp[j].divsiz->dix = numtabp[DN].val;
+ contabp[j].divsiz->diy = numtabp[DL].val;
+ }
+ dip = &d[--dilev];
+ offset = dip->op;
+ }
+ goto rtn;
+ }
+ if (++dilev == NDI) {
+ --dilev;
+ ERROR "Diversions nested too deep" WARN;
+ edone(02);
+ }
+ if (dip != d) {
+ FINDDIV(j);
+ savslot = j;
+ wbf((Tchar)0);
+ }
+ diflg++;
+ dip = &d[dilev];
+ dip->op = finds(i);
+ dip->curd = i;
+ clrmn(oldmn);
+ k = (int *) & dip->dnl;
+ for (j = 0; j < 10; j++)
+ k[j] = 0; /*not op and curd*/
+rtn:
+ app = 0;
+ diflg = 0;
+}
+
+
+void casedt(void)
+{
+ lgf++;
+ dip->dimac = dip->ditrap = dip->ditf = 0;
+ skip();
+ dip->ditrap = vnumb((int *)0);
+ if (nonumb)
+ return;
+ skip();
+ dip->dimac = getrq();
+}
+
+#define LNSIZE 4000
+void casetl(void)
+{
+ int j;
+ int w[3];
+ Tchar buf[LNSIZE];
+ Tchar *tp;
+ Tchar i, delim;
+
+ /*
+ * bug fix
+ *
+ * if .tl is the first thing in the file, the p1
+ * doesn't come out, also the pagenumber will be 0
+ *
+ * tends too confuse the device filter (and the user as well)
+ */
+ if (dip == d && numtabp[NL].val == -1)
+ newline(1);
+ dip->nls = 0;
+ skip();
+ if (ismot(delim = getch())) {
+ ch = delim;
+ delim = '\'';
+ } else
+ delim = cbits(delim);
+ tp = buf;
+ numtabp[HP].val = 0;
+ w[0] = w[1] = w[2] = 0;
+ j = 0;
+ while (cbits(i = getch()) != '\n') {
+ if (cbits(i) == cbits(delim)) {
+ if (j < 3)
+ w[j] = numtabp[HP].val;
+ numtabp[HP].val = 0;
+ if (w[j] != 0)
+ *tp++ = WORDSP;
+ j++;
+ *tp++ = 0;
+ } else {
+ if (cbits(i) == pagech) {
+ setn1(numtabp[PN].val, numtabp[findr('%')].fmt,
+ i&SFMASK);
+ continue;
+ }
+ numtabp[HP].val += width(i);
+ if (tp < &buf[LNSIZE-10]) {
+ if (cbits(i) == ' ' && *tp != WORDSP)
+ *tp++ = WORDSP;
+ *tp++ = i;
+ } else {
+ ERROR "Overflow in casetl" WARN;
+ }
+ }
+ }
+ if (j<3)
+ w[j] = numtabp[HP].val;
+ *tp++ = 0;
+ *tp++ = 0;
+ *tp = 0;
+ tp = buf;
+ if (NROFF)
+ horiz(po);
+ while (i = *tp++)
+ pchar(i);
+ if (w[1] || w[2])
+ horiz(j = quant((lt - w[1]) / 2 - w[0], HOR));
+ while (i = *tp++)
+ pchar(i);
+ if (w[2]) {
+ horiz(lt - w[0] - w[1] - w[2] - j);
+ while (i = *tp++)
+ pchar(i);
+ }
+ newline(0);
+ if (dip != d) {
+ if (dip->dnl > dip->hnl)
+ dip->hnl = dip->dnl;
+ } else {
+ if (numtabp[NL].val > dip->hnl)
+ dip->hnl = numtabp[NL].val;
+ }
+}
+
+
+void casepc(void)
+{
+ pagech = chget(IMP);
+}
+
+
+void casepm(void)
+{
+ int i, k;
+ int xx, cnt, tcnt, kk, tot;
+ Offset j;
+
+ kk = cnt = tcnt = 0;
+ tot = !skip();
+ stackdump();
+ for (i = 0; i < nm; i++) {
+ if ((xx = contabp[i].rq) == 0 || contabp[i].mx == 0)
+ continue;
+ tcnt++;
+ j = contabp[i].mx;
+ for (k = 1; (j = blist[bindex(j)].nextoff) != -1; )
+ k++;
+ cnt++;
+ kk += k;
+ if (!tot)
+ fprintf(stderr, "%-2.2s %d\n", unpair(xx), k);
+ }
+ fprintf(stderr, "pm: total %d, macros %d, space %d\n", tcnt, cnt, kk);
+}
+
+void stackdump(void) /* dumps stack of macros in process */
+{
+ Stack *p;
+
+ if (frame != stk) {
+ fprintf(stderr, "stack: ");
+ for (p = frame; p != stk; p = p->pframe)
+ fprintf(stderr, "%s ", unpair(p->mname));
+ fprintf(stderr, "\n");
+ }
+}
diff --git a/src/cmd/troff/n4.c b/src/cmd/troff/n4.c
new file mode 100644
index 00000000..3b3698e4
--- /dev/null
+++ b/src/cmd/troff/n4.c
@@ -0,0 +1,828 @@
+/*
+ * troff4.c
+ *
+ * number registers, conversion, arithmetic
+ */
+
+#include "tdef.h"
+#include "fns.h"
+#include "ext.h"
+
+
+int regcnt = NNAMES;
+int falsef = 0; /* on if inside false branch of if */
+
+#define NHASHSIZE 128 /* must be 2**n */
+#define NHASH(i) ((i>>6)^i) & (NHASHSIZE-1)
+Numtab *nhash[NHASHSIZE];
+
+Numtab *numtabp = NULL;
+#define NDELTA 400
+int ncnt = 0;
+
+void setn(void)
+{
+ int i, j, f;
+ Tchar ii;
+ Uchar *p;
+ char buf[NTM]; /* for \n(.S */
+
+ f = nform = 0;
+ if ((i = cbits(ii = getach())) == '+')
+ f = 1;
+ else if (i == '-')
+ f = -1;
+ else if (ii) /* don't put it back if it's already back (thanks to jaap) */
+ ch = ii;
+ if (falsef)
+ f = 0;
+ if ((i = getsn()) == 0)
+ return;
+ p = unpair(i);
+ if (p[0] == '.')
+ switch (p[1]) {
+ case 's':
+ i = pts;
+ break;
+ case 'v':
+ i = lss;
+ break;
+ case 'f':
+ i = font;
+ break;
+ case 'p':
+ i = pl;
+ break;
+ case 't':
+ i = findt1();
+ break;
+ case 'o':
+ i = po;
+ break;
+ case 'l':
+ i = ll;
+ break;
+ case 'i':
+ i = in;
+ break;
+ case '$':
+ i = frame->nargs;
+ break;
+ case 'A':
+ i = ascii;
+ break;
+ case 'c':
+ i = numtabp[CD].val;
+ break;
+ case 'n':
+ i = lastl;
+ break;
+ case 'a':
+ i = ralss;
+ break;
+ case 'h':
+ i = dip->hnl;
+ break;
+ case 'd':
+ if (dip != d)
+ i = dip->dnl;
+ else
+ i = numtabp[NL].val;
+ break;
+ case 'u':
+ i = fi;
+ break;
+ case 'j':
+ i = ad + 2 * admod;
+ break;
+ case 'w':
+ i = widthp;
+ break;
+ case 'x':
+ i = nel;
+ break;
+ case 'y':
+ i = un;
+ break;
+ case 'T':
+ i = dotT;
+ break; /* -Tterm used in nroff */
+ case 'V':
+ i = VERT;
+ break;
+ case 'H':
+ i = HOR;
+ break;
+ case 'k':
+ i = ne;
+ break;
+ case 'P':
+ i = print;
+ break;
+ case 'L':
+ i = ls;
+ break;
+ case 'R': /* maximal # of regs that can be addressed */
+ i = 255*256 - regcnt;
+ break;
+ case 'z':
+ p = unpair(dip->curd);
+ *pbp++ = p[1]; /* watch order */
+ *pbp++ = p[0];
+ return;
+ case 'b':
+ i = bdtab[font];
+ break;
+ case 'F':
+ cpushback(cfname[ifi]);
+ return;
+ case 'S':
+ buf[0] = j = 0;
+ for( i = 0; tabtab[i] != 0 && i < NTAB; i++) {
+ if (i > 0)
+ buf[j++] = ' ';
+ sprintf(&buf[j], "%d", tabtab[i] & TABMASK);
+ j = strlen(buf);
+ if ( tabtab[i] & RTAB)
+ sprintf(&buf[j], "uR");
+ else if (tabtab[i] & CTAB)
+ sprintf(&buf[j], "uC");
+ else
+ sprintf(&buf[j], "uL");
+ j += 2;
+ }
+ cpushback(buf);
+ return;
+ default:
+ goto s0;
+ }
+ else {
+s0:
+ if ((j = findr(i)) == -1)
+ i = 0;
+ else {
+ i = numtabp[j].val = numtabp[j].val + numtabp[j].inc * f;
+ nform = numtabp[j].fmt;
+ }
+ }
+ setn1(i, nform, (Tchar) 0);
+}
+
+Tchar numbuf[25];
+Tchar *numbufp;
+
+int wrc(Tchar i)
+{
+ if (numbufp >= &numbuf[24])
+ return(0);
+ *numbufp++ = i;
+ return(1);
+}
+
+
+
+/* insert into input number i, in format form, with size-font bits bits */
+void setn1(int i, int form, Tchar bits)
+{
+ numbufp = numbuf;
+ nrbits = bits;
+ nform = form;
+ fnumb(i, wrc);
+ *numbufp = 0;
+ pushback(numbuf);
+}
+
+void prnumtab(Numtab *p)
+{
+ int i;
+ for (i = 0; i < ncnt; i++)
+ if (p)
+ if (p[i].r != 0)
+ fprintf(stderr, "slot %d, %s, val %d\n", i, unpair(p[i].r), p[i].val);
+ else
+ fprintf(stderr, "slot %d empty\n", i);
+ else
+ fprintf(stderr, "slot %d empty\n", i);
+}
+
+void nnspace(void)
+{
+ ncnt = sizeof(numtab)/sizeof(Numtab) + NDELTA;
+ numtabp = (Numtab *) grow((char *)numtabp, ncnt, sizeof(Numtab));
+ if (numtabp == NULL) {
+ ERROR "not enough memory for registers (%d)", ncnt WARN;
+ exit(1);
+ }
+ numtabp = (Numtab *) memcpy((char *)numtabp, (char *)numtab,
+ sizeof(numtab));
+ if (numtabp == NULL) {
+ ERROR "Cannot initialize registers" WARN;
+ exit(1);
+ }
+}
+
+void grownumtab(void)
+{
+ ncnt += NDELTA;
+ numtabp = (Numtab *) grow((char *) numtabp, ncnt, sizeof(Numtab));
+ if (numtabp == NULL) {
+ ERROR "Too many number registers (%d)", ncnt WARN;
+ done2(04);
+ } else {
+ memset((char *)(numtabp) + (ncnt - NDELTA) * sizeof(Numtab),
+ 0, NDELTA * sizeof(Numtab));
+ nrehash();
+ }
+}
+
+void nrehash(void)
+{
+ Numtab *p;
+ int i;
+
+ for (i=0; i<NHASHSIZE; i++)
+ nhash[i] = 0;
+ for (p=numtabp; p < &numtabp[ncnt]; p++)
+ p->link = 0;
+ for (p=numtabp; p < &numtabp[ncnt]; p++) {
+ if (p->r == 0)
+ continue;
+ i = NHASH(p->r);
+ p->link = nhash[i];
+ nhash[i] = p;
+ }
+}
+
+void nunhash(Numtab *rp)
+{
+ Numtab *p;
+ Numtab **lp;
+
+ if (rp->r == 0)
+ return;
+ lp = &nhash[NHASH(rp->r)];
+ p = *lp;
+ while (p) {
+ if (p == rp) {
+ *lp = p->link;
+ p->link = 0;
+ return;
+ }
+ lp = &p->link;
+ p = p->link;
+ }
+}
+
+int findr(int i)
+{
+ Numtab *p;
+ int h = NHASH(i);
+
+ if (i == 0)
+ return(-1);
+a0:
+ for (p = nhash[h]; p; p = p->link)
+ if (i == p->r)
+ return(p - numtabp);
+ for (p = numtabp; p < &numtabp[ncnt]; p++) {
+ if (p->r == 0) {
+ p->r = i;
+ p->link = nhash[h];
+ nhash[h] = p;
+ regcnt++;
+ return(p - numtabp);
+ }
+ }
+ grownumtab();
+ goto a0;
+}
+
+int usedr(int i) /* returns -1 if nr i has never been used */
+{
+ Numtab *p;
+
+ if (i == 0)
+ return(-1);
+ for (p = nhash[NHASH(i)]; p; p = p->link)
+ if (i == p->r)
+ return(p - numtabp);
+ return -1;
+}
+
+
+int fnumb(int i, int (*f)(Tchar))
+{
+ int j;
+
+ j = 0;
+ if (i < 0) {
+ j = (*f)('-' | nrbits);
+ i = -i;
+ }
+ switch (nform) {
+ default:
+ case '1':
+ case 0:
+ return decml(i, f) + j;
+ case 'i':
+ case 'I':
+ return roman(i, f) + j;
+ case 'a':
+ case 'A':
+ return abc(i, f) + j;
+ }
+}
+
+
+int decml(int i, int (*f)(Tchar))
+{
+ int j, k;
+
+ k = 0;
+ nform--;
+ if ((j = i / 10) || (nform > 0))
+ k = decml(j, f);
+ return(k + (*f)((i % 10 + '0') | nrbits));
+}
+
+
+int roman(int i, int (*f)(Tchar))
+{
+
+ if (!i)
+ return((*f)('0' | nrbits));
+ if (nform == 'i')
+ return(roman0(i, f, "ixcmz", "vldw"));
+ else
+ return(roman0(i, f, "IXCMZ", "VLDW"));
+}
+
+
+int roman0(int i, int (*f)(Tchar), char *onesp, char *fivesp)
+{
+ int q, rem, k;
+
+ if (!i)
+ return(0);
+ k = roman0(i / 10, f, onesp + 1, fivesp + 1);
+ q = (i = i % 10) / 5;
+ rem = i % 5;
+ if (rem == 4) {
+ k += (*f)(*onesp | nrbits);
+ if (q)
+ i = *(onesp + 1);
+ else
+ i = *fivesp;
+ return(k += (*f)(i | nrbits));
+ }
+ if (q)
+ k += (*f)(*fivesp | nrbits);
+ while (--rem >= 0)
+ k += (*f)(*onesp | nrbits);
+ return(k);
+}
+
+
+int abc(int i, int (*f)(Tchar))
+{
+ if (!i)
+ return((*f)('0' | nrbits));
+ else
+ return(abc0(i - 1, f));
+}
+
+
+int abc0(int i, int (*f)(Tchar))
+{
+ int j, k;
+
+ k = 0;
+ if (j = i / 26)
+ k = abc0(j - 1, f);
+ return(k + (*f)((i % 26 + nform) | nrbits));
+}
+
+long atoi0(void)
+{
+ int c, k, cnt;
+ Tchar ii;
+ long i, acc;
+
+ acc = 0;
+ nonumb = 0;
+ cnt = -1;
+a0:
+ cnt++;
+ ii = getch();
+ c = cbits(ii);
+ switch (c) {
+ default:
+ ch = ii;
+ if (cnt)
+ break;
+ case '+':
+ i = ckph();
+ if (nonumb)
+ break;
+ acc += i;
+ goto a0;
+ case '-':
+ i = ckph();
+ if (nonumb)
+ break;
+ acc -= i;
+ goto a0;
+ case '*':
+ i = ckph();
+ if (nonumb)
+ break;
+ acc *= i;
+ goto a0;
+ case '/':
+ i = ckph();
+ if (nonumb)
+ break;
+ if (i == 0) {
+ flusho();
+ ERROR "divide by zero." WARN;
+ acc = 0;
+ } else
+ acc /= i;
+ goto a0;
+ case '%':
+ i = ckph();
+ if (nonumb)
+ break;
+ acc %= i;
+ goto a0;
+ case '&': /*and*/
+ i = ckph();
+ if (nonumb)
+ break;
+ if ((acc > 0) && (i > 0))
+ acc = 1;
+ else
+ acc = 0;
+ goto a0;
+ case ':': /*or*/
+ i = ckph();
+ if (nonumb)
+ break;
+ if ((acc > 0) || (i > 0))
+ acc = 1;
+ else
+ acc = 0;
+ goto a0;
+ case '=':
+ if (cbits(ii = getch()) != '=')
+ ch = ii;
+ i = ckph();
+ if (nonumb) {
+ acc = 0;
+ break;
+ }
+ if (i == acc)
+ acc = 1;
+ else
+ acc = 0;
+ goto a0;
+ case '>':
+ k = 0;
+ if (cbits(ii = getch()) == '=')
+ k++;
+ else
+ ch = ii;
+ i = ckph();
+ if (nonumb) {
+ acc = 0;
+ break;
+ }
+ if (acc > (i - k))
+ acc = 1;
+ else
+ acc = 0;
+ goto a0;
+ case '<':
+ k = 0;
+ if (cbits(ii = getch()) == '=')
+ k++;
+ else
+ ch = ii;
+ i = ckph();
+ if (nonumb) {
+ acc = 0;
+ break;
+ }
+ if (acc < (i + k))
+ acc = 1;
+ else
+ acc = 0;
+ goto a0;
+ case ')':
+ break;
+ case '(':
+ acc = atoi0();
+ goto a0;
+ }
+ return(acc);
+}
+
+
+long ckph(void)
+{
+ Tchar i;
+ long j;
+
+ if (cbits(i = getch()) == '(')
+ j = atoi0();
+ else {
+ j = atoi1(i);
+ }
+ return(j);
+}
+
+
+/*
+ * print error about illegal numeric argument;
+ */
+void prnumerr(void)
+{
+ char err_buf[40];
+ static char warn[] = "Numeric argument expected";
+ int savcd = numtabp[CD].val;
+
+ if (numerr.type == RQERR)
+ sprintf(err_buf, "%c%s: %s", nb ? cbits(c2) : cbits(cc),
+ unpair(numerr.req), warn);
+ else
+ sprintf(err_buf, "\\%c'%s': %s", numerr.esc, &numerr.escarg,
+ warn);
+ if (frame != stk) /* uncertainty correction */
+ numtabp[CD].val--;
+ ERROR err_buf WARN;
+ numtabp[CD].val = savcd;
+}
+
+
+long atoi1(Tchar ii)
+{
+ int i, j, digits;
+ double acc; /* this is the only double in troff! */
+ int neg, abs, field, decpnt;
+ extern int ifnum;
+
+
+ neg = abs = field = decpnt = digits = 0;
+ acc = 0;
+ for (;;) {
+ i = cbits(ii);
+ switch (i) {
+ default:
+ break;
+ case '+':
+ ii = getch();
+ continue;
+ case '-':
+ neg = 1;
+ ii = getch();
+ continue;
+ case '|':
+ abs = 1 + neg;
+ neg = 0;
+ ii = getch();
+ continue;
+ }
+ break;
+ }
+a1:
+ while (i >= '0' && i <= '9') {
+ field++;
+ digits++;
+ acc = 10 * acc + i - '0';
+ ii = getch();
+ i = cbits(ii);
+ }
+ if (i == '.' && !decpnt++) {
+ field++;
+ digits = 0;
+ ii = getch();
+ i = cbits(ii);
+ goto a1;
+ }
+ if (!field) {
+ ch = ii;
+ goto a2;
+ }
+ switch (i) {
+ case 'u':
+ i = j = 1; /* should this be related to HOR?? */
+ break;
+ case 'v': /*VSs - vert spacing*/
+ j = lss;
+ i = 1;
+ break;
+ case 'm': /*Ems*/
+ j = EM;
+ i = 1;
+ break;
+ case 'n': /*Ens*/
+ j = EM;
+ if (TROFF)
+ i = 2;
+ else
+ i = 1; /*Same as Ems in NROFF*/
+ break;
+ case 'p': /*Points*/
+ j = INCH;
+ i = 72;
+ break;
+ case 'i': /*Inches*/
+ j = INCH;
+ i = 1;
+ break;
+ case 'c': /*Centimeters*/
+ /* if INCH is too big, this will overflow */
+ j = INCH * 50;
+ i = 127;
+ break;
+ case 'P': /*Picas*/
+ j = INCH;
+ i = 6;
+ break;
+ default:
+ j = dfact;
+ ch = ii;
+ i = dfactd;
+ }
+ if (neg)
+ acc = -acc;
+ if (!noscale) {
+ acc = (acc * j) / i;
+ }
+ if (field != digits && digits > 0)
+ while (digits--)
+ acc /= 10;
+ if (abs) {
+ if (dip != d)
+ j = dip->dnl;
+ else
+ j = numtabp[NL].val;
+ if (!vflag) {
+ j = numtabp[HP].val;
+ }
+ if (abs == 2)
+ j = -j;
+ acc -= j;
+ }
+a2:
+ nonumb = (!field || field == decpnt);
+ if (nonumb && (trace & TRNARGS) && !ismot(ii) && !nlflg && !ifnum) {
+ if (cbits(ii) != RIGHT ) /* Too painful to do right */
+ prnumerr();
+ }
+ return(acc);
+}
+
+
+void caserr(void)
+{
+ int i, j;
+ Numtab *p;
+
+ lgf++;
+ while (!skip() && (i = getrq()) ) {
+ j = usedr(i);
+ if (j < 0)
+ continue;
+ p = &numtabp[j];
+ nunhash(p);
+ p->r = p->val = p->inc = p->fmt = 0;
+ regcnt--;
+ }
+}
+
+/*
+ * .nr request; if tracing, don't check optional
+ * 2nd argument because tbl generates .in 1.5n
+ */
+void casenr(void)
+{
+ int i, j;
+ int savtr = trace;
+
+ lgf++;
+ skip();
+ if ((i = findr(getrq())) == -1)
+ goto rtn;
+ skip();
+ j = inumb(&numtabp[i].val);
+ if (nonumb)
+ goto rtn;
+ numtabp[i].val = j;
+ skip();
+ trace = 0;
+ j = atoi0(); /* BUG??? */
+ trace = savtr;
+ if (nonumb)
+ goto rtn;
+ numtabp[i].inc = j;
+rtn:
+ return;
+}
+
+void caseaf(void)
+{
+ int i, k;
+ Tchar j;
+
+ lgf++;
+ if (skip() || !(i = getrq()) || skip())
+ return;
+ k = 0;
+ j = getch();
+ if (!isalpha(cbits(j))) {
+ ch = j;
+ while ((j = cbits(getch())) >= '0' && j <= '9')
+ k++;
+ }
+ if (!k)
+ k = j;
+ numtabp[findr(i)].fmt = k; /* was k & BYTEMASK */
+}
+
+void setaf(void) /* return format of number register */
+{
+ int i, j;
+
+ i = usedr(getsn());
+ if (i == -1)
+ return;
+ if (numtabp[i].fmt > 20) /* it was probably a, A, i or I */
+ *pbp++ = numtabp[i].fmt;
+ else
+ for (j = (numtabp[i].fmt ? numtabp[i].fmt : 1); j; j--)
+ *pbp++ = '0';
+}
+
+
+int vnumb(int *i)
+{
+ vflag++;
+ dfact = lss;
+ res = VERT;
+ return(inumb(i));
+}
+
+
+int hnumb(int *i)
+{
+ dfact = EM;
+ res = HOR;
+ return(inumb(i));
+}
+
+
+int inumb(int *n)
+{
+ int i, j, f;
+ Tchar ii;
+
+ f = 0;
+ if (n) {
+ if ((j = cbits(ii = getch())) == '+')
+ f = 1;
+ else if (j == '-')
+ f = -1;
+ else
+ ch = ii;
+ }
+ i = atoi0();
+ if (n && f)
+ i = *n + f * i;
+ i = quant(i, res);
+ vflag = 0;
+ res = dfactd = dfact = 1;
+ if (nonumb)
+ i = 0;
+ return(i);
+}
+
+
+int quant(int n, int m)
+{
+ int i, neg;
+
+ neg = 0;
+ if (n < 0) {
+ neg++;
+ n = -n;
+ }
+ /* better as i = ((n + m/2)/m)*m */
+ i = n / m;
+ if (n - m * i > m / 2)
+ i += 1;
+ i *= m;
+ if (neg)
+ i = -i;
+ return(i);
+}
diff --git a/src/cmd/troff/n5.c b/src/cmd/troff/n5.c
new file mode 100644
index 00000000..c2801e47
--- /dev/null
+++ b/src/cmd/troff/n5.c
@@ -0,0 +1,1149 @@
+/*
+ * troff5.c
+ *
+ * misc processing requests
+ */
+
+#include "tdef.h"
+#include "fns.h"
+#include "ext.h"
+
+int iflist[NIF];
+int ifx;
+int ifnum = 0; /* trying numeric expression for .if or .ie condition */
+
+void casead(void)
+{
+ int i;
+
+ ad = 1;
+ /* leave admod alone */
+ if (skip())
+ return;
+ switch (i = cbits(getch())) {
+ case 'r': /* right adj, left ragged */
+ admod = 2;
+ break;
+ case 'l': /* left adj, right ragged */
+ admod = ad = 0; /* same as casena */
+ break;
+ case 'c': /*centered adj*/
+ admod = 1;
+ break;
+ case 'b':
+ case 'n':
+ admod = 0;
+ break;
+ case '0':
+ case '2':
+ case '4':
+ ad = 0;
+ case '1':
+ case '3':
+ case '5':
+ admod = (i - '0') / 2;
+ }
+}
+
+
+void casena(void)
+{
+ ad = 0;
+}
+
+
+void casefi(void)
+{
+ tbreak();
+ fi = 1;
+ pendnf = 0;
+}
+
+
+void casenf(void)
+{
+ tbreak();
+ fi = 0;
+}
+
+
+void casers(void)
+{
+ dip->nls = 0;
+}
+
+
+void casens(void)
+{
+ dip->nls++;
+}
+
+
+chget(int c)
+{
+ Tchar i;
+
+ if (skip() || ismot(i = getch()) || cbits(i) == ' ' || cbits(i) == '\n') {
+ ch = i;
+ return(c);
+ } else
+ return cbits(i); /* was (i & BYTEMASK) */
+}
+
+
+void casecc(void)
+{
+ cc = chget('.');
+}
+
+
+void casec2(void)
+{
+ c2 = chget('\'');
+}
+
+
+void casehc(void)
+{
+ ohc = chget(OHC);
+}
+
+
+void casetc(void)
+{
+ tabc = chget(0);
+}
+
+
+void caselc(void)
+{
+ dotc = chget(0);
+}
+
+
+void casehy(void)
+{
+ int i;
+
+ hyf = 1;
+ if (skip())
+ return;
+ noscale++;
+ i = atoi0();
+ noscale = 0;
+ if (nonumb)
+ return;
+ hyf = max(i, 0);
+}
+
+
+void casenh(void)
+{
+ hyf = 0;
+}
+
+
+max(int aa, int bb)
+{
+ if (aa > bb)
+ return(aa);
+ else
+ return(bb);
+}
+
+
+void casece(void)
+{
+ int i;
+
+ noscale++;
+ skip();
+ i = max(atoi0(), 0);
+ if (nonumb)
+ i = 1;
+ tbreak();
+ ce = i;
+ noscale = 0;
+}
+
+
+void casein(void)
+{
+ int i;
+
+ if (skip())
+ i = in1;
+ else {
+ i = max(hnumb(&in), 0);
+ if (nonumb)
+ i = in1;
+ }
+ tbreak();
+ in1 = in;
+ in = i;
+ if (!nc) {
+ un = in;
+ setnel();
+ }
+}
+
+
+void casell(void)
+{
+ int i;
+
+ if (skip())
+ i = ll1;
+ else {
+ i = max(hnumb(&ll), INCH / 10);
+ if (nonumb)
+ i = ll1;
+ }
+ ll1 = ll;
+ ll = i;
+ setnel();
+}
+
+
+void caselt(void)
+{
+ int i;
+
+ if (skip())
+ i = lt1;
+ else {
+ i = max(hnumb(&lt), 0);
+ if (nonumb)
+ i = lt1;
+ }
+ lt1 = lt;
+ lt = i;
+}
+
+
+void caseti(void)
+{
+ int i;
+
+ if (skip())
+ return;
+ i = max(hnumb(&in), 0);
+ tbreak();
+ un1 = i;
+ setnel();
+}
+
+
+void casels(void)
+{
+ int i;
+
+ noscale++;
+ if (skip())
+ i = ls1;
+ else {
+ i = max(inumb(&ls), 1);
+ if (nonumb)
+ i = ls1;
+ }
+ ls1 = ls;
+ ls = i;
+ noscale = 0;
+}
+
+
+void casepo(void)
+{
+ int i;
+
+ if (skip())
+ i = po1;
+ else {
+ i = max(hnumb(&po), 0);
+ if (nonumb)
+ i = po1;
+ }
+ po1 = po;
+ po = i;
+ if (TROFF & !ascii)
+ esc += po - po1;
+}
+
+
+void casepl(void)
+{
+ int i;
+
+ skip();
+ if ((i = vnumb(&pl)) == 0)
+ pl = 11 * INCH; /*11in*/
+ else
+ pl = i;
+ if (numtabp[NL].val > pl)
+ numtabp[NL].val = pl;
+}
+
+
+void casewh(void)
+{
+ int i, j, k;
+
+ lgf++;
+ skip();
+ i = vnumb((int *)0);
+ if (nonumb)
+ return;
+ skip();
+ j = getrq();
+ if ((k = findn(i)) != NTRAP) {
+ mlist[k] = j;
+ return;
+ }
+ for (k = 0; k < NTRAP; k++)
+ if (mlist[k] == 0)
+ break;
+ if (k == NTRAP) {
+ flusho();
+ ERROR "cannot plant trap." WARN;
+ return;
+ }
+ mlist[k] = j;
+ nlist[k] = i;
+}
+
+
+void casech(void)
+{
+ int i, j, k;
+
+ lgf++;
+ skip();
+ if (!(j = getrq()))
+ return;
+ else
+ for (k = 0; k < NTRAP; k++)
+ if (mlist[k] == j)
+ break;
+ if (k == NTRAP)
+ return;
+ skip();
+ i = vnumb((int *)0);
+ if (nonumb)
+ mlist[k] = 0;
+ nlist[k] = i;
+}
+
+
+findn(int i)
+{
+ int k;
+
+ for (k = 0; k < NTRAP; k++)
+ if ((nlist[k] == i) && (mlist[k] != 0))
+ break;
+ return(k);
+}
+
+
+void casepn(void)
+{
+ int i;
+
+ skip();
+ noscale++;
+ i = max(inumb(&numtabp[PN].val), 0);
+ noscale = 0;
+ if (!nonumb) {
+ npn = i;
+ npnflg++;
+ }
+}
+
+
+void casebp(void)
+{
+ int i;
+ Stack *savframe;
+
+ if (dip != d)
+ return;
+ savframe = frame;
+ skip();
+ if ((i = inumb(&numtabp[PN].val)) < 0)
+ i = 0;
+ tbreak();
+ if (!nonumb) {
+ npn = i;
+ npnflg++;
+ } else if (dip->nls)
+ return;
+ eject(savframe);
+}
+
+void casetm(void)
+{
+ casetm1(0, stderr);
+}
+
+
+void casefm(void)
+{
+ static struct fcache {
+ char *name;
+ FILE *fp;
+ } fcache[15];
+ int i;
+
+ if ( skip() || !getname()) {
+ ERROR "fm: missing filename" WARN;
+ return;
+ }
+
+ for (i = 0; i < 15 && fcache[i].fp != NULL; i++) {
+ if (strcmp(nextf, fcache[i].name) == 0)
+ break;
+ }
+ if (i >= 15) {
+ ERROR "fm: too many streams" WARN;
+ return;
+ }
+ if (fcache[i].fp == NULL) {
+ if( (fcache[i].fp = fopen(unsharp(nextf), "w")) == NULL) {
+ ERROR "fm: cannot open %s", nextf WARN;
+ return;
+ }
+ fcache[i].name = strdupl(nextf);
+ }
+ casetm1(0, fcache[i].fp);
+}
+
+void casetm1(int ab, FILE *out)
+{
+ int i, j, c;
+ char *p;
+ char tmbuf[NTM];
+
+ lgf++;
+ copyf++;
+ if (ab) {
+ if (skip())
+ ERROR "User Abort" WARN;
+ else {
+ extern int error;
+ int savtrac = trace;
+ i = trace = 0;
+ noscale++;
+ i = inumb(&trace);
+ noscale--;
+ if (i) {
+ error = i;
+ if (nlflg || skip())
+ ERROR "User Abort, exit code %d", i WARN;
+ }
+ trace = savtrac;
+ }
+ } else
+ skip();
+ for (i = 0; i < NTM - 2; ) {
+ if ((c = cbits(getch())) == '\n' || c == RIGHT)
+ break;
+ else if (c == MINUS) { /* special pleading for strange encodings */
+ tmbuf[i++] = '\\';
+ tmbuf[i++] = '-';
+ } else if (c == PRESC) {
+ tmbuf[i++] = '\\';
+ tmbuf[i++] = 'e';
+ } else if (c == FILLER) {
+ tmbuf[i++] = '\\';
+ tmbuf[i++] = '&';
+ } else if (c == UNPAD) {
+ tmbuf[i++] = '\\';
+ tmbuf[i++] = ' ';
+ } else if (c == OHC) {
+ tmbuf[i++] = '\\';
+ tmbuf[i++] = '%';
+ } else if (c >= ALPHABET) {
+ p = chname(c);
+ switch (*p) {
+ case MBchar:
+ sprintf(&tmbuf[i], p+1);
+ break;
+ case Number:
+ sprintf(&tmbuf[i], "\\N'%s'", p+1);
+ break;
+ case Troffchar:
+ if ((j = strlen(p+1)) == 2)
+ sprintf(&tmbuf[i], "\\(%s", p+1);
+ else
+ sprintf(&tmbuf[i], "\\C'%s'", p+1);
+ break;
+ default:
+ sprintf(&tmbuf[i]," %s? ", p);
+ break;
+ }
+ j = strlen(&tmbuf[i]);
+ i += j;
+ } else
+ tmbuf[i++] = c;
+ }
+ tmbuf[i] = 0;
+ if (ab) /* truncate output */
+ obufp = obuf; /* should be a function in n2.c */
+ flusho();
+ if (i)
+ fprintf(out, "%s\n", tmbuf);
+ fflush(out);
+ copyf--;
+ lgf--;
+}
+
+
+void casesp(void)
+{
+ casesp1(0);
+}
+
+void casesp1(int a)
+{
+ int i, j, savlss;
+
+ tbreak();
+ if (dip->nls || trap)
+ return;
+ i = findt1();
+ if (!a) {
+ skip();
+ j = vnumb((int *)0);
+ if (nonumb)
+ j = lss;
+ } else
+ j = a;
+ if (j == 0)
+ return;
+ if (i < j)
+ j = i;
+ savlss = lss;
+ if (dip != d)
+ i = dip->dnl;
+ else
+ i = numtabp[NL].val;
+ if ((i + j) < 0)
+ j = -i;
+ lss = j;
+ newline(0);
+ lss = savlss;
+}
+
+
+void casert(void)
+{
+ int a, *p;
+
+ skip();
+ if (dip != d)
+ p = &dip->dnl;
+ else
+ p = &numtabp[NL].val;
+ a = vnumb(p);
+ if (nonumb)
+ a = dip->mkline;
+ if ((a < 0) || (a >= *p))
+ return;
+ nb++;
+ casesp1(a - *p);
+}
+
+
+void caseem(void)
+{
+ lgf++;
+ skip();
+ em = getrq();
+}
+
+
+void casefl(void)
+{
+ tbreak();
+ if (!ascii)
+ ptflush();
+ flusho();
+}
+
+
+void caseev(void)
+{
+ int nxev;
+
+ if (skip()) {
+e0:
+ if (evi == 0)
+ return;
+ nxev = evlist[--evi];
+ goto e1;
+ }
+ noscale++;
+ nxev = atoi0();
+ noscale = 0;
+ if (nonumb)
+ goto e0;
+ flushi();
+ if (nxev >= NEV || nxev < 0 || evi >= EVLSZ) {
+ flusho();
+ ERROR "cannot do .ev %d", nxev WARN;
+ if (error)
+ done2(040);
+ else
+ edone(040);
+ return;
+ }
+ evlist[evi++] = ev;
+e1:
+ if (ev == nxev)
+ return;
+ ev = nxev;
+ envp = &env[ev];
+}
+
+void envcopy(Env *e1, Env *e2) /* copy env e2 to e1 */
+{
+ *e1 = *e2; /* rumor hath that this fails on some machines */
+}
+
+
+void caseel(void)
+{
+ if (--ifx < 0) {
+ ifx = 0;
+ iflist[0] = 0;
+ }
+ caseif1(2);
+}
+
+
+void caseie(void)
+{
+ if (ifx >= NIF) {
+ ERROR "if-else overflow." WARN;
+ ifx = 0;
+ edone(040);
+ }
+ caseif1(1);
+ ifx++;
+}
+
+
+void caseif(void)
+{
+ caseif1(0);
+}
+
+void caseif1(int x)
+{
+ extern int falsef;
+ int notflag, true;
+ Tchar i;
+
+ if (x == 2) {
+ notflag = 0;
+ true = iflist[ifx];
+ goto i1;
+ }
+ true = 0;
+ skip();
+ if ((cbits(i = getch())) == '!') {
+ notflag = 1;
+ } else {
+ notflag = 0;
+ ch = i;
+ }
+ ifnum++;
+ i = atoi0();
+ ifnum = 0;
+ if (!nonumb) {
+ if (i > 0)
+ true++;
+ goto i1;
+ }
+ i = getch();
+ switch (cbits(i)) {
+ case 'e':
+ if (!(numtabp[PN].val & 01))
+ true++;
+ break;
+ case 'o':
+ if (numtabp[PN].val & 01)
+ true++;
+ break;
+ case 'n':
+ if (NROFF)
+ true++;
+ break;
+ case 't':
+ if (TROFF)
+ true++;
+ break;
+ case ' ':
+ break;
+ default:
+ true = cmpstr(i);
+ }
+i1:
+ true ^= notflag;
+ if (x == 1)
+ iflist[ifx] = !true;
+ if (true) {
+i2:
+ while ((cbits(i = getch())) == ' ')
+ ;
+ if (cbits(i) == LEFT)
+ goto i2;
+ ch = i;
+ nflush++;
+ } else {
+ if (!nlflg) {
+ copyf++;
+ falsef++;
+ eatblk(0);
+ copyf--;
+ falsef--;
+ }
+ }
+}
+
+void eatblk(int inblk)
+{
+ int cnt, i;
+
+ cnt = 0;
+ do {
+ if (ch) {
+ i = cbits(ch);
+ ch = 0;
+ } else
+ i = cbits(getch0());
+ if (i == ESC)
+ cnt++;
+ else {
+ if (cnt == 1)
+ switch (i) {
+ case '{': i = LEFT; break;
+ case '}': i = RIGHT; break;
+ case '\n': i = 'x'; break;
+ }
+ cnt = 0;
+ }
+ if (i == LEFT) eatblk(1);
+ } while ((!inblk && (i != '\n')) || (inblk && (i != RIGHT)));
+ if (i == '\n') {
+ nlflg++;
+ if (ip == 0)
+ numtabp[CD].val++;
+ }
+}
+
+
+cmpstr(Tchar c)
+{
+ int j, delim;
+ Tchar i;
+ int val;
+ int savapts, savapts1, savfont, savfont1, savpts, savpts1;
+ Tchar string[1280];
+ Tchar *sp;
+
+ if (ismot(c))
+ return(0);
+ delim = cbits(c);
+ savapts = apts;
+ savapts1 = apts1;
+ savfont = font;
+ savfont1 = font1;
+ savpts = pts;
+ savpts1 = pts1;
+ sp = string;
+ while ((j = cbits(i = getch()))!=delim && j!='\n' && sp<&string[1280-1])
+ *sp++ = i;
+ if (sp >= string + 1280) {
+ ERROR "too-long string compare." WARN;
+ edone(0100);
+ }
+ if (nlflg) {
+ val = sp==string;
+ goto rtn;
+ }
+ *sp = 0;
+ apts = savapts;
+ apts1 = savapts1;
+ font = savfont;
+ font1 = savfont1;
+ pts = savpts;
+ pts1 = savpts1;
+ mchbits();
+ val = 1;
+ sp = string;
+ while ((j = cbits(i = getch())) != delim && j != '\n') {
+ if (*sp != i) {
+ eat(delim);
+ val = 0;
+ goto rtn;
+ }
+ sp++;
+ }
+ if (*sp)
+ val = 0;
+rtn:
+ apts = savapts;
+ apts1 = savapts1;
+ font = savfont;
+ font1 = savfont1;
+ pts = savpts;
+ pts1 = savpts1;
+ mchbits();
+ return(val);
+}
+
+
+void caserd(void)
+{
+
+ lgf++;
+ skip();
+ getname();
+ if (!iflg) {
+ if (quiet) {
+ if (NROFF) {
+ echo_off();
+ flusho();
+ }
+ fprintf(stderr, "\007"); /*bell*/
+ } else {
+ if (nextf[0]) {
+ fprintf(stderr, "%s:", nextf);
+ } else {
+ fprintf(stderr, "\007"); /*bell*/
+ }
+ }
+ }
+ collect();
+ tty++;
+ pushi(RD_OFFSET, PAIR('r','d'));
+}
+
+
+rdtty(void)
+{
+ char onechar;
+
+ onechar = 0;
+ if (read(0, &onechar, 1) == 1) {
+ if (onechar == '\n')
+ tty++;
+ else
+ tty = 1;
+ if (tty != 3)
+ return(onechar);
+ }
+ tty = 0;
+ if (NROFF && quiet)
+ echo_on();
+ return(0);
+}
+
+
+void caseec(void)
+{
+ eschar = chget('\\');
+}
+
+
+void caseeo(void)
+{
+ eschar = 0;
+}
+
+
+void caseta(void)
+{
+ int i, j, k;
+
+ tabtab[0] = nonumb = 0;
+ for (i = 0; ((i < (NTAB - 1)) && !nonumb); i++) {
+ if (skip())
+ break;
+ k = tabtab[max(i-1, 0)] & TABMASK;
+ if ((j = max(hnumb(&k), 0)) > TABMASK) {
+ ERROR "Tab too far away" WARN;
+ j = TABMASK;
+ }
+ tabtab[i] = j & TABMASK;
+ if (!nonumb)
+ switch (cbits(ch)) {
+ case 'C':
+ tabtab[i] |= CTAB;
+ break;
+ case 'R':
+ tabtab[i] |= RTAB;
+ break;
+ default: /*includes L*/
+ break;
+ }
+ nonumb = ch = 0;
+ }
+ if (!skip())
+ ERROR "Too many tab stops" WARN;
+ tabtab[i] = 0;
+}
+
+
+void casene(void)
+{
+ int i, j;
+
+ skip();
+ i = vnumb((int *)0);
+ if (nonumb)
+ i = lss;
+ if (dip == d && numtabp[NL].val == -1) {
+ newline(1);
+ return;
+ }
+ if (i > (j = findt1())) {
+ i = lss;
+ lss = j;
+ dip->nls = 0;
+ newline(0);
+ lss = i;
+ }
+}
+
+
+void casetr(void)
+{
+ int i, j;
+ Tchar k;
+
+ lgf++;
+ skip();
+ while ((i = cbits(k=getch())) != '\n') {
+ if (ismot(k))
+ return;
+ if (ismot(k = getch()))
+ return;
+ if ((j = cbits(k)) == '\n')
+ j = ' ';
+ trtab[i] = j;
+ }
+}
+
+
+void casecu(void)
+{
+ cu++;
+ caseul();
+}
+
+
+void caseul(void)
+{
+ int i;
+
+ noscale++;
+ skip();
+ i = max(atoi0(), 0);
+ if (nonumb)
+ i = 1;
+ if (ul && (i == 0)) {
+ font = sfont;
+ ul = cu = 0;
+ }
+ if (i) {
+ if (!ul) {
+ sfont = font;
+ font = ulfont;
+ }
+ ul = i;
+ }
+ noscale = 0;
+ mchbits();
+}
+
+
+void caseuf(void)
+{
+ int i, j;
+
+ if (skip() || !(i = getrq()) || i == 'S' || (j = findft(i)) == -1)
+ ulfont = ULFONT; /*default underline position*/
+ else
+ ulfont = j;
+ if (NROFF && ulfont == FT)
+ ulfont = ULFONT;
+}
+
+
+void caseit(void)
+{
+ int i;
+
+ lgf++;
+ it = itmac = 0;
+ noscale++;
+ skip();
+ i = atoi0();
+ skip();
+ if (!nonumb && (itmac = getrq()))
+ it = i;
+ noscale = 0;
+}
+
+
+void casemc(void)
+{
+ int i;
+
+ if (icf > 1)
+ ic = 0;
+ icf = 0;
+ if (skip())
+ return;
+ ic = getch();
+ icf = 1;
+ skip();
+ i = max(hnumb((int *)0), 0);
+ if (!nonumb)
+ ics = i;
+}
+
+
+void casemk(void)
+{
+ int i, j;
+
+ if (dip != d)
+ j = dip->dnl;
+ else
+ j = numtabp[NL].val;
+ if (skip()) {
+ dip->mkline = j;
+ return;
+ }
+ if ((i = getrq()) == 0)
+ return;
+ numtabp[findr(i)].val = j;
+}
+
+
+void casesv(void)
+{
+ int i;
+
+ skip();
+ if ((i = vnumb((int *)0)) < 0)
+ return;
+ if (nonumb)
+ i = 1;
+ sv += i;
+ caseos();
+}
+
+
+void caseos(void)
+{
+ int savlss;
+
+ if (sv <= findt1()) {
+ savlss = lss;
+ lss = sv;
+ newline(0);
+ lss = savlss;
+ sv = 0;
+ }
+}
+
+
+void casenm(void)
+{
+ int i;
+
+ lnmod = nn = 0;
+ if (skip())
+ return;
+ lnmod++;
+ noscale++;
+ i = inumb(&numtabp[LN].val);
+ if (!nonumb)
+ numtabp[LN].val = max(i, 0);
+ getnm(&ndf, 1);
+ getnm(&nms, 0);
+ getnm(&ni, 0);
+ getnm(&nmwid, 3); /* really kludgy! */
+ noscale = 0;
+ nmbits = chbits;
+}
+
+/*
+ * .nm relies on the fact that illegal args are skipped; don't warn
+ * for illegality of these
+ */
+void getnm(int *p, int min)
+{
+ int i;
+ int savtr = trace;
+
+ eat(' ');
+ if (skip())
+ return;
+ trace = 0;
+ i = atoi0();
+ if (nonumb)
+ return;
+ *p = max(i, min);
+ trace = savtr;
+}
+
+
+void casenn(void)
+{
+ noscale++;
+ skip();
+ nn = max(atoi0(), 1);
+ noscale = 0;
+}
+
+
+void caseab(void)
+{
+ casetm1(1, stderr);
+ done3(0);
+}
+
+
+/* nroff terminal handling has been pretty well excised */
+/* as part of the merge with troff. these are ghostly remnants, */
+/* called, but doing nothing. restore them at your peril. */
+
+
+void save_tty(void) /*save any tty settings that may be changed*/
+{
+}
+
+
+void restore_tty(void) /*restore tty settings from beginning*/
+{
+}
+
+
+void set_tty(void)
+{
+}
+
+
+void echo_off(void) /*turn off ECHO for .rd in "-q" mode*/
+{
+}
+
+
+void echo_on(void) /*restore ECHO after .rd in "-q" mode*/
+{
+}
diff --git a/src/cmd/troff/n6.c b/src/cmd/troff/n6.c
new file mode 100644
index 00000000..e4affa17
--- /dev/null
+++ b/src/cmd/troff/n6.c
@@ -0,0 +1,362 @@
+#include "tdef.h"
+#include "ext.h"
+#include "fns.h"
+#include <ctype.h>
+
+/*
+ * n6.c -- width functions, sizes and fonts
+*/
+
+n_width(Tchar j)
+{
+ int i, k;
+
+ if (iszbit(j))
+ return 0;
+ if (ismot(j)) {
+ if (isvmot(j))
+ return(0);
+ k = absmot(j);
+ if (isnmot(j))
+ k = -k;
+ return(k);
+ }
+ i = cbits(j);
+ if (i < ' ') {
+ if (i == '\b')
+ return(-widthp);
+ if (i == PRESC)
+ i = eschar;
+ else if (i == HX)
+ return(0);
+ }
+ if (i == ohc)
+ return(0);
+ i = trtab[i];
+ if (i < ' ')
+ return(0);
+ if (i >= t.tfont.nchars) /* not on the font */
+ k = t.Char; /* really ought to check properly */
+ else
+ k = t.tfont.wp[i].wid * t.Char;
+ widthp = k;
+ return(k);
+}
+
+
+Tchar n_setch(int c)
+{
+ return t_setch(c);
+}
+
+Tchar n_setabs(void) /* set absolute char from \N'...' */
+{ /* for now, a no-op */
+ return t_setabs();
+}
+
+int n_findft(int i)
+{
+ int k;
+
+ if ((k = i - '0') >= 0 && k <= nfonts && k < smnt)
+ return(k);
+ for (k = 0; fontlab[k] != i; k++)
+ if (k > nfonts)
+ return(-1);
+ return(k);
+}
+
+
+
+void n_mchbits(void)
+{
+ chbits = 0;
+ setfbits(chbits, font);
+ sps = width(' ' | chbits);
+}
+
+
+void n_setps(void )
+{
+ int i, j;
+
+ i = cbits(getch());
+ if (isdigit(i)) { /* \sd or \sdd */
+ i -= '0';
+ if (i == 0) /* \s0 */
+ ;
+ else if (i <= 3 && (ch=getch()) && isdigit(cbits(ch))) { /* \sdd */
+ ch = 0;
+ }
+ } else if (i == '(') { /* \s(dd */
+ getch();
+ getch();
+ } else if (i == '+' || i == '-') { /* \s+, \s- */
+ j = cbits(getch());
+ if (isdigit(j)) { /* \s+d, \s-d */
+ ;
+ } else if (j == '(') { /* \s+(dd, \s-(dd */
+ getch();
+ getch();
+ }
+ }
+}
+
+
+Tchar n_setht(void) /* set character height from \H'...' */
+{
+
+ getch();
+ inumb(&apts);
+ getch();
+ return(0);
+}
+
+
+Tchar n_setslant(void) /* set slant from \S'...' */
+{
+ int n;
+
+ getch();
+ n = 0;
+ n = inumb(&n);
+ getch();
+ return(0);
+}
+
+
+void n_caseft(void)
+{
+ skip();
+ setfont(1);
+}
+
+
+void n_setfont(int a)
+{
+ int i, j;
+
+ if (a)
+ i = getrq();
+ else
+ i = getsn();
+ if (!i || i == 'P') {
+ j = font1;
+ goto s0;
+ }
+ if (i == 'S' || i == '0')
+ return;
+ if ((j = findft(i)) == -1)
+ return;
+s0:
+ font1 = font;
+ font = j;
+ mchbits();
+}
+
+
+void n_setwd(void)
+{
+ int base, wid;
+ Tchar i;
+ int delim, emsz, k;
+ int savhp, savapts, savapts1, savfont, savfont1, savpts, savpts1;
+
+ base = numtabp[ST].val = numtabp[ST].val = wid = numtabp[CT].val = 0;
+ if (ismot(i = getch()))
+ return;
+ delim = cbits(i);
+ savhp = numtabp[HP].val;
+ numtabp[HP].val = 0;
+ savapts = apts;
+ savapts1 = apts1;
+ savfont = font;
+ savfont1 = font1;
+ savpts = pts;
+ savpts1 = pts1;
+ setwdf++;
+ while (cbits(i = getch()) != delim && !nlflg) {
+ k = width(i);
+ wid += k;
+ numtabp[HP].val += k;
+ if (!ismot(i)) {
+ emsz = (INCH * pts + 36) / 72;
+ } else if (isvmot(i)) {
+ k = absmot(i);
+ if (isnmot(i))
+ k = -k;
+ base -= k;
+ emsz = 0;
+ } else
+ continue;
+ if (base < numtabp[SB].val)
+ numtabp[SB].val = base;
+ if ((k = base + emsz) > numtabp[ST].val)
+ numtabp[ST].val = k;
+ }
+ setn1(wid, 0, (Tchar) 0);
+ numtabp[HP].val = savhp;
+ apts = savapts;
+ apts1 = savapts1;
+ font = savfont;
+ font1 = savfont1;
+ pts = savpts;
+ pts1 = savpts1;
+ mchbits();
+ setwdf = 0;
+}
+
+
+Tchar n_vmot(void)
+{
+ dfact = lss;
+ vflag++;
+ return n_mot();
+}
+
+
+Tchar n_hmot(void)
+{
+ dfact = EM;
+ return n_mot();
+}
+
+
+Tchar n_mot(void)
+{
+ int j, n;
+ Tchar i;
+
+ j = HOR;
+ getch(); /*eat delim*/
+ if (n = atoi0()) {
+ if (vflag)
+ j = VERT;
+ i = makem(quant(n, j));
+ } else
+ i = 0;
+ getch();
+ vflag = 0;
+ dfact = 1;
+ return(i);
+}
+
+
+Tchar n_sethl(int k)
+{
+ int j;
+ Tchar i;
+
+ j = t.Halfline;
+ if (k == 'u')
+ j = -j;
+ else if (k == 'r')
+ j = -2 * j;
+ vflag++;
+ i = makem(j);
+ vflag = 0;
+ return(i);
+}
+
+
+Tchar n_makem(int i)
+{
+ Tchar j;
+
+ if (i >= 0)
+ j = i;
+ else
+ j = -i;
+ j |= MOT;
+ if (i < 0)
+ j |= NMOT;
+ if (vflag)
+ j |= VMOT;
+ return(j);
+}
+
+
+void n_casefp(void)
+{
+ int i, j;
+
+ skip();
+ if ((i = cbits(getch()) - '0') < 0 || i > nfonts)
+ return;
+ if (skip() || !(j = getrq()))
+ return;
+ fontlab[i] = j;
+}
+
+
+
+void n_casebd(void)
+{
+ int i, j, k;
+
+ k = 0;
+bd0:
+ if (skip() || !(i = getrq()) || (j = findft(i)) == -1) {
+ if (k)
+ goto bd1;
+ else
+ return;
+ }
+ if (j == smnt) {
+ k = smnt;
+ goto bd0;
+ }
+ if (k) {
+ sbold = j;
+ j = k;
+ }
+bd1:
+ skip();
+ noscale++;
+ bdtab[j] = atoi0();
+ noscale = 0;
+}
+
+
+void n_casevs(void)
+{
+ int i;
+
+ skip();
+ vflag++;
+ dfact = INCH; /*default scaling is points!*/
+ dfactd = 72;
+ res = VERT;
+ i = inumb(&lss);
+ if (nonumb)
+ i = lss1;
+ if (i < VERT)
+ i = VERT; /* was VERT */
+ lss1 = lss;
+ lss = i;
+}
+
+
+
+
+Tchar n_xlss(void)
+{
+ /* stores \x'...' into
+ /* two successive Tchars.
+ /* the first contains HX, the second the value,
+ /* encoded as a vertical motion.
+ /* decoding is done in n2.c by pchar().
+ */
+ int i;
+
+ getch();
+ dfact = lss;
+ i = quant(atoi0(), VERT);
+ dfact = 1;
+ getch();
+ if (i >= 0)
+ *pbp++ = MOT | VMOT | i;
+ else
+ *pbp++ = MOT | VMOT | NMOT | -i;
+ return(HX);
+}
diff --git a/src/cmd/troff/n7.c b/src/cmd/troff/n7.c
new file mode 100644
index 00000000..c22a485c
--- /dev/null
+++ b/src/cmd/troff/n7.c
@@ -0,0 +1,834 @@
+#include "tdef.h"
+#include "fns.h"
+#include "ext.h"
+
+#ifdef STRICT
+ /* not in ANSI or POSIX */
+#define isascii(a) ((a) >= 0 && (a) <= 127)
+#endif
+
+#define GETCH gettch
+Tchar gettch(void);
+
+
+/*
+ * troff7.c
+ *
+ * text
+ */
+
+int brflg;
+
+void tbreak(void)
+{
+ int pad, k;
+ Tchar *i, j;
+ int resol;
+ int un0 = un;
+
+ trap = 0;
+ if (nb)
+ return;
+ if (dip == d && numtabp[NL].val == -1) {
+ newline(1);
+ return;
+ }
+ if (!nc) {
+ setnel();
+ if (!wch)
+ return;
+ if (pendw)
+ getword(1);
+ movword();
+ } else if (pendw && !brflg) {
+ getword(1);
+ movword();
+ }
+ *linep = dip->nls = 0;
+ if (NROFF && dip == d)
+ horiz(po);
+ if (lnmod)
+ donum();
+ lastl = ne;
+ if (brflg != 1) {
+ totout = 0;
+ } else if (ad) {
+ if ((lastl = ll - un) < ne)
+ lastl = ne;
+ }
+ if (admod && ad && (brflg != 2)) {
+ lastl = ne;
+ adsp = adrem = 0;
+ if (admod == 1)
+ un += quant(nel / 2, HOR);
+ else if (admod == 2)
+ un += nel;
+ }
+ totout++;
+ brflg = 0;
+ if (lastl + un > dip->maxl)
+ dip->maxl = lastl + un;
+ horiz(un);
+ if (NROFF) {
+ if (adrem % t.Adj)
+ resol = t.Hor;
+ else
+ resol = t.Adj;
+ } else
+ resol = HOR;
+
+ lastl = ne + (nwd-1) * adsp + adrem;
+ for (i = line; nc > 0; ) {
+ if ((cbits(j = *i++)) == ' ') {
+ pad = 0;
+ do {
+ pad += width(j);
+ nc--;
+ } while ((cbits(j = *i++)) == ' ');
+ i--;
+ pad += adsp;
+ --nwd;
+ if (adrem) {
+ if (adrem < 0) {
+ pad -= resol;
+ adrem += resol;
+ } else if ((totout & 01) || adrem / resol >= nwd) {
+ pad += resol;
+ adrem -= resol;
+ }
+ }
+ pchar((Tchar) WORDSP);
+ horiz(pad);
+ } else {
+ pchar(j);
+ nc--;
+ }
+ }
+ if (ic) {
+ if ((k = ll - un0 - lastl + ics) > 0)
+ horiz(k);
+ pchar(ic);
+ }
+ if (icf)
+ icf++;
+ else
+ ic = 0;
+ ne = nwd = 0;
+ un = in;
+ setnel();
+ newline(0);
+ if (dip != d) {
+ if (dip->dnl > dip->hnl)
+ dip->hnl = dip->dnl;
+ } else {
+ if (numtabp[NL].val > dip->hnl)
+ dip->hnl = numtabp[NL].val;
+ }
+ for (k = ls - 1; k > 0 && !trap; k--)
+ newline(0);
+ spread = 0;
+}
+
+void donum(void)
+{
+ int i, nw;
+ int lnv = numtabp[LN].val;
+
+ nrbits = nmbits;
+ nw = width('1' | nrbits);
+ if (nn) {
+ nn--;
+ goto d1;
+ }
+ if (lnv % ndf) {
+ numtabp[LN].val++;
+d1:
+ un += nw * (nmwid + nms + ni);
+ return;
+ }
+ i = 0;
+ do { /* count digits in numtabp[LN].val */
+ i++;
+ } while ((lnv /= 10) > 0);
+ horiz(nw * (ni + max(nmwid-i, 0)));
+ nform = 0;
+ fnumb(numtabp[LN].val, pchar);
+ un += nw * nms;
+ numtabp[LN].val++;
+}
+
+
+void text(void)
+{
+ Tchar i;
+ static int spcnt;
+
+ nflush++;
+ numtabp[HP].val = 0;
+ if ((dip == d) && (numtabp[NL].val == -1)) {
+ newline(1);
+ return;
+ }
+ setnel();
+ if (ce || !fi) {
+ nofill();
+ return;
+ }
+ if (pendw)
+ goto t4;
+ if (pendt)
+ if (spcnt)
+ goto t2;
+ else
+ goto t3;
+ pendt++;
+ if (spcnt)
+ goto t2;
+ while ((cbits(i = GETCH())) == ' ') {
+ spcnt++;
+ numtabp[HP].val += sps;
+ widthp = sps;
+ }
+ if (nlflg) {
+t1:
+ nflush = pendt = ch = spcnt = 0;
+ callsp();
+ return;
+ }
+ ch = i;
+ if (spcnt) {
+t2:
+ tbreak();
+ if (nc || wch)
+ goto rtn;
+ un += spcnt * sps;
+ spcnt = 0;
+ setnel();
+ if (trap)
+ goto rtn;
+ if (nlflg)
+ goto t1;
+ }
+t3:
+ if (spread)
+ goto t5;
+ if (pendw || !wch)
+t4:
+ if (getword(0))
+ goto t6;
+ if (!movword())
+ goto t3;
+t5:
+ if (nlflg)
+ pendt = 0;
+ adsp = adrem = 0;
+ if (ad) {
+ if (nwd == 1)
+ adsp = nel;
+ else
+ adsp = nel / (nwd - 1);
+ adsp = (adsp / HOR) * HOR;
+ adrem = nel - adsp*(nwd-1);
+ }
+ brflg = 1;
+ tbreak();
+ spread = 0;
+ if (!trap)
+ goto t3;
+ if (!nlflg)
+ goto rtn;
+t6:
+ pendt = 0;
+ ckul();
+rtn:
+ nflush = 0;
+}
+
+
+void nofill(void)
+{
+ int j;
+ Tchar i;
+
+ if (!pendnf) {
+ over = 0;
+ tbreak();
+ if (trap)
+ goto rtn;
+ if (nlflg) {
+ ch = nflush = 0;
+ callsp();
+ return;
+ }
+ adsp = adrem = 0;
+ nwd = 10000;
+ }
+ while ((j = (cbits(i = GETCH()))) != '\n') {
+ if (j == ohc)
+ continue;
+ if (j == CONT) {
+ pendnf++;
+ nflush = 0;
+ flushi();
+ ckul();
+ return;
+ }
+ j = width(i);
+ widthp = j;
+ numtabp[HP].val += j;
+ storeline(i, j);
+ }
+ if (ce) {
+ ce--;
+ if ((i = quant(nel / 2, HOR)) > 0)
+ un += i;
+ }
+ if (!nc)
+ storeline((Tchar)FILLER, 0);
+ brflg = 2;
+ tbreak();
+ ckul();
+rtn:
+ pendnf = nflush = 0;
+}
+
+
+void callsp(void)
+{
+ int i;
+
+ if (flss)
+ i = flss;
+ else
+ i = lss;
+ flss = 0;
+ casesp1(i);
+}
+
+
+void ckul(void)
+{
+ if (ul && (--ul == 0)) {
+ cu = 0;
+ font = sfont;
+ mchbits();
+ }
+ if (it && --it == 0 && itmac)
+ control(itmac, 0);
+}
+
+
+void storeline(Tchar c, int w)
+{
+ int diff;
+
+ if (linep >= line + lnsize - 2) {
+ lnsize += LNSIZE;
+ diff = linep - line;
+ if (( line = (Tchar *)realloc((char *)line, lnsize * sizeof(Tchar))) != NULL) {
+ if (linep && diff)
+ linep = line + diff;
+ } else {
+ if (over) {
+ return;
+ } else {
+ flusho();
+ ERROR "Line overflow." WARN;
+ over++;
+ *linep++ = LEFTHAND;
+ w = width(LEFTHAND);
+ nc++;
+ c = '\n';
+ }
+ }
+ }
+ *linep++ = c;
+ ne += w;
+ nel -= w;
+ nc++;
+}
+
+
+void newline(int a)
+{
+ int i, j, nlss;
+ int opn;
+
+ if (a)
+ goto nl1;
+ if (dip != d) {
+ j = lss;
+ pchar1((Tchar)FLSS);
+ if (flss)
+ lss = flss;
+ i = lss + dip->blss;
+ dip->dnl += i;
+ pchar1((Tchar)i);
+ pchar1((Tchar)'\n');
+ lss = j;
+ dip->blss = flss = 0;
+ if (dip->alss) {
+ pchar1((Tchar)FLSS);
+ pchar1((Tchar)dip->alss);
+ pchar1((Tchar)'\n');
+ dip->dnl += dip->alss;
+ dip->alss = 0;
+ }
+ if (dip->ditrap && !dip->ditf && dip->dnl >= dip->ditrap && dip->dimac)
+ if (control(dip->dimac, 0)) {
+ trap++;
+ dip->ditf++;
+ }
+ return;
+ }
+ j = lss;
+ if (flss)
+ lss = flss;
+ nlss = dip->alss + dip->blss + lss;
+ numtabp[NL].val += nlss;
+ if (TROFF && ascii) {
+ dip->alss = dip->blss = 0;
+ }
+ pchar1((Tchar)'\n');
+ flss = 0;
+ lss = j;
+ if (numtabp[NL].val < pl)
+ goto nl2;
+nl1:
+ ejf = dip->hnl = numtabp[NL].val = 0;
+ ejl = frame;
+ if (donef) {
+ if ((!nc && !wch) || ndone)
+ done1(0);
+ ndone++;
+ donef = 0;
+ if (frame == stk)
+ nflush++;
+ }
+ opn = numtabp[PN].val;
+ numtabp[PN].val++;
+ if (npnflg) {
+ numtabp[PN].val = npn;
+ npn = npnflg = 0;
+ }
+nlpn:
+ if (numtabp[PN].val == pfrom) {
+ print++;
+ pfrom = -1;
+ } else if (opn == pto) {
+ print = 0;
+ opn = -1;
+ chkpn();
+ goto nlpn;
+ }
+ if (print)
+ ptpage(numtabp[PN].val); /* supposedly in a clean state so can pause */
+ if (stop && print) {
+ dpn++;
+ if (dpn >= stop) {
+ dpn = 0;
+ ptpause();
+ }
+ }
+nl2:
+ trap = 0;
+ if (numtabp[NL].val == 0) {
+ if ((j = findn(0)) != NTRAP)
+ trap = control(mlist[j], 0);
+ } else if ((i = findt(numtabp[NL].val - nlss)) <= nlss) {
+ if ((j = findn1(numtabp[NL].val - nlss + i)) == NTRAP) {
+ flusho();
+ ERROR "Trap botch." WARN;
+ done2(-5);
+ }
+ trap = control(mlist[j], 0);
+ }
+}
+
+
+findn1(int a)
+{
+ int i, j;
+
+ for (i = 0; i < NTRAP; i++) {
+ if (mlist[i]) {
+ if ((j = nlist[i]) < 0)
+ j += pl;
+ if (j == a)
+ break;
+ }
+ }
+ return(i);
+}
+
+
+void chkpn(void)
+{
+ pto = *(pnp++);
+ pfrom = pto>=0 ? pto : -pto;
+ if (pto == -INT_MAX) {
+ flusho();
+ done1(0);
+ }
+ if (pto < 0) {
+ pto = -pto;
+ print++;
+ pfrom = 0;
+ }
+}
+
+
+findt(int a)
+{
+ int i, j, k;
+
+ k = INT_MAX;
+ if (dip != d) {
+ if (dip->dimac && (i = dip->ditrap - a) > 0)
+ k = i;
+ return(k);
+ }
+ for (i = 0; i < NTRAP; i++) {
+ if (mlist[i]) {
+ if ((j = nlist[i]) < 0)
+ j += pl;
+ if ((j -= a) <= 0)
+ continue;
+ if (j < k)
+ k = j;
+ }
+ }
+ i = pl - a;
+ if (k > i)
+ k = i;
+ return(k);
+}
+
+
+findt1(void)
+{
+ int i;
+
+ if (dip != d)
+ i = dip->dnl;
+ else
+ i = numtabp[NL].val;
+ return(findt(i));
+}
+
+
+void eject(Stack *a)
+{
+ int savlss;
+
+ if (dip != d)
+ return;
+ ejf++;
+ if (a)
+ ejl = a;
+ else
+ ejl = frame;
+ if (trap)
+ return;
+e1:
+ savlss = lss;
+ lss = findt(numtabp[NL].val);
+ newline(0);
+ lss = savlss;
+ if (numtabp[NL].val && !trap)
+ goto e1;
+}
+
+
+movword(void)
+{
+ int w;
+ Tchar i, *wp;
+ int savwch, hys;
+
+ over = 0;
+ wp = wordp;
+ if (!nwd) {
+ while (cbits(*wp++) == ' ') {
+ wch--;
+ wne -= sps;
+ }
+ wp--;
+ }
+ if (wne > nel && !hyoff && hyf && (!nwd || nel > 3 * sps) &&
+ (!(hyf & 02) || (findt1() > lss)))
+ hyphen(wp);
+ savwch = wch;
+ hyp = hyptr;
+ nhyp = 0;
+ while (*hyp && *hyp <= wp)
+ hyp++;
+ while (wch) {
+ if (hyoff != 1 && *hyp == wp) {
+ hyp++;
+ if (!wdstart || (wp > wdstart + 1 && wp < wdend &&
+ (!(hyf & 04) || wp < wdend - 1) && /* 04 => last 2 */
+ (!(hyf & 010) || wp > wdstart + 2))) { /* 010 => 1st 2 */
+ nhyp++;
+ storeline((Tchar)IMP, 0);
+ }
+ }
+ i = *wp++;
+ w = width(i);
+ wne -= w;
+ wch--;
+ storeline(i, w);
+ }
+ if (nel >= 0) {
+ nwd++;
+ return(0); /* line didn't fill up */
+ }
+ if (TROFF)
+ xbits((Tchar)HYPHEN, 1);
+ hys = width((Tchar)HYPHEN);
+m1:
+ if (!nhyp) {
+ if (!nwd)
+ goto m3;
+ if (wch == savwch)
+ goto m4;
+ }
+ if (*--linep != IMP)
+ goto m5;
+ if (!(--nhyp))
+ if (!nwd)
+ goto m2;
+ if (nel < hys) {
+ nc--;
+ goto m1;
+ }
+m2:
+ if ((i = cbits(*(linep - 1))) != '-' && i != EMDASH) {
+ *linep = (*(linep - 1) & SFMASK) | HYPHEN;
+ w = width(*linep);
+ nel -= w;
+ ne += w;
+ linep++;
+ }
+m3:
+ nwd++;
+m4:
+ wordp = wp;
+ return(1); /* line filled up */
+m5:
+ nc--;
+ w = width(*linep);
+ ne -= w;
+ nel += w;
+ wne += w;
+ wch++;
+ wp--;
+ goto m1;
+}
+
+
+void horiz(int i)
+{
+ vflag = 0;
+ if (i)
+ pchar(makem(i));
+}
+
+
+void setnel(void)
+{
+ if (!nc) {
+ linep = line;
+ if (un1 >= 0) {
+ un = un1;
+ un1 = -1;
+ }
+ nel = ll - un;
+ ne = adsp = adrem = 0;
+ }
+}
+
+
+getword(int x)
+{
+ int j, k;
+ Tchar i, *wp;
+ int noword;
+ int obits;
+
+ noword = 0;
+ if (x)
+ if (pendw) {
+ *pendw = 0;
+ goto rtn;
+ }
+ if (wordp = pendw)
+ goto g1;
+ hyp = hyptr;
+ wordp = word;
+ over = wne = wch = 0;
+ hyoff = 0;
+ obits = chbits;
+ while (1) { /* picks up 1st char of word */
+ j = cbits(i = GETCH());
+ if (j == '\n') {
+ wne = wch = 0;
+ noword = 1;
+ goto rtn;
+ }
+ if (j == ohc) {
+ hyoff = 1; /* 1 => don't hyphenate */
+ continue;
+ }
+ if (j == ' ') {
+ numtabp[HP].val += sps;
+ widthp = sps;
+ storeword(i, sps);
+ continue;
+ }
+ break;
+ }
+ storeword(' ' | obits, sps);
+ if (spflg) {
+ storeword(' ' | obits, sps);
+ spflg = 0;
+ }
+g0:
+ if (j == CONT) {
+ pendw = wordp;
+ nflush = 0;
+ flushi();
+ return(1);
+ }
+ if (hyoff != 1) {
+ if (j == ohc) {
+ hyoff = 2;
+ *hyp++ = wordp;
+ if (hyp > hyptr + NHYP - 1)
+ hyp = hyptr + NHYP - 1;
+ goto g1;
+ }
+ if (((j == '-' || j == EMDASH)) && !(i & ZBIT)) /* zbit avoids \X */
+ if (wordp > word + 1) {
+ hyoff = 2;
+ *hyp++ = wordp + 1;
+ if (hyp > hyptr + NHYP - 1)
+ hyp = hyptr + NHYP - 1;
+ }
+ }
+ j = width(i);
+ numtabp[HP].val += j;
+ storeword(i, j);
+g1:
+ j = cbits(i = GETCH());
+ if (j != ' ') {
+ static char *sentchar = ".?!"; /* sentence terminators */
+ if (j != '\n')
+ goto g0;
+ wp = wordp-1; /* handle extra space at end of sentence */
+ while (wp >= word) {
+ j = cbits(*wp--);
+ if (j=='"' || j=='\'' || j==')' || j==']' || j=='*' || j==DAGGER)
+ continue;
+ for (k = 0; sentchar[k]; k++)
+ if (j == sentchar[k]) {
+ spflg++;
+ break;
+ }
+ break;
+ }
+ }
+ *wordp = 0;
+ numtabp[HP].val += sps;
+rtn:
+ for (wp = word; *wp; wp++) {
+ if (ismot(j))
+ break; /* drechsler */
+ j = cbits(*wp);
+ if (j == ' ')
+ continue;
+ if (!(isascii(j) && isdigit(j)) && j != '-')
+ break;
+ }
+ if (*wp == 0) /* all numbers, so don't hyphenate */
+ hyoff = 1;
+ wdstart = 0;
+ wordp = word;
+ pendw = 0;
+ *hyp++ = 0;
+ setnel();
+ return(noword);
+}
+
+
+void storeword(Tchar c, int w)
+{
+ Tchar *savp;
+ int i;
+
+ if (wordp >= word + wdsize - 2) {
+ wdsize += WDSIZE;
+ savp = word;
+ if (( word = (Tchar *)realloc((char *)word, wdsize * sizeof(Tchar))) != NULL) {
+ if (wordp)
+ wordp = word + (wordp - savp);
+ if (pendw)
+ pendw = word + (pendw - savp);
+ if (wdstart)
+ wdstart = word + (wdstart - savp);
+ if (wdend)
+ wdend = word + (wdend - savp);
+ for (i = 0; i < NHYP; i++)
+ if (hyptr[i])
+ hyptr[i] = word + (hyptr[i] - savp);
+ } else {
+ if (over) {
+ return;
+ } else {
+ flusho();
+ ERROR "Word overflow." WARN;
+ over++;
+ c = LEFTHAND;
+ w = width(LEFTHAND);
+ }
+ }
+ }
+ widthp = w;
+ wne += w;
+ *wordp++ = c;
+ wch++;
+}
+
+
+Tchar gettch(void)
+{
+ extern int c_isalnum;
+ Tchar i;
+ int j;
+
+ if (TROFF)
+ return getch();
+
+ i = getch();
+ j = cbits(i);
+ if (ismot(i) || fbits(i) != ulfont)
+ return(i);
+ if (cu) {
+ if (trtab[j] == ' ') {
+ setcbits(i, '_');
+ setfbits(i, FT); /* default */
+ }
+ return(i);
+ }
+ /* should test here for characters that ought to be underlined */
+ /* in the old nroff, that was the 200 bit on the width! */
+ /* for now, just do letters, digits and certain special chars */
+ if (j <= 127) {
+ if (!isalnum(j))
+ setfbits(i, FT);
+ } else {
+ if (j < c_isalnum)
+ setfbits(i, FT);
+ }
+ return(i);
+}
diff --git a/src/cmd/troff/n8.c b/src/cmd/troff/n8.c
new file mode 100644
index 00000000..d1be5080
--- /dev/null
+++ b/src/cmd/troff/n8.c
@@ -0,0 +1,540 @@
+#include "tdef.h"
+#include "fns.h"
+#include "ext.h"
+
+#define HY_BIT 0200 /* stuff in here only works for 7-bit ascii */
+ /* this value is used (as a literal) in suftab.c */
+ /* to encode possible hyphenation points in suffixes. */
+ /* it could be changed, by widening the tables */
+ /* to be shorts instead of chars. */
+
+/*
+ * troff8.c
+ *
+ * hyphenation
+ */
+
+int hexsize = 0; /* hyphenation exception list size */
+char *hbufp = NULL; /* base of list */
+char *nexth = NULL; /* first free slot in list */
+Tchar *hyend;
+
+#define THRESH 160 /* digram goodness threshold */
+int thresh = THRESH;
+
+int texhyphen(void);
+static int alpha(Tchar);
+
+void hyphen(Tchar *wp)
+{
+ int j;
+ Tchar *i;
+
+ i = wp;
+ while (punct((*i++)))
+ ;
+ if (!alpha(*--i))
+ return;
+ wdstart = i++;
+ while (alpha(*i++))
+ ;
+ hyend = wdend = --i - 1;
+ while (punct((*i++)))
+ ;
+ if (*--i)
+ return;
+ if (wdend - wdstart < 4) /* 4 chars is too short to hyphenate */
+ return;
+ hyp = hyptr;
+ *hyp = 0;
+ hyoff = 2;
+
+ /* for now, try exceptions first, then tex (if hyphalg is non-zero),
+ then suffix and digram if tex didn't hyphenate it at all.
+ */
+
+ if (!exword() && !texhyphen() && !suffix())
+ digram();
+
+ /* this appears to sort hyphenation points into increasing order */
+ *hyp++ = 0;
+ if (*hyptr)
+ for (j = 1; j; ) {
+ j = 0;
+ for (hyp = hyptr + 1; *hyp != 0; hyp++) {
+ if (*(hyp - 1) > *hyp) {
+ j++;
+ i = *hyp;
+ *hyp = *(hyp - 1);
+ *(hyp - 1) = i;
+ }
+ }
+ }
+}
+
+static alpha(Tchar i) /* non-zero if really alphabetic */
+{
+ if (ismot(i))
+ return 0;
+ else if (cbits(i) >= ALPHABET) /* this isn't very elegant, but there's */
+ return 0; /* no good way to make sure i is in range for */
+ else /* the call of isalpha */
+ return isalpha(cbits(i));
+}
+
+
+punct(Tchar i)
+{
+ if (!i || alpha(i))
+ return(0);
+ else
+ return(1);
+}
+
+
+void caseha(void) /* set hyphenation algorithm */
+{
+ hyphalg = HYPHALG;
+ if (skip())
+ return;
+ noscale++;
+ hyphalg = atoi0();
+ noscale = 0;
+}
+
+
+void caseht(void) /* set hyphenation threshold; not in manual! */
+{
+ thresh = THRESH;
+ if (skip())
+ return;
+ noscale++;
+ thresh = atoi0();
+ noscale = 0;
+}
+
+
+char *growh(char *where)
+{
+ char *new;
+
+ hexsize += NHEX;
+ if ((new = grow(hbufp, hexsize, sizeof(char))) == NULL)
+ return NULL;
+ if (new == hbufp) {
+ return where;
+ } else {
+ int diff;
+ diff = where - hbufp;
+ hbufp = new;
+ return new + diff;
+ }
+}
+
+
+void casehw(void)
+{
+ int i, k;
+ char *j;
+ Tchar t;
+
+ if (nexth == NULL) {
+ if ((nexth = hbufp = grow(hbufp, NHEX, sizeof(char))) == NULL) {
+ ERROR "No space for exception word list." WARN;
+ return;
+ }
+ hexsize = NHEX;
+ }
+ k = 0;
+ while (!skip()) {
+ if ((j = nexth) >= hbufp + hexsize - 2)
+ if ((j = nexth = growh(j)) == NULL)
+ goto full;
+ for (;;) {
+ if (ismot(t = getch()))
+ continue;
+ i = cbits(t);
+ if (i == ' ' || i == '\n') {
+ *j++ = 0;
+ nexth = j;
+ *j = 0;
+ if (i == ' ')
+ break;
+ else
+ return;
+ }
+ if (i == '-') {
+ k = HY_BIT;
+ continue;
+ }
+ *j++ = maplow(i) | k;
+ k = 0;
+ if (j >= hbufp + hexsize - 2)
+ if ((j = growh(j)) == NULL)
+ goto full;
+ }
+ }
+ return;
+full:
+ ERROR "Cannot grow exception word list." WARN;
+ *nexth = 0;
+}
+
+
+int exword(void)
+{
+ Tchar *w;
+ char *e, *save;
+
+ e = hbufp;
+ while (1) {
+ save = e;
+ if (e == NULL || *e == 0)
+ return(0);
+ w = wdstart;
+ while (*e && w <= hyend && (*e & 0177) == maplow(cbits(*w))) {
+ e++;
+ w++;
+ }
+ if (!*e) {
+ if (w-1 == hyend || (w == wdend && maplow(cbits(*w)) == 's')) {
+ w = wdstart;
+ for (e = save; *e; e++) {
+ if (*e & HY_BIT)
+ *hyp++ = w;
+ if (hyp > hyptr + NHYP - 1)
+ hyp = hyptr + NHYP - 1;
+ w++;
+ }
+ return(1);
+ } else {
+ e++;
+ continue;
+ }
+ } else
+ while (*e++)
+ ;
+ }
+}
+
+
+suffix(void)
+{
+ Tchar *w;
+ char *s, *s0;
+ Tchar i;
+ extern char *suftab[];
+
+again:
+ i = cbits(*hyend);
+ if (!alpha(i))
+ return(0);
+ if (i < 'a')
+ i -= 'A' - 'a';
+ if ((s0 = suftab[i-'a']) == 0)
+ return(0);
+ for (;;) {
+ if ((i = *s0 & 017) == 0)
+ return(0);
+ s = s0 + i - 1;
+ w = hyend - 1;
+ while (s > s0 && w >= wdstart && (*s & 0177) == maplow(cbits(*w))) {
+ s--;
+ w--;
+ }
+ if (s == s0)
+ break;
+ s0 += i;
+ }
+ s = s0 + i - 1;
+ w = hyend;
+ if (*s0 & HY_BIT)
+ goto mark;
+ while (s > s0) {
+ w--;
+ if (*s-- & HY_BIT) {
+mark:
+ hyend = w - 1;
+ if (*s0 & 0100) /* 0100 used in suftab to encode something too */
+ continue;
+ if (!chkvow(w))
+ return(0);
+ *hyp++ = w;
+ }
+ }
+ if (*s0 & 040)
+ return(0);
+ if (exword())
+ return(1);
+ goto again;
+}
+
+
+maplow(int i)
+{
+ if (isupper(i))
+ i = tolower(i);
+ return(i);
+}
+
+
+vowel(int i)
+{
+ switch (i) {
+ case 'a': case 'A':
+ case 'e': case 'E':
+ case 'i': case 'I':
+ case 'o': case 'O':
+ case 'u': case 'U':
+ case 'y': case 'Y':
+ return(1);
+ default:
+ return(0);
+ }
+}
+
+
+Tchar *chkvow(Tchar *w)
+{
+ while (--w >= wdstart)
+ if (vowel(cbits(*w)))
+ return(w);
+ return(0);
+}
+
+
+void digram(void)
+{
+ Tchar *w;
+ int val;
+ Tchar *nhyend, *maxw;
+ int maxval;
+ extern char bxh[26][13], bxxh[26][13], xxh[26][13], xhx[26][13], hxx[26][13];
+
+again:
+ if (!(w = chkvow(hyend + 1)))
+ return;
+ hyend = w;
+ if (!(w = chkvow(hyend)))
+ return;
+ nhyend = w;
+ maxval = 0;
+ w--;
+ while (++w < hyend && w < wdend - 1) {
+ val = 1;
+ if (w == wdstart)
+ val *= dilook('a', cbits(*w), bxh);
+ else if (w == wdstart + 1)
+ val *= dilook(cbits(*(w-1)), cbits(*w), bxxh);
+ else
+ val *= dilook(cbits(*(w-1)), cbits(*w), xxh);
+ val *= dilook(cbits(*w), cbits(*(w+1)), xhx);
+ val *= dilook(cbits(*(w+1)), cbits(*(w+2)), hxx);
+ if (val > maxval) {
+ maxval = val;
+ maxw = w + 1;
+ }
+ }
+ hyend = nhyend;
+ if (maxval > thresh)
+ *hyp++ = maxw;
+ goto again;
+}
+
+
+dilook(int a, int b, char t[26][13])
+{
+ int i, j;
+
+ i = t[maplow(a)-'a'][(j = maplow(b)-'a')/2];
+ if (!(j & 01))
+ i >>= 4;
+ return(i & 017);
+}
+
+
+/* here beginneth the tex hyphenation code, as interpreted freely */
+/* the main difference is that there is no attempt to squeeze space */
+/* as tightly at tex does. */
+
+static int texit(Tchar *, Tchar *);
+static int readpats(void);
+static void install(char *);
+static void fixup(void);
+static int trieindex(int, int);
+
+static char pats[50000]; /* size ought to be computed dynamically */
+static char *nextpat = pats;
+static char *trie[27*27]; /* english-specific sizes */
+
+int texhyphen(void)
+{
+ static int loaded = 0; /* -1: couldn't find tex file */
+
+ if (hyphalg == 0 || loaded == -1) /* non-zero => tex for now */
+ return 0;
+ if (loaded == 0) {
+ if (readpats())
+ loaded = 1;
+ else
+ loaded = -1;
+ }
+ return texit(wdstart, wdend);
+}
+
+static int texit(Tchar *start, Tchar *end) /* hyphenate as in tex, return # found */
+{
+ int nw, i, k, equal, cnt[500];
+ char w[500+1], *np, *pp, *wp, *xpp, *xwp;
+
+ w[0] = '.';
+ for (nw = 1; start <= end && nw < 500-1; nw++, start++)
+ w[nw] = maplow(tolower(cbits(*start)));
+ start -= (nw - 1);
+ w[nw++] = '.';
+ w[nw] = 0;
+/*
+ * printf("try %s\n", w);
+*/
+ for (i = 0; i <= nw; i++)
+ cnt[i] = '0';
+
+ for (wp = w; wp < w + nw; wp++) {
+ for (pp = trie[trieindex(*wp, *(wp+1))]; pp < nextpat; ) {
+ if (pp == 0 /* no trie entry */
+ || *pp != *wp /* no match on 1st letter */
+ || *(pp+1) != *(wp+1)) /* no match on 2nd letter */
+ break; /* so move to next letter of word */
+ equal = 1;
+ for (xpp = pp+2, xwp = wp+2; *xpp; )
+ if (*xpp++ != *xwp++) {
+ equal = 0;
+ break;
+ }
+ if (equal) {
+ np = xpp+1; /* numpat */
+ for (k = wp-w; *np; k++, np++)
+ if (*np > cnt[k])
+ cnt[k] = *np;
+/*
+ * printf("match: %s %s\n", pp, xpp+1);
+*/
+ }
+ pp += *(pp-1); /* skip over pattern and numbers to next */
+ }
+ }
+/*
+ * for (i = 0; i < nw; i++) printf("%c", w[i]);
+ * printf(" ");
+ * for (i = 0; i <= nw; i++) printf("%c", cnt[i]);
+ * printf("\n");
+*/
+/*
+ * for (i = 1; i < nw - 1; i++) {
+ * if (i > 2 && i < nw - 3 && cnt[i] % 2)
+ * printf("-");
+ * if (cbits(start[i-1]) != '.')
+ * printf("%c", cbits(start[i-1]));
+ * }
+ * printf("\n");
+*/
+ for (i = 1; i < nw -1; i++)
+ if (i > 2 && i < nw - 3 && cnt[i] % 2)
+ *hyp++ = start + i - 1;
+ return hyp - hyptr; /* non-zero if a hyphen was found */
+}
+
+/*
+ This code assumes that hyphen.tex looks like
+ % some comments
+ \patterns{ % more comments
+ pat5ter4ns, 1 per line, SORTED, nothing else
+ }
+ more goo
+ \hyphenation{ % more comments
+ ex-cep-tions, one per line; i ignore this part for now
+ }
+
+ this code is NOT robust against variations. unfortunately,
+ it looks like every local language version of this file has
+ a different format. i have also made no provision for weird
+ characters. sigh.
+*/
+
+static int readpats(void)
+{
+ FILE *fp;
+ char buf[200], buf1[200];
+
+ if ((fp = fopen(unsharp(TEXHYPHENS), "r")) == NULL
+ && (fp = fopen(unsharp(DWBalthyphens), "r")) == NULL) {
+ ERROR "warning: can't find hyphen.tex" WARN;
+ return 0;
+ }
+
+ while (fgets(buf, sizeof buf, fp) != NULL) {
+ sscanf(buf, "%s", buf1);
+ if (strcmp(buf1, "\\patterns{") == 0)
+ break;
+ }
+ while (fgets(buf, sizeof buf, fp) != NULL) {
+ if (buf[0] == '}')
+ break;
+ install(buf);
+ }
+ fclose(fp);
+ fixup();
+ return 1;
+}
+
+static void install(char *s) /* map ab4c5de to: 12 abcde \0 00405 \0 */
+{
+ int npat, lastpat;
+ char num[500], *onextpat = nextpat;
+
+ num[0] = '0';
+ *nextpat++ = ' '; /* fill in with count later */
+ for (npat = lastpat = 0; *s != '\n' && *s != '\0'; s++) {
+ if (isdigit(*s)) {
+ num[npat] = *s;
+ lastpat = npat;
+ } else {
+ *nextpat++ = *s;
+ npat++;
+ num[npat] = '0';
+ }
+ }
+ *nextpat++ = 0;
+ if (nextpat > pats + sizeof(pats)-20) {
+ ERROR "tex hyphenation table overflow, tail end ignored" WARN;
+ nextpat = onextpat;
+ }
+ num[lastpat+1] = 0;
+ strcat(nextpat, num);
+ nextpat += strlen(nextpat) + 1;
+}
+
+static void fixup(void) /* build indexes of where . a b c ... start */
+{
+ char *p, *lastc;
+ int n;
+
+ for (lastc = pats, p = pats+1; p < nextpat; p++)
+ if (*p == ' ') {
+ *lastc = p - lastc;
+ lastc = p;
+ }
+ *lastc = p - lastc;
+ for (p = pats+1; p < nextpat; ) {
+ n = trieindex(p[0], p[1]);
+ if (trie[n] == 0)
+ trie[n] = p;
+ p += p[-1];
+ }
+ /* printf("pats = %d\n", nextpat - pats); */
+}
+
+static int trieindex(int d1, int d2)
+{
+ return 27 * (d1 == '.' ? 0 : d1 - 'a' + 1) + (d2 == '.' ? 0 : d2 - 'a' + 1);
+}
diff --git a/src/cmd/troff/n9.c b/src/cmd/troff/n9.c
new file mode 100644
index 00000000..5cd70648
--- /dev/null
+++ b/src/cmd/troff/n9.c
@@ -0,0 +1,488 @@
+#include "tdef.h"
+#include "ext.h"
+#include "fns.h"
+
+/*
+ * troff9.c
+ *
+ * misc functions
+ */
+
+Tchar setz(void)
+{
+ Tchar i;
+
+ if (!ismot(i = getch()))
+ i |= ZBIT;
+ return(i);
+}
+
+void setline(void)
+{
+ Tchar *i;
+ Tchar c;
+ int length;
+ int j, w, cnt, delim, rem, temp;
+ Tchar linebuf[NC];
+
+ if (ismot(c = getch()))
+ return;
+ delim = cbits(c);
+ vflag = 0;
+ dfact = EM;
+ length = quant(atoi0(), HOR);
+ dfact = 1;
+ if (!length) {
+ eat(delim);
+ return;
+ }
+s0:
+ if ((j = cbits(c = getch())) == delim || j == '\n') {
+ ch = c;
+ c = RULE | chbits;
+ } else if (cbits(c) == FILLER)
+ goto s0;
+ w = width(c);
+ if (w <= 0) {
+ ERROR "zero-width underline character ignored" WARN;
+ c = RULE | chbits;
+ w = width(c);
+ }
+ i = linebuf;
+ if (length < 0) {
+ *i++ = makem(length);
+ length = -length;
+ }
+ if (!(cnt = length / w)) {
+ *i++ = makem(-(temp = ((w - length) / 2)));
+ *i++ = c;
+ *i++ = makem(-(w - length - temp));
+ goto s1;
+ }
+ if (rem = length % w) {
+ if (cbits(c) == RULE || cbits(c) == UNDERLINE || cbits(c) == ROOTEN)
+ *i++ = c | ZBIT;
+ *i++ = makem(rem);
+ }
+ if (cnt) {
+ *i++ = RPT;
+ *i++ = cnt;
+ *i++ = c;
+ }
+s1:
+ *i = 0;
+ eat(delim);
+ pushback(linebuf);
+}
+
+
+eat(int c)
+{
+ int i;
+
+ while ((i = cbits(getch())) != c && i != '\n')
+ ;
+ return(i);
+}
+
+
+void setov(void)
+{
+ int j, k;
+ Tchar i, o[NOV+1];
+ int delim, w[NOV+1];
+
+ if (ismot(i = getch()))
+ return;
+ delim = cbits(i);
+ for (k = 0; k < NOV && (j = cbits(i = getch())) != delim && j != '\n'; k++) {
+ o[k] = i;
+ w[k] = width(i);
+ }
+ o[k] = w[k] = 0;
+ if (o[0])
+ for (j = 1; j; ) {
+ j = 0;
+ for (k = 1; o[k] ; k++) {
+ if (w[k-1] < w[k]) {
+ j++;
+ i = w[k];
+ w[k] = w[k-1];
+ w[k-1] = i;
+ i = o[k];
+ o[k] = o[k-1];
+ o[k-1] = i;
+ }
+ }
+ }
+ else
+ return;
+ *pbp++ = makem(w[0] / 2);
+ for (k = 0; o[k]; k++)
+ ;
+ while (k>0) {
+ k--;
+ *pbp++ = makem(-((w[k] + w[k+1]) / 2));
+ *pbp++ = o[k];
+ }
+}
+
+
+void setbra(void)
+{
+ int k;
+ Tchar i, *j, dwn;
+ int cnt, delim;
+ Tchar brabuf[NC];
+
+ if (ismot(i = getch()))
+ return;
+ delim = cbits(i);
+ j = brabuf + 1;
+ cnt = 0;
+ if (NROFF)
+ dwn = (2 * t.Halfline) | MOT | VMOT;
+ else
+ dwn = EM | MOT | VMOT;
+ while ((k = cbits(i = getch())) != delim && k != '\n' && j <= brabuf + NC - 4) {
+ *j++ = i | ZBIT;
+ *j++ = dwn;
+ cnt++;
+ }
+ if (--cnt < 0)
+ return;
+ else if (!cnt) {
+ ch = *(j - 2);
+ return;
+ }
+ *j = 0;
+ if (NROFF)
+ *--j = *brabuf = (cnt * t.Halfline) | MOT | NMOT | VMOT;
+ else
+ *--j = *brabuf = (cnt * EM) / 2 | MOT | NMOT | VMOT;
+ *--j &= ~ZBIT;
+ pushback(brabuf);
+}
+
+
+void setvline(void)
+{
+ int i;
+ Tchar c, rem, ver, neg;
+ int cnt, delim, v;
+ Tchar vlbuf[NC];
+ Tchar *vlp;
+
+ if (ismot(c = getch()))
+ return;
+ delim = cbits(c);
+ dfact = lss;
+ vflag++;
+ i = quant(atoi0(), VERT);
+ dfact = 1;
+ if (!i) {
+ eat(delim);
+ vflag = 0;
+ return;
+ }
+ if ((cbits(c = getch())) == delim) {
+ c = BOXRULE | chbits; /*default box rule*/
+ } else
+ getch();
+ c |= ZBIT;
+ neg = 0;
+ if (i < 0) {
+ i = -i;
+ neg = NMOT;
+ }
+ if (NROFF)
+ v = 2 * t.Halfline;
+ else {
+ v = EM;
+ if (v < VERT) /* ATT EVK hack: Erik van Konijnenburg, */
+ v = VERT; /* hvlpb!evkonij, ATT NSI Hilversum, Holland */
+ }
+
+ cnt = i / v;
+ rem = makem(i % v) | neg;
+ ver = makem(v) | neg;
+ vlp = vlbuf;
+ if (!neg)
+ *vlp++ = ver;
+ if (absmot(rem) != 0) {
+ *vlp++ = c;
+ *vlp++ = rem;
+ }
+ while (vlp < vlbuf + NC - 3 && cnt--) {
+ *vlp++ = c;
+ *vlp++ = ver;
+ }
+ *(vlp - 2) &= ~ZBIT;
+ if (!neg)
+ vlp--;
+ *vlp = 0;
+ pushback(vlbuf);
+ vflag = 0;
+}
+
+#define NPAIR (NC/2-6) /* max pairs in spline, etc. */
+
+void setdraw(void) /* generate internal cookies for a drawing function */
+{
+ int i, j, k, dx[NPAIR], dy[NPAIR], delim, type;
+ Tchar c, drawbuf[NC];
+ int drawch = '.'; /* character to draw with */
+
+ /* input is \D'f dx dy dx dy ... c' (or at least it had better be) */
+ /* this does drawing function f with character c and the */
+ /* specified dx,dy pairs interpreted as appropriate */
+ /* pairs are deltas from last point, except for radii */
+
+ /* l dx dy: line from here by dx,dy */
+ /* c x: circle of diameter x, left side here */
+ /* e x y: ellipse of diameters x,y, left side here */
+ /* a dx1 dy1 dx2 dy2:
+ ccw arc: ctr at dx1,dy1, then end at dx2,dy2 from there */
+ /* ~ dx1 dy1 dx2 dy2...:
+ spline to dx1,dy1 to dx2,dy2 ... */
+ /* b x c:
+ built-up character of type c, ht x */
+ /* f dx dy ...: f is any other char: like spline */
+
+ if (ismot(c = getch()))
+ return;
+ delim = cbits(c);
+ numerr.escarg = type = cbits(getch());
+ if (type == '~') /* head off the .tr ~ problem */
+ type = 's';
+ for (i = 0; i < NPAIR ; i++) {
+ skip();
+ vflag = 0;
+ dfact = EM;
+ dx[i] = quant(atoi0(), HOR);
+ if (dx[i] > MAXMOT)
+ dx[i] = MAXMOT;
+ else if (dx[i] < -MAXMOT)
+ dx[i] = -MAXMOT;
+ skip();
+ if (type == 'c') {
+ dy[i] = 0;
+ goto eat;
+ }
+ vflag = 1;
+ dfact = lss;
+ dy[i] = quant(atoi0(), VERT);
+ if (dy[i] > MAXMOT)
+ dy[i] = MAXMOT;
+ else if (dy[i] < -MAXMOT)
+ dy[i] = -MAXMOT;
+eat:
+ if (cbits(c = getch()) != ' ') { /* must be the end */
+ if (cbits(c) != delim) {
+ drawch = cbits(c);
+ getch();
+ }
+ i++;
+ break;
+ }
+ }
+ dfact = 1;
+ vflag = 0;
+ if (TROFF) {
+ drawbuf[0] = DRAWFCN | chbits | ZBIT;
+ drawbuf[1] = type | chbits | ZBIT;
+ drawbuf[2] = drawch | chbits | ZBIT;
+ for (k = 0, j = 3; k < i; k++) {
+ drawbuf[j++] = MOT | ((dx[k] >= 0) ? dx[k] : (NMOT | -dx[k]));
+ drawbuf[j++] = MOT | VMOT | ((dy[k] >= 0) ? dy[k] : (NMOT | -dy[k]));
+ }
+ if (type == DRAWELLIPSE) {
+ drawbuf[5] = drawbuf[4] | NMOT; /* so the net vertical is zero */
+ j = 6;
+ } else if (type == DRAWBUILD) {
+ drawbuf[4] = drawbuf[3] | NMOT; /* net horizontal motion is zero */
+ drawbuf[2] &= ~ZBIT; /* width taken from drawing char */
+ j = 5;
+ }
+ drawbuf[j++] = DRAWFCN | chbits | ZBIT; /* marks end for ptout */
+ drawbuf[j] = 0;
+ pushback(drawbuf);
+ }
+}
+
+
+void casefc(void)
+{
+ int i;
+ Tchar j;
+
+ gchtab[fc] &= ~FCBIT;
+ fc = IMP;
+ padc = ' ';
+ if (skip() || ismot(j = getch()) || (i = cbits(j)) == '\n')
+ return;
+ fc = i;
+ gchtab[fc] |= FCBIT;
+ if (skip() || ismot(ch) || (ch = cbits(ch)) == fc)
+ return;
+ padc = ch;
+}
+
+
+Tchar setfield(int x)
+{
+ Tchar ii, jj, *fp;
+ int i, j;
+ int length, ws, npad, temp, type;
+ Tchar **pp, *padptr[NPP];
+ Tchar fbuf[FBUFSZ];
+ int savfc, savtc, savlc;
+ Tchar rchar;
+ int savepos;
+ static Tchar wbuf[] = { WORDSP, 0};
+
+ if (x == tabch)
+ rchar = tabc | chbits;
+ else if (x == ldrch)
+ rchar = dotc | chbits;
+ temp = npad = ws = 0;
+ savfc = fc;
+ savtc = tabch;
+ savlc = ldrch;
+ tabch = ldrch = fc = IMP;
+ savepos = numtabp[HP].val;
+ gchtab[tabch] &= ~TABBIT;
+ gchtab[ldrch] &= ~LDRBIT;
+ gchtab[fc] &= ~FCBIT;
+ gchtab[IMP] |= TABBIT|LDRBIT|FCBIT;
+ for (j = 0; ; j++) {
+ if ((tabtab[j] & TABMASK) == 0) {
+ if (x == savfc)
+ ERROR "zero field width." WARN;
+ jj = 0;
+ goto rtn;
+ }
+ if ((length = ((tabtab[j] & TABMASK) - numtabp[HP].val)) > 0 )
+ break;
+ }
+ type = tabtab[j] & ~TABMASK;
+ fp = fbuf;
+ pp = padptr;
+ if (x == savfc) {
+ while (1) {
+ j = cbits(ii = getch());
+ jj = width(ii);
+ widthp = jj;
+ numtabp[HP].val += jj;
+ if (j == padc) {
+ npad++;
+ *pp++ = fp;
+ if (pp > padptr + NPP - 1)
+ break;
+ goto s1;
+ } else if (j == savfc)
+ break;
+ else if (j == '\n') {
+ temp = j;
+ if (nlflg && ip == 0) {
+ numtabp[CD].val--;
+ nlflg = 0;
+ }
+ break;
+ }
+ ws += jj;
+s1:
+ *fp++ = ii;
+ if (fp > fbuf + FBUFSZ - 3)
+ break;
+ }
+ if (ws)
+ *fp++ = WORDSP;
+ if (!npad) {
+ npad++;
+ *pp++ = fp;
+ *fp++ = 0;
+ }
+ *fp++ = temp;
+ *fp = 0;
+ temp = i = (j = length - ws) / npad;
+ i = (i / HOR) * HOR;
+ if ((j -= i * npad) < 0)
+ j = -j;
+ ii = makem(i);
+ if (temp < 0)
+ ii |= NMOT;
+ for (; npad > 0; npad--) {
+ *(*--pp) = ii;
+ if (j) {
+ j -= HOR;
+ (*(*pp)) += HOR;
+ }
+ }
+ pushback(fbuf);
+ jj = 0;
+ } else if (type == 0) {
+ /*plain tab or leader*/
+ if ((j = width(rchar)) > 0) {
+ int nchar = length / j;
+ while (nchar-->0 && pbp < &pbbuf[NC-3]) {
+ numtabp[HP].val += j;
+ widthp = j;
+ *pbp++ = rchar;
+ }
+ length %= j;
+ }
+ if (length)
+ jj = length | MOT;
+ else
+ jj = getch0();
+ if (savepos > 0)
+ pushback(wbuf);
+ } else {
+ /*center tab*/
+ /*right tab*/
+ while ((j = cbits(ii = getch())) != savtc && j != '\n' && j != savlc) {
+ jj = width(ii);
+ ws += jj;
+ numtabp[HP].val += jj;
+ widthp = jj;
+ *fp++ = ii;
+ if (fp > fbuf + FBUFSZ - 3)
+ break;
+ }
+ *fp++ = ii;
+ *fp = 0;
+ if (type == RTAB)
+ length -= ws;
+ else
+ length -= ws / 2; /*CTAB*/
+ pushback(fbuf);
+ if ((j = width(rchar)) != 0 && length > 0) {
+ int nchar = length / j;
+ while (nchar-- > 0 && pbp < &pbbuf[NC-3])
+ *pbp++ = rchar;
+ length %= j;
+ }
+ if (savepos > 0)
+ pushback(wbuf);
+ length = (length / HOR) * HOR;
+ jj = makem(length);
+ if (nlflg) {
+ if (ip == 0)
+ numtabp[CD].val--;
+ nlflg = 0;
+ }
+ }
+rtn:
+ gchtab[fc] &= ~FCBIT;
+ gchtab[tabch] &= ~TABBIT;
+ gchtab[ldrch] &= ~LDRBIT;
+ fc = savfc;
+ tabch = savtc;
+ ldrch = savlc;
+ gchtab[fc] |= FCBIT;
+ gchtab[tabch] = TABBIT;
+ gchtab[ldrch] |= LDRBIT;
+ numtabp[HP].val = savepos;
+ return(jj);
+}
diff --git a/src/cmd/troff/ni.c b/src/cmd/troff/ni.c
new file mode 100644
index 00000000..a80cec64
--- /dev/null
+++ b/src/cmd/troff/ni.c
@@ -0,0 +1,390 @@
+#include <stdio.h>
+#include "tdef.h"
+#include "fns.h"
+#include "ext.h"
+
+char termtab[NS]; /* term type added in ptinit() */
+char fontdir[NS]; /* added in casefp; not used by nroff */
+char devname[20]; /* default output device */
+
+Numtab numtab[NN] = {
+ { PAIR('%', 0) },
+ { PAIR('n', 'l') },
+ { PAIR('y', 'r') },
+ { PAIR('h', 'p') },
+ { PAIR('c', 't') },
+ { PAIR('d', 'n') },
+ { PAIR('m', 'o') },
+ { PAIR('d', 'y') },
+ { PAIR('d', 'w') },
+ { PAIR('l', 'n') },
+ { PAIR('d', 'l') },
+ { PAIR('s', 't') },
+ { PAIR('s', 'b') },
+ { PAIR('c', '.') },
+ { PAIR('$', '$') },
+};
+
+
+int alphabet = 256; /* latin-1 */
+int pto = 10000;
+int pfrom = 1;
+int print = 1;
+char nextf[NS] = TMACDIR;
+char mfiles[NMF][NS];
+int nmfi = 0;
+int oldbits = -1;
+int init = 1;
+int fc = IMP; /* field character */
+int eschar = '\\';
+int pl;
+int po;
+FILE *ptid;
+
+int dfact = 1;
+int dfactd = 1;
+int res = 1;
+int smnt = 0; /* beginning of special fonts */
+int ascii = 0; /* ascii normally off for troff, on for nroff; -a turns on */
+int lg;
+int pnlist[NPN] = { -1 };
+
+
+int *pnp = pnlist;
+int npn = 1;
+int npnflg = 1;
+int dpn = -1;
+int totout = 1;
+int ulfont = ULFONT;
+int tabch = TAB;
+int ldrch = LEADER;
+
+
+Contab contab[NM] = {
+ C(PAIR('d', 's'), caseds),
+ C(PAIR('a', 's'), caseas),
+ C(PAIR('s', 'p'), casesp),
+ C(PAIR('f', 't'), caseft),
+ C(PAIR('p', 's'), caseps),
+ C(PAIR('v', 's'), casevs),
+ C(PAIR('n', 'r'), casenr),
+ C(PAIR('i', 'f'), caseif),
+ C(PAIR('i', 'e'), caseie),
+ C(PAIR('e', 'l'), caseel),
+ C(PAIR('p', 'o'), casepo),
+ C(PAIR('t', 'l'), casetl),
+ C(PAIR('t', 'm'), casetm),
+ C(PAIR('f', 'm'), casefm),
+ C(PAIR('b', 'p'), casebp),
+ C(PAIR('c', 'h'), casech),
+ C(PAIR('p', 'n'), casepn),
+ C(PAIR('b', 'r'), tbreak),
+ C(PAIR('t', 'i'), caseti),
+ C(PAIR('n', 'e'), casene),
+ C(PAIR('n', 'f'), casenf),
+ C(PAIR('c', 'e'), casece),
+ C(PAIR('f', 'i'), casefi),
+ C(PAIR('i', 'n'), casein),
+ C(PAIR('l', 'l'), casell),
+ C(PAIR('n', 's'), casens),
+ C(PAIR('m', 'k'), casemk),
+ C(PAIR('r', 't'), casert),
+ C(PAIR('a', 'm'), caseam),
+ C(PAIR('d', 'e'), casede),
+ C(PAIR('d', 'i'), casedi),
+ C(PAIR('d', 'a'), caseda),
+ C(PAIR('w', 'h'), casewh),
+ C(PAIR('d', 't'), casedt),
+ C(PAIR('i', 't'), caseit),
+ C(PAIR('r', 'm'), caserm),
+ C(PAIR('r', 'r'), caserr),
+ C(PAIR('r', 'n'), casern),
+ C(PAIR('a', 'd'), casead),
+ C(PAIR('r', 's'), casers),
+ C(PAIR('n', 'a'), casena),
+ C(PAIR('p', 'l'), casepl),
+ C(PAIR('t', 'a'), caseta),
+ C(PAIR('t', 'r'), casetr),
+ C(PAIR('u', 'l'), caseul),
+ C(PAIR('c', 'u'), casecu),
+ C(PAIR('l', 't'), caselt),
+ C(PAIR('n', 'x'), casenx),
+ C(PAIR('s', 'o'), caseso),
+ C(PAIR('i', 'g'), caseig),
+ C(PAIR('t', 'c'), casetc),
+ C(PAIR('f', 'c'), casefc),
+ C(PAIR('e', 'c'), caseec),
+ C(PAIR('e', 'o'), caseeo),
+ C(PAIR('l', 'c'), caselc),
+ C(PAIR('e', 'v'), caseev),
+ C(PAIR('r', 'd'), caserd),
+ C(PAIR('a', 'b'), caseab),
+ C(PAIR('f', 'l'), casefl),
+ C(PAIR('e', 'x'), caseex),
+ C(PAIR('s', 's'), casess),
+ C(PAIR('f', 'p'), casefp),
+ C(PAIR('c', 's'), casecs),
+ C(PAIR('b', 'd'), casebd),
+ C(PAIR('l', 'g'), caselg),
+ C(PAIR('h', 'c'), casehc),
+ C(PAIR('h', 'y'), casehy),
+ C(PAIR('n', 'h'), casenh),
+ C(PAIR('n', 'm'), casenm),
+ C(PAIR('n', 'n'), casenn),
+ C(PAIR('s', 'v'), casesv),
+ C(PAIR('o', 's'), caseos),
+ C(PAIR('l', 's'), casels),
+ C(PAIR('c', 'c'), casecc),
+ C(PAIR('c', '2'), casec2),
+ C(PAIR('e', 'm'), caseem),
+ C(PAIR('a', 'f'), caseaf),
+ C(PAIR('h', 'a'), caseha),
+ C(PAIR('h', 'w'), casehw),
+ C(PAIR('m', 'c'), casemc),
+ C(PAIR('p', 'm'), casepm),
+ C(PAIR('p', 'i'), casepi),
+ C(PAIR('u', 'f'), caseuf),
+ C(PAIR('p', 'c'), casepc),
+ C(PAIR('h', 't'), caseht),
+ C(PAIR('c', 'f'), casecf),
+ C(PAIR('s', 'y'), casesy),
+ C(PAIR('l', 'f'), caself),
+ C(PAIR('p', 't'), casept),
+ C(PAIR('g', 'd'), casegd),
+};
+
+
+Tbuf _oline;
+
+/*
+ * troff environment block
+ */
+
+Env env[NEV] = { { /* this sets up env[0] */
+/* int ics */ 0, /* insertion character space, set by .mc */
+/* int sps */ 0,
+/* int spacesz */ 0,
+/* int lss */ 0,
+/* int lss1 */ 0,
+/* int ll */ 0,
+/* int ll1 */ 0,
+/* int lt */ 0,
+/* int lt1 */ 0,
+/* Tchar ic */ 0, /* insertion character (= margin character) */
+/* int icf */ 0, /* insertion character flag */
+/* Tchar chbits */ 0, /* size+font bits for current character */
+/* Tchar spbits */ 0,
+/* Tchar nmbits */ 0, /* size+font bits for number from .nm */
+/* int apts */ PS, /* actual point size -- as requested by user */
+/* int apts1 */ PS, /* need not match an existent size */
+/* int pts */ PS, /* hence, this is the size that really exists */
+/* int pts1 */ PS,
+/* int font */ FT,
+/* int font1 */ FT,
+/* int ls */ 1,
+/* int ls1 */ 1,
+/* int ad */ 1,
+/* int nms */ 1, /* .nm multiplier */
+/* int ndf */ 1, /* .nm separator */
+/* int nmwid */ 3, /* max width of .nm numbers */
+/* int fi */ 1,
+/* int cc */ '.',
+/* int c2 */ '\'',
+/* int ohc */ OHC,
+/* int tdelim */ IMP,
+/* int hyf */ 1,
+/* int hyoff */ 0,
+/* int hyphalg */ HYPHALG,
+/* int un1 */ -1,
+/* int tabc */ 0,
+/* int dotc */ '.',
+/* int adsp */ 0, /* add this much space to each padding point */
+/* int adrem */ 0, /* excess space to add until it runs out */
+/* int lastl */ 0, /* last text on current output line */
+/* int nel */ 0, /* how much space left on current output line */
+/* int admod */ 0, /* adjust mode */
+/* Tchar *wordp */ 0,
+/* int spflg */ 0, /* probably to indicate space after punctuation needed */
+/* Tchar *linep */ 0,
+/* Tchar *wdend */ 0,
+/* Tchar *wdstart */ 0,
+/* int wne */ 0,
+/* int ne */ 0, /* how much space taken on current output line */
+/* int nc */ 0, /* #characters (incl blank) on output line */
+/* int nb */ 0,
+/* int lnmod */ 0, /* line number mode, set by .nm */
+/* int nwd */ 0, /* number of words on current output line */
+/* int nn */ 0, /* from .nn command */
+/* int ni */ 0, /* indent of .nm numbers, probably */
+/* int ul */ 0,
+/* int cu */ 0,
+/* int ce */ 0,
+/* int in */ 0, /* indent and previous value */
+/* int in1 */ 0,
+/* int un */ 0, /* unindent of left margin in some way */
+/* int wch */ 0,
+/* int pendt */ 0,
+/* Tchar *pendw */ (Tchar *)0,
+/* int pendnf */ 0,
+/* int spread */ 0,
+/* int it */ 0, /* input trap count */
+/* int itmac */ 0,
+} };
+
+Env *envp = env; /* start off in env 0 */
+
+Numerr numerr;
+
+Stack *frame, *stk, *ejl;
+Stack *nxf;
+
+int pipeflg;
+int hflg; /* used in nroff only */
+int eqflg; /* used in nroff only */
+
+int xpts;
+int ppts;
+int pfont;
+int mpts;
+int mfont;
+int cs;
+int ccs;
+int bd;
+
+int stdi;
+int quiet;
+int stop;
+char ibuf[IBUFSZ];
+char xbuf[IBUFSZ];
+char *ibufp;
+char *xbufp;
+char *eibuf;
+char *xeibuf;
+Tchar pbbuf[NC]; /* pushback buffer for arguments, \n, etc. */
+Tchar *pbp = pbbuf; /* next free slot in pbbuf */
+Tchar *lastpbp = pbbuf; /* pbp in previous stack frame */
+int nx;
+int mflg;
+Tchar ch = 0;
+int ibf;
+int ifi;
+int iflg;
+int rargc;
+char **argp;
+Ushort trtab[NTRTAB];
+int lgf;
+int copyf;
+Offset ip;
+int nlflg;
+int donef;
+int nflush;
+int nfo;
+int padc;
+int raw;
+int flss;
+int nonumb;
+int trap;
+int tflg;
+int ejf;
+int dilev;
+Offset offset;
+int em;
+int ds;
+Offset woff;
+int app;
+int ndone;
+int lead;
+int ralss;
+Offset nextb;
+Tchar nrbits;
+int nform;
+int oldmn;
+int newmn;
+int macerr;
+Offset apptr;
+int diflg;
+int evi;
+int vflag;
+int noscale;
+int po1;
+int nlist[NTRAP];
+int mlist[NTRAP];
+int evlist[EVLSZ];
+int ev;
+int tty;
+int sfont = FT; /* appears to be "standard" font; used by .ul */
+int sv;
+int esc;
+int widthp;
+int xfont;
+int setwdf;
+int over;
+int nhyp;
+Tchar **hyp;
+Tchar *olinep;
+int dotT;
+char *unlkp;
+Wcache widcache[NWIDCACHE];
+Diver d[NDI];
+Diver *dip;
+
+int c_hyphen;
+int c_emdash;
+int c_rule;
+int c_minus;
+int c_fi;
+int c_fl;
+int c_ff;
+int c_ffi;
+int c_ffl;
+int c_acute;
+int c_grave;
+int c_under;
+int c_rooten;
+int c_boxrule;
+int c_lefthand;
+int c_dagger;
+int c_isalnum;
+
+Spnames spnames[] =
+{
+ &c_hyphen, "hy",
+ &c_emdash, "em",
+ &c_rule, "ru",
+ &c_minus, "\\-",
+ &c_fi, "fi",
+ &c_fl, "fl",
+ &c_ff, "ff",
+ &c_ffi, "Fi",
+ &c_ffl, "Fl",
+ &c_acute, "aa",
+ &c_grave, "ga",
+ &c_under, "ul",
+ &c_rooten, "rn",
+ &c_boxrule, "br",
+ &c_lefthand, "lh",
+ &c_dagger, "dg", /* not in nroff?? */
+ &c_isalnum, "__",
+ 0, 0
+};
+
+
+Tchar (*hmot)(void);
+Tchar (*makem)(int i);
+Tchar (*setabs)(void);
+Tchar (*setch)(int c);
+Tchar (*sethl)(int k);
+Tchar (*setht)(void);
+Tchar (*setslant)(void);
+Tchar (*vmot)(void);
+Tchar (*xlss)(void);
+int (*findft)(int i);
+int (*width)(Tchar j);
+void (*mchbits)(void);
+void (*ptlead)(void);
+void (*ptout)(Tchar i);
+void (*ptpause)(void);
+void (*setfont)(int a);
+void (*setps)(void);
+void (*setwd)(void);
+
diff --git a/src/cmd/troff/suftab.c b/src/cmd/troff/suftab.c
new file mode 100644
index 00000000..1aa8a009
--- /dev/null
+++ b/src/cmd/troff/suftab.c
@@ -0,0 +1,612 @@
+/*
+ * Suffix table
+ */
+
+typedef unsigned char Uchar;
+
+static Uchar sufa[] = {
+ 02,0200+'t', /* -TA */
+ 02,0200+'s', /* -SA */
+ 03,0200+'t','r', /* -TRA */
+ 03,0200+'d','r', /* -DRA */
+ 03,0200+'b','r', /* -BRA */
+ 02,0200+'p', /* -PA */
+ 02,0200+'n', /* -NA */
+ 02,0200+'m', /* -MA */
+ 03,0200+'p','l', /* -PLA */
+ 02,0200+'l', /* -LA */
+ 02,0200+'k', /* -KA */
+ 03,0200+'t','h', /* -THA */
+ 03,0200+'s','h', /* -SHA */
+ 02,0200+'g', /* -GA */
+ 02,0200+'d', /* -DA */
+ 02,0200+'c', /* -CA */
+ 02,0200+'b', /* -BA */
+ 00
+};
+
+static Uchar sufc[] = {
+ 04,'e','t',0200+'i', /* ET-IC */
+ 07,'a','l',0200+'i','s',0200+'t','i', /* AL-IS-TIC */
+ 04,'s',0200+'t','i', /* S-TIC */
+ 04,'p',0200+'t','i', /* P-TIC */
+ 05,0200+'l','y','t',0200+'i', /* -LYT-IC */
+ 04,'o','t',0200+'i', /* OT-IC */
+ 05,'a','n',0200+'t','i', /* AN-TIC */
+ 04,'n',0200+'t','i', /* N-TIC */
+ 04,'c',0200+'t','i', /* C-TIC */
+ 04,'a','t',0200+'i', /* AT-IC */
+ 04,'h',0200+'n','i', /* H-NIC */
+ 03,'n',0200+'i', /* N-IC */
+ 03,'m',0200+'i', /* M-IC */
+ 04,'l',0200+'l','i', /* L-LIC */
+ 04,'b',0200+'l','i', /* B-LIC */
+ 04,0200+'c','l','i', /* -CLIC */
+ 03,'l',0200+'i', /* L-IC */
+ 03,'h',0200+'i', /* H-IC */
+ 03,'f',0200+'i', /* F-IC */
+ 03,'d',0200+'i', /* D-IC */
+ 03,0200+'b','i', /* -BIC */
+ 03,'a',0200+'i', /* A-IC */
+ 03,0200+'m','a', /* -MAC */
+ 03,'i',0200+'a', /* I-AC */
+ 00
+};
+
+static Uchar sufd[] = {
+ 04,0200+'w','o','r', /* -WORD */
+ 04,0200+'l','o','r', /* -LORD */
+ 04,0200+'f','o','r', /* -FORD */
+ 04,0200+'y','a','r', /* -YARD */
+ 04,0200+'w','a','r', /* -WARD */
+ 05,0200+'g','u','a','r', /* -GUARD */
+ 04,0200+'t','a','r', /* -TARD */
+ 05,0200+'b','o','a','r', /* -BOARD */
+ 04,0200+'n','a','r', /* -NARD */
+ 05,0200+'l','i','a','r', /* -LIARD */
+ 04,0200+'i','a','r', /* -IARD */
+ 04,0200+'g','a','r', /* -GARD */
+ 04,0200+'b','a','r', /* -BARD */
+ 03,0200+'r','o', /* -ROD */
+ 04,0200+'w','o','o', /* -WOOD */
+ 04,0200+'h','o','o', /* -HOOD */
+ 04,0200+'m','o','n', /* -MOND */
+ 04,0200+'t','e','n', /* -TEND */
+ 05,0200+'s','t','a','n', /* -STAND */
+ 04,0200+'l','a','n', /* -LAND */
+ 04,0200+'h','a','n', /* -HAND */
+ 04,0200+'h','o','l', /* -HOLD */
+ 04,0200+'f','o','l', /* -FOLD */
+ 05,0200+'f','i','e','l', /* -FIELD */
+ 03,0200+'v','i', /* -VID */
+ 03,0200+'c','i', /* -CID */
+ 04,0200+'s','a','i', /* -SAID */
+ 04,0200+'m','a','i', /* -MAID */
+ 04,'t',0200+'t','e', /* T-TED */
+ 03,'t',0200+'e', /* T-ED */
+ 04,0200+'d','r','e', /* -DRED */
+ 04,0200+'c','r','e', /* -CRED */
+ 04,0200+'b','r','e', /* -BRED */
+ 05,'v',0200+'e','l','e', /* V-ELED */
+ 0100+04,'a','l',0200+'e', /* AL/ED */
+ 0140+03,0200+'e','e', /* /EED */
+ 040+05,'e','d',0200+'d','e', /* ED-DED */
+ 04,'d',0200+'d','e', /* D-DED */
+ 040+04,'e','d',0200+'e', /* ED-ED */
+ 03,'d',0200+'e', /* D-ED */
+ 05,0200+'d','u','c','e', /* -DUCED */
+ 0300+02,'e', /* E/D */
+ 05,0200+'s','t','e','a', /* -STEAD */
+ 05,0200+'a','h','e','a', /* -AHEAD */
+ 04,0200+'h','e','a', /* -HEAD */
+ 00
+};
+
+static Uchar sufe[] = {
+ 05,'a','r',0200+'i','z', /* AR-IZE */
+ 05,'a','n',0200+'i','z', /* AN-IZE */
+ 05,'a','l',0200+'i','z', /* AL-IZE */
+ 06,0200+'a','r','d',0200+'i','z', /* -ARD-IZE */
+ 05,0200+'s','e','l','v', /* -SELVE */
+ 05,0200+'k','n','i','v', /* -KNIVE */
+ 05,0200+'l','i','e','v', /* -LIEVE */
+ 0100+03,0200+'q','u', /* /QUE */
+ 07,'o','n',0200+'t','i','n',0200+'u', /* ON-TIN-UE */
+ 03,0200+'n','u', /* -NUE */
+ 03,0200+'d','u', /* -DUE */
+ 0300+02,'u', /* U/E */
+ 0300+05,'q','u','a','t', /* QUAT/E */
+ 04,'u',0200+'a','t', /* U-ATE */
+ 05,0200+'s','t','a','t', /* -STATE */
+ 04,0200+'t','a','t', /* -TATE */
+ 06,0200+'t','o','r',0200+'a','t', /* -TOR-ATE */
+ 05,'e','n',0200+'a','t', /* EN-ATE */
+ 04,0200+'m','a','t', /* -MATE */
+ 05,0200+'h','o','u','s', /* -HOUSE */
+ 05,0200+'c','l','o','s', /* -CLOSE */
+ 04,'i',0200+'o','s', /* I-OSE */
+ 04,0200+'w','i','s', /* -WISE */
+ 05,'a','s',0200+'u','r', /* AS-URE */
+ 040+04,0200+'s','u','r', /* -SURE */
+ 06,0200+'f','i','g',0200+'u','r', /* -FIG-URE */
+ 040+03,0200+'t','r', /* -TRE */
+ 05,0200+'s','t','o','r', /* -STORE */
+ 04,0200+'f','o','r', /* -FORE */
+ 05,0200+'w','h','e','r', /* -WHERE */
+ 06,0200+'s','p','h','e','r', /* -SPHERE */
+ 03,0200+'d','r', /* -DRE */
+ 03,0200+'c','r', /* -CRE */
+ 03,0200+'b','r', /* -BRE */
+ 05,0200+'s','c','o','p', /* -SCOPE */
+ 04,'y',0200+'o','n', /* Y-ONE */
+ 05,0200+'s','t','o','n', /* -STONE */
+ 05,0200+'p','h','o','n', /* -PHONE */
+ 04,0200+'g','o','n', /* -GONE */
+ 04,'e',0200+'o','n', /* E-ONE */
+ 040+04,0200+'e','n','n', /* -ENNE */
+ 040+05,'a',0200+'r','i','n', /* A-RINE */
+ 05,0200+'c','l','i','n', /* -CLINE */
+ 04,0200+'l','i','n', /* -LINE */
+ 007,00200+'r','o','u',00200+'t','i','n', /*-ROU-TINE */
+ 04,0200+'s','o','m', /* -SOME */
+ 04,0200+'c','o','m', /* -COME */
+ 04,0200+'t','i','m', /* -TIME */
+ 03,0200+'z','l', /* -ZLE */
+ 03,0200+'t','l', /* -TLE */
+ 03,0200+'s','l', /* -SLE */
+ 03,0200+'p','l', /* -PLE */
+ 05,0200+'v','i','l','l', /* -VILLE */
+ 04,'c','k',0200+'l', /* CK-LE */
+ 03,0200+'k','l', /* -KLE */
+ 03,0200+'g','l', /* -GLE */
+ 03,0200+'f','l', /* -FLE */
+ 03,0200+'d','l', /* -DLE */
+ 03,0200+'c','l', /* -CLE */
+ 05,0200+'p','a',0200+'b','l', /* -PA-BLE */
+ 05,'f','a',0200+'b','l', /* FA-BLE */
+ 05,0200+'c','a',0200+'b','l', /* -CA-BLE */
+ 06,0200+'s','t','a','b','l', /* -STABLE */
+ 04,0200+'a','b','l', /* -ABLE */
+ 03,0200+'b','l', /* -BLE */
+ 04,0200+'d','a','l', /* -DALE */
+ 04,0200+'m','a','l', /* -MALE */
+ 04,0200+'s','a','l', /* -SALE */
+ 04,0200+'l','i','k', /* -LIKE */
+ 0340+05,'g',0200+'u','a','g', /* -G/UAGE */
+ 05,0200+'r','i','a','g', /* -RIAGE */
+ 05,'e','r',0200+'a','g', /* ER-AGE */
+ 04,'m',0200+'a','g', /* M-AGE */
+ 04,'k',0200+'a','g', /* K-AGE */
+ 04,'d',0200+'a','g', /* D-AGE */
+ 04,0200+'w','i','f', /* -WIFE */
+ 05,0200+'k','n','i','f', /* -KNIFE */
+ 03,0200+'s','e', /* -SEE */
+ 04,0200+'f','r','e', /* -FREE */
+ 0340+02,'e', /* EE */
+ 04,0200+'w','i','d', /* -WIDE */
+ 04,0200+'t','i','d', /* -TIDE */
+ 04,0200+'s','i','d', /* -SIDE */
+ 06,0200+'q','u','e','n','c', /* -QUENCE */
+ 07,0200+'f','l','u',0200+'e','n','c', /* -FLU-ENCE */
+ 040+06,'e','s',0200+'e','n','c', /* ES-ENCE */
+ 06,'e','r',0200+'e','n','c', /* ER-ENCE */
+ 05,'i',0200+'e','n','c', /* I-ENCE */
+ 040+05,0200+'s','a','n','c', /* -SANCE */
+ 06,'e','r',0200+'a','n','c', /* ER-ANCE */
+ 06,'a','r',0200+'a','n','c', /* AR-ANCE */
+ 05,0200+'n','a','n','c', /* -NANCE */
+ 07,0200+'b','a','l',0200+'a','n','c', /* -BAL-ANCE */
+ 05,'i',0200+'a','n','c', /* I-ANCE */
+ 07,0200+'j','u','s',0200+'t','i','c', /* -JUS-TICE */
+ 05,0200+'s','t','i','c', /* -STICE */
+ 06,0200+'n','o','v',0200+'i','c', /* NOV-ICE */
+ 04,0200+'v','i','c', /* -VICE */
+ 05,0200+'p','i','e','c', /* -PIECE */
+ 05,0200+'p','l','a','c', /* -PLACE */
+ 0340+01, /* /E */
+ 00
+};
+
+static Uchar suff[] = {
+ 03,0200+'o','f', /* -OFF */
+ 05,0200+'p','r','o','o', /* -PROOF */
+ 04,0200+'s','e','l', /* -SELF */
+ 03,0200+'r','i', /* -RIF */
+ 040+04,0200+'l','i','e', /* -LIEF */
+ 00
+};
+
+static Uchar sufg[] = {
+ 03,0200+'l','o', /* -LOG */
+ 04,0200+'l','o','n', /* -LONG */
+ 05,'t',0200+'t','i','n', /* T-TING */
+ 06,0200+'s','t','r','i','n', /* -STRING */
+ 05,'r',0200+'r','i','n', /* R-RING */
+ 05,'p',0200+'p','i','n', /* P-PING */
+ 05,'n',0200+'n','i','n', /* N-NING */
+ 05,'m',0200+'m','i','n', /* M-MING */
+ 05,'l',0200+'l','i','n', /* L-LING */
+ 05,0200+'z','l','i','n', /* -ZLING */
+ 05,0200+'t','l','i','n', /* -TLING */
+ 040+05,'s',0200+'l','i','n', /* S-LING */
+ 05,'r',0200+'l','i','n', /* R-LING */
+ 05,0200+'p','l','i','n', /* -PLING */
+ 06,'n',0200+'k','l','i','n', /* N-KLING */
+ 05,'k',0200+'l','i','n', /* K-LING */
+ 05,0200+'g','l','i','n', /* -GLING */
+ 05,0200+'f','l','i','n', /* -FLING */
+ 05,0200+'d','l','i','n', /* -DLING */
+ 05,0200+'c','l','i','n', /* -CLING */
+ 05,0200+'b','l','i','n', /* -BLING */
+ 06,'y',0200+'t','h','i','n', /* Y-THING */
+ 07,'e','e','t','h',0200+'i','n', /* EETH-ING */
+ 06,'e',0200+'t','h','i','n', /* E-THING */
+ 05,'g',0200+'g','i','n', /* G-GING */
+ 05,'d',0200+'d','i','n', /* D-DING */
+ 05,'b',0200+'b','i','n', /* B-BING */
+ 03,0200+'i','n', /* -ING */
+ 00
+};
+
+static Uchar sufh[] = {
+ 05,0200+'m','o','u','t', /* -MOUTH */
+ 05,0200+'w','o','r','t', /* -WORTH */
+ 04,0200+'w','i','t', /* -WITH */
+ 05,'t',0200+'t','i','s', /* T-TISH */
+ 05,'e',0200+'t','i','s', /* E-TISH */
+ 05,'p',0200+'p','i','s', /* P-PISH */
+ 05,'r',0200+'n','i','s', /* R-NISH */
+ 05,'n',0200+'n','i','s', /* N-NISH */
+ 05,0200+'p','l','i','s', /* -PLISH */
+ 05,0200+'g','u','i','s', /* -GUISH */
+ 05,0200+'g','l','i','s', /* -GLISH */
+ 05,'b',0200+'l','i','s', /* B-LISH */
+ 05,'g',0200+'g','i','s', /* G-GISH */
+ 05,'d',0200+'d','i','s', /* D-DISH */
+ 03,0200+'i','s', /* -ISH */
+ 05,0200+'g','r','a','p', /* -GRAPH */
+ 07,0200+'b','o','r',0200+'o','u','g', /* -BOR-OUGH */
+ 05,0200+'b','u','r','g', /* -BURGH */
+ 04,0200+'v','i','c', /* -VICH */
+ 03,0200+'n','a', /* -NAH */
+ 03,0200+'l','a', /* -LAH */
+ 04,0200+'m','i',0200+'a', /* -MI-AH */
+ 00
+};
+
+static Uchar sufi[] = {
+ 03,0200+'t','r', /* -TRI */
+ 03,0200+'c','h', /* -CHI */
+ 0200+03,'i','f', /* IF-I */
+ 0200+03,'e','d', /* ED-I */
+ 05,0200+'a','s','c','i', /* -ASCII */
+ 04,0200+'s','e','m', /* -SEMI */
+ 00
+};
+
+static Uchar sufk[] = {
+ 04,0200+'w','o','r', /* -WORK */
+ 04,0200+'m','a','r', /* -MARK */
+ 04,0200+'b','o','o', /* -BOOK */
+ 04,0200+'w','a','l', /* -WALK */
+ 05,0200+'c','r','a','c', /* -CRACK */
+ 04,0200+'b','a','c', /* -BACK */
+ 00
+};
+
+static Uchar sufl[] = {
+ 03,0200+'f','u', /* -FUL */
+ 05,'s',0200+'w','e','l', /* S-WELL */
+ 04,0200+'t','e','l', /* -TELL */
+ 05,0200+'s','h','e','l', /* -SHELL */
+ 05,0200+'s','t','a','l', /* -STALL */
+ 04,'s',0200+'t','a', /* S-TAL */
+ 04,0200+'b','a','l', /* -BALL */
+ 04,0200+'c','a','l', /* -CALL */
+ 03,'v',0200+'e', /* V-EL */
+ 03,'u',0200+'e', /* U-EL */
+ 03,'k',0200+'e', /* K-EL */
+ 04,'t','h',0200+'e', /* TH-EL */
+ 05,'t','c','h',0200+'e', /* TCH-EL */
+ 03,'a',0200+'e', /* A-EL */
+ 0140+04,0200+'q','u','a', /* /QUAL */
+ 040+03,'u',0200+'a', /* U-AL */
+ 03,0200+'t','a', /* -TAL */
+ 04,'u','r',0200+'a', /* UR-AL */
+ 040+05,'g',0200+'o',0200+'n','a', /* G-O-NAL */
+ 04,'o','n',0200+'a', /* ON-AL */
+ 03,0200+'n','a', /* -NAL */
+ 04,0200+'t','i','a', /* -TIAL */
+ 04,0200+'s','i','a', /* -SIAL */
+ 040+05,0200+'t','r','i',0200+'a', /* -TRI-AL */
+ 04,'r','i',0200+'a', /* RI-AL */
+ 04,0200+'n','i',0200+'a', /* -NI-AL */
+ 04,0200+'d','i',0200+'a', /* -DI-AL */
+ 04,0200+'c','i','a', /* -CIAL */
+ 03,0200+'g','a', /* -GAL */
+ 04,0200+'m','e','a', /* -MEAL */
+/* 040+04,0200+'r','e',0200+'a', /* -RE-AL */
+ 040+04,0200+'r','e','a', /* -REAL */
+ 06,'c',0200+'t','i',0200+'c','a', /* C-TI-CAL */
+ 05,0200+'s','i',0200+'c','a', /* -SI-CAL */
+ 04,0200+'i',0200+'c','a', /* -I-CAL */
+ 03,0200+'c','a', /* -CAL */
+ 03,0200+'b','a', /* -BAL */
+ 06,0200+'n','o',0200+'m','i',0200+'a', /* -NO-MI-AL */
+ 00
+};
+
+static Uchar sufm[] = {
+ 03,0200+'n','u', /* -NUM */
+ 05,'o',0200+'r','i',0200+'u', /* O-RI-UM */
+ 040+03,'i',0200+'u', /* I-UM */
+ 040+03,'e',0200+'u', /* E-UM */
+ 05,'i','v',0200+'i','s', /* IV-ISM */
+ 04,0200+'t','i','s', /* -TISM */
+ 05,'i',0200+'m','i','s', /* I-MISM */
+ 05,'a','l',0200+'i','s', /* AL-ISM */
+ 040+04,'e',0200+'i','s', /* E-ISM */
+ 040+04,'a',0200+'i','s', /* A-ISM */
+ 04,0200+'r','o','o', /* -ROOM */
+ 03,0200+'d','o', /* -DOM */
+ 03,0200+'h','a', /* -HAM */
+ 06,0200+'a',0200+'r','i','t','h', /* -A-RITHM */
+ 05,0200+'r','i','t','h', /* -RITHM */
+ 00
+};
+
+static Uchar sufn[] = {
+ 05,0200+'k','n','o','w', /* -KNOWN */
+ 04,0200+'t','o','w', /* -TOWN */
+ 04,0200+'d','o','w', /* -DOWN */
+ 04,0200+'t','u','r', /* -TURN */
+ 05,0200+'s','p','o','o', /* -SPOON */
+ 04,0200+'n','o','o', /* -NOON */
+ 04,0200+'m','o','o', /* -MOON */
+ 011,'a','l',0200+'i',0200+'z','a',0200+'t','i','o', /* AL-I-ZA-TION */
+ 07,0200+'i',0200+'z','a',0200+'t','i','o', /* -I-ZA-TION */
+ 07,'l',0200+'i',0200+'a',0200+'t','i','o', /* L-I-A-TION */
+ 04,0200+'t','i','o', /* -TION */
+ 040+05,'s',0200+'s','i','o', /* S-SION */
+ 04,0200+'s','i','o', /* -SION */
+ 04,'n',0200+'i','o', /* N-ION */
+ 04,0200+'g','i','o', /* -GION */
+ 04,0200+'c','i','o', /* -CION */
+ 03,0200+'c','o', /* -CON */
+ 05,0200+'c','o','l','o', /* -COLON */
+ 03,0200+'t','o', /* -TON */
+ 04,'i','s',0200+'o', /* IS-ON */
+ 03,0200+'s','o', /* -SON */
+ 03,0200+'r','i', /* -RIN */
+ 03,0200+'p','i', /* -PIN */
+ 03,0200+'n','i', /* -NIN */
+ 03,0200+'m','i', /* -MIN */
+ 03,0200+'l','i', /* -LIN */
+ 03,0200+'k','i', /* -KIN */
+ 05,0200+'s','t','e','i', /* -STEIN */
+ 04,0200+'t','a','i', /* -TAIN */
+ 05,'g','h','t',0200+'e', /* GHT-EN */
+ 05,0200+'w','o','m',0200+'e', /* -WOM-EN */
+ 03,0200+'m','e', /* -MEN */
+ 04,'o',0200+'k','e', /* O-KEN */
+ 03,'k',0200+'e', /* K-EN */
+ 04,0200+'t','e','e', /* -TEEN */
+ 04,0200+'s','e','e', /* -SEEN */
+ 040+03,0200+'s','a', /* -SAN */
+ 05,0200+'w','o','m',0200+'a', /* -WOM-AN */
+ 03,0200+'m','a', /* -MAN */
+ 04,0200+'t','i','a', /* -TIAN */
+ 04,0200+'s','i','a', /* -SIAN */
+ 040+04,'e',0200+'i','a', /* E-IAN */
+ 04,0200+'c','i','a', /* -CIAN */
+ 0300+03,'i','a', /* IA/N */
+ 05,0200+'c','l','e','a', /* -CLEAN */
+ 04,0200+'m','e','a', /* -MEAN */
+ 040+03,'e',0200+'a', /* E-AN */
+ 00
+};
+
+static Uchar sufo[] = {
+ 05,0200+'m','a','c',0200+'r', /* -MAC-RO */
+ 00
+};
+
+static Uchar sufp[] = {
+ 05,0200+'g','r','o','u', /* -GROUP */
+ 02,0200+'u', /* -UP */
+ 04,0200+'s','h','i', /* -SHIP */
+ 04,0200+'k','e','e', /* -KEEP */
+ 00
+};
+
+static Uchar sufr[] = {
+ 04,0200+'z','a','r', /* -ZARR */
+ 0300+02,'r', /* R/R */
+ 03,0200+'t','o', /* -TOR */
+ 040+03,0200+'s','o', /* -SOR */
+ 040+04,0200+'r','i',0200+'o', /* -RI-OR */
+ 04,'i','z',0200+'e', /* IZ-ER */
+ 05,0200+'c','o','v',0200+'e', /* -COV-ER */
+ 04,0200+'o','v','e', /* -OVER */
+ 04,0200+'e','v',0200+'e', /* -EV-ER */
+ 8,0200+'c','o','m',0200+'p','u','t',0200+'e', /* -COM-PUT-ER */
+ 040+05,'u','s',0200+'t','e', /* US-TER */
+ 05,'o','s','t',0200+'e', /* OST-ER */
+ 040+05,0200+'a','c',0200+'t','e', /* -AC-TER */
+ 06,0200+'w','r','i','t',0200+'e', /* -WRIT-ER */
+ 040+05,'i','s',0200+'t','e', /* IS-TER */
+ 040+05,'e','s',0200+'t','e', /* ES-TER */
+ 040+05,'a','s',0200+'t','e', /* AS-TER */
+ 04,0200+'s','t','e', /* -STER */
+ 05,'a','r',0200+'t','e', /* AR-TER */
+ 04,'r','t',0200+'e', /* RT-ER */
+ 040+05,'m',0200+'e',0200+'t','e', /* M-E-TER */
+ 05,0200+'w','a',0200+'t','e', /* -WA-TER */
+ 03,'r',0200+'e', /* R-ER */
+ 04,'o','p',0200+'e', /* OP-ER */
+ 05,0200+'p','a',0200+'p','e', /* -PA-PER */
+ 04,'w','n',0200+'e', /* WN-ER */
+ 040+04,'s',0200+'n','e', /* S-NER */
+ 04,'o','n',0200+'e', /* ON-ER */
+ 04,'r','m',0200+'e', /* RM-ER */
+ 03,0200+'m','e', /* -MER */
+ 04,'l','l',0200+'e', /* LL-ER */
+ 05,'d',0200+'d','l','e', /* D-DLER */
+ 04,0200+'b','l','e', /* -BLER */
+ 03,'k',0200+'e', /* K-ER */
+ 05,'n',0200+'t','h','e', /* N-THER */
+ 06,0200+'f','a',0200+'t','h','e', /* -FA-THER */
+ 06,'e','i',0200+'t','h','e', /* EI-THER */
+ 04,'t','h',0200+'e', /* TH-ER */
+ 04,'s','h',0200+'e', /* SH-ER */
+ 04,0200+'p','h','e', /* -PHER */
+ 04,'c','h',0200+'e', /* CH-ER */
+ 04,'d','g',0200+'e', /* DG-ER */
+ 04,'r','d',0200+'e', /* RD-ER */
+ 06,'o','u','n','d',0200+'e', /* OUND-ER */
+ 04,'l','d',0200+'e', /* LD-ER */
+ 04,'i','d',0200+'e', /* ID-ER */
+ 05,0200+'d','u','c',0200+'e', /* -DUC-ER */
+ 04,'n','c',0200+'e', /* NC-ER */
+ 0100+02, 0200+'e', /* /ER */
+ 03,0200+'s','a', /* -SAR */
+ 040+06,'a','c',0200+'u',0200+'l','a', /* AC-U-LAR */
+ 040+06,'e','c',0200+'u',0200+'l','a', /* EC-U-LAR */
+ 040+06,'i','c',0200+'u',0200+'l','a', /* IC-U-LAR */
+ 040+06,'e','g',0200+'u',0200+'l','a', /* EG-U-LAR */
+ 00
+};
+
+static Uchar sufs[] = {
+ 040+04,'u',0200+'o','u', /* U-OUS */
+ 05,0200+'t','i','o','u', /* -TIOUS */
+ 05,0200+'g','i','o','u', /* -GIOUS */
+ 05,0200+'c','i','o','u', /* -CIOUS */
+ 040+04,'i',0200+'o','u', /* I-OUS */
+ 05,0200+'g','e','o','u', /* -GEOUS */
+ 05,0200+'c','e','o','u', /* -CEOUS */
+ 04,'e',0200+'o','u', /* E-OUS */
+ 0140+02,0200+'u', /* /US */
+ 04,0200+'n','e','s', /* -NESS */
+ 04,0200+'l','e','s', /* -LESS */
+ 0140+02,0200+'s', /* /SS */
+ 040+05,'p',0200+'o',0200+'l','i', /* P-O-LIS */
+ 0140+02,0200+'i', /* /IS */
+ 0100+03,0200+'x','e', /* X/ES */
+ 0100+03,0200+'s','e', /* S/ES */
+ 0100+04,'s','h',0200+'e', /* SH/ES */
+ 0100+04,'c','h',0200+'e', /* CH/ES */
+ 0300+01, /* /S */
+ 00
+};
+
+static Uchar suft[] = {
+ 05,0200+'l','i','m',0200+'i', /* -LIM-IT */
+ 06,'i','o','n',0200+'i','s', /* ION-IST */
+ 05,'i','n',0200+'i','s', /* IN-IST */
+ 05,'a','l',0200+'i','s', /* AL-IST */
+ 06,'l',0200+'o',0200+'g','i','s', /* L-O-GIST */
+ 05,'h','t',0200+'e','s', /* HT-EST */
+ 04,'i',0200+'e','s', /* I-EST */
+ 05,'g',0200+'g','e','s', /* G-GEST */
+ 04,'g',0200+'e','s', /* G-EST */
+ 05,'d',0200+'d','e','s', /* D-DEST */
+ 04,'d',0200+'e','s', /* D-EST */
+ 04,0200+'c','a','s', /* -CAST */
+ 05,0200+'h','e','a','r', /* -HEART */
+ 04,0200+'f','o','o', /* -FOOT */
+ 03,'i',0200+'o', /* I-OT */
+ 05,0200+'f','r','o','n', /* -FRONT */
+ 05,0200+'p','r','i','n', /* -PRINT */
+ 04,0200+'m','e','n', /* -MENT */
+ 05,0200+'c','i','e','n', /* -CIENT */
+ 04,'i',0200+'a','n', /* I-ANT */
+ 06,0200+'w','r','i','g','h', /* -WRIGHT */
+ 06,0200+'b','r','i','g','h', /* -BRIGHT */
+ 06,0200+'f','l','i','g','h', /* -FLIGHT */
+ 06,0200+'w','e','i','g','h', /* -WEIGHT */
+ 05,0200+'s','h','i','f', /* -SHIFT */
+ 05,0200+'c','r','a','f', /* -CRAFT */
+ 040+04,'d','g',0200+'e', /* DG-ET */
+ 04,0200+'g','o','a', /* -GOAT */
+ 04,0200+'c','o','a', /* -COAT */
+ 04,0200+'b','o','a', /* -BOAT */
+ 04,0200+'w','h','a', /* -WHAT */
+ 04,0200+'c','u','i', /* -CUIT */
+ 00
+};
+
+static Uchar sufy[] = {
+ 040+04,'e','s',0200+'t', /* ES-TY */
+ 040+05,'q','u','i',0200+'t', /* QUI-TY */
+ 04,0200+'t','i',0200+'t', /* -TI-TY */
+ 040+05,'o','s',0200+'i',0200+'t', /* OS-I-TY */
+ 04,0200+'s','i',0200+'t', /* -SI-TY */
+ 05,'i','n',0200+'i',0200+'t', /* IN-I-TY */
+ 04,'n','i',0200+'t', /* NI-TY */
+ 040+010,'f','a',0200+'b','i','l',0200+'i',0200+'t', /* FA-BIL-I-TY */
+ 010,0200+'c','a',0200+'b','i','l',0200+'i',0200+'t', /* -CA-BIL-I-TY */
+ 010,0200+'p','a',0200+'b','i','l',0200+'i',0200+'t', /* -PA-BIL-I-TY */
+ 06,0200+'b','i','l',0200+'i',0200+'t', /* -BIL-I-TY */
+ 03,'i',0200+'t', /* I-TY */
+ 04,0200+'b','u','r', /* -BUR-Y */
+ 04,0200+'t','o',0200+'r', /* -TO-RY */
+ 05,0200+'q','u','a','r', /* -QUAR-Y */
+ 040+04,'u',0200+'a','r', /* U-ARY */
+ 07,0200+'m','e','n',0200+'t','a',0200+'r', /* -MEN-TA-RY */
+ 06,'i','o','n',0200+'a','r', /* ION-ARY */
+ 04,'i',0200+'a','r', /* I-ARY */
+ 04,'n',0200+'o',0200+'m', /* N-O-MY */
+ 03,0200+'p','l', /* -PLY */
+ 04,'g',0200+'g','l', /* G-GLY */
+ 05,0200+'p','a',0200+'b','l', /* -PA-BLY */
+ 05,'f','a',0200+'b','l', /* FA-BLY */
+ 05,0200+'c','a',0200+'b','l', /* -CA-BLY */
+ 04,0200+'a','b','l', /* -ABLY */
+ 03,0200+'b','l', /* -BLY */
+ 02,0200+'l', /* -LY */
+ 03,0200+'s','k', /* -SKY */
+ 040+06,'g',0200+'r','a',0200+'p','h', /* G-RA-PHY */
+ 04,'l',0200+'o',0200+'g', /* L-O-GY */
+ 02,0200+'f', /* -FY */
+ 03,0200+'n','e', /* -NEY */
+ 03,0200+'l','e', /* -LEY */
+ 04,'c','k',0200+'e', /* CK-EY */
+ 03,0200+'k','e', /* -KEY */
+ 04,0200+'b','o','d', /* -BODY */
+ 05,0200+'s','t','u','d', /* -STUDY */
+ 0340+04,'e','e','d', /* EEDY */
+ 02,0200+'b', /* -BY */
+ 03,0200+'w','a', /* -WAY */
+ 03,0200+'d','a', /* -DAY */
+ 00
+};
+
+Uchar *suftab[] = {
+ sufa,
+ 0,
+ sufc,
+ sufd,
+ sufe,
+ suff,
+ sufg,
+ sufh,
+ sufi,
+ 0,
+ sufk,
+ sufl,
+ sufm,
+ sufn,
+ sufo,
+ sufp,
+ 0,
+ sufr,
+ sufs,
+ suft,
+ 0,
+ 0,
+ 0,
+ 0,
+ sufy,
+ 0,
+};
diff --git a/src/cmd/troff/t10.c b/src/cmd/troff/t10.c
new file mode 100644
index 00000000..3e8026d1
--- /dev/null
+++ b/src/cmd/troff/t10.c
@@ -0,0 +1,512 @@
+#include "tdef.h"
+#include "fns.h"
+#include "ext.h"
+
+/*
+ * troff10.c
+ *
+ * typesetter interface
+ */
+
+int vpos = 0; /* absolute vertical position on page */
+int hpos = 0; /* ditto horizontal */
+
+extern Font fonts[MAXFONTS+1];
+
+int Inch;
+int Hor;
+int Vert;
+int Unitwidth;
+int nfonts;
+
+
+
+void t_ptinit(void)
+{
+ int i;
+ char buf[100], *p;
+
+ hmot = t_hmot;
+ makem = t_makem;
+ setabs = t_setabs;
+ setch = t_setch;
+ sethl = t_sethl;
+ setht = t_setht;
+ setslant = t_setslant;
+ vmot = t_vmot;
+ xlss = t_xlss;
+ findft = t_findft;
+ width = t_width;
+ mchbits = t_mchbits;
+ ptlead = t_ptlead;
+ ptout = t_ptout;
+ ptpause = t_ptpause;
+ setfont = t_setfont;
+ setps = t_setps;
+ setwd = t_setwd;
+
+ /* open table for device, */
+ /* read in resolution, size info, font info, etc., set params */
+ if ((p = getenv("TYPESETTER")) != 0)
+ strcpy(devname, p);
+ if (termtab[0] == 0)
+ strcpy(termtab, DWBfontdir);
+ if (fontdir[0] == 0)
+ strcpy(fontdir, DWBfontdir);
+ if (devname[0] == 0)
+ strcpy(devname, TDEVNAME);
+ hyf = 1;
+ lg = 1;
+
+ sprintf(buf, "/dev%s/DESC", devname);
+ strcat(termtab, buf);
+ if (getdesc(termtab) < 0) {
+ ERROR "can't open DESC file %s", termtab WARN;
+ done3(1);
+ }
+ if (!ascii) {
+ OUT "x T %s\n", devname PUT;
+ OUT "x res %d %d %d\n", Inch, Hor, Vert PUT;
+ OUT "x init\n" PUT;
+ }
+ for (i = 1; i <= nfonts; i++)
+ setfp(i, fontlab[i], (char *) 0, 0);
+ sps = EM/3; /* space size */
+ ics = EM; /* insertion character space */
+ for (i = 0; i < (NTAB - 1) && DTAB * (i + 1) < TABMASK; i++)
+ tabtab[i] = DTAB * (i + 1);
+ tabtab[NTAB] = 0;
+ pl = 11 * INCH; /* paper length */
+ po = PO; /* page offset */
+ spacesz = SS;
+ lss = lss1 = VS;
+ ll = ll1 = lt = lt1 = LL;
+ t_specnames(); /* install names like "hyphen", etc. */
+}
+
+void t_specnames(void)
+{
+ int i;
+
+ for (i = 0; spnames[i].n; i++)
+ *spnames[i].n = chadd(spnames[i].v, Troffchar, Install);
+}
+
+void t_ptout(Tchar i)
+{
+ int dv;
+ Tchar *k;
+ int temp, a, b;
+ int diff;
+
+ if (cbits(i) != '\n') {
+ if (olinep >= oline + olnsize) {
+ diff = olinep - oline;
+ olnsize += OLNSIZE;
+ if ((oline = (Tchar *)realloc((char *)oline, olnsize * sizeof(Tchar))) != NULL) {
+ if (diff && olinep)
+ olinep = oline + diff;
+ } else {
+ ERROR "Output line overflow." WARN;
+ done(2);
+ }
+ }
+ *olinep++ = i;
+ return;
+ }
+ if (olinep == oline) {
+ lead += lss;
+ return;
+ }
+
+ hpos = po; /* ??? */
+ esc = 0; /* ??? */
+ ptesc(); /* the problem is to get back to the left end of the line */
+ dv = 0;
+ for (k = oline; k < olinep; k++) {
+ if (ismot(*k) && isvmot(*k)) {
+ temp = absmot(*k);
+ if (isnmot(*k))
+ temp = -temp;
+ dv += temp;
+ }
+ }
+ if (dv) {
+ vflag++;
+ *olinep++ = makem(-dv);
+ vflag = 0;
+ }
+
+ b = dip->blss + lss;
+ lead += dip->blss + lss;
+ dip->blss = 0;
+ for (k = oline; k < olinep; )
+ k += ptout0(k); /* now passing a pointer! */
+ olinep = oline;
+ lead += dip->alss;
+ a = dip->alss;
+ dip->alss = 0;
+ /*
+ OUT "x xxx end of line: hpos=%d, vpos=%d\n", hpos, vpos PUT;
+*/
+ OUT "n%d %d\n", b, a PUT; /* be nice to chuck */
+}
+
+int ptout0(Tchar *pi)
+{
+ int j, k, w;
+ int z, dx, dy, dx2, dy2, n;
+ Tchar i;
+ int outsize; /* size of object being printed */
+
+ outsize = 1; /* default */
+ i = *pi;
+ k = cbits(i);
+ if (ismot(i)) {
+ j = absmot(i);
+ if (isnmot(i))
+ j = -j;
+ if (isvmot(i))
+ lead += j;
+ else
+ esc += j;
+ return(outsize);
+ }
+ if (k == CHARHT) {
+ xpts = fbits(i); /* sneaky, font bits as size bits */
+ if (xpts != mpts)
+ ptps();
+ OUT "x H %d\n", sbits(i) PUT;
+ return(outsize);
+ }
+ if (k == SLANT) {
+ OUT "x S %d\n", sfbits(i)-180 PUT;
+ return(outsize);
+ }
+ if (k == WORDSP) {
+ oput('w');
+ return(outsize);
+ }
+ if (sfbits(i) == oldbits) {
+ xfont = pfont;
+ xpts = ppts;
+ } else
+ xbits(i, 2);
+ if (k == XON) {
+ extern int xon;
+ ptflush(); /* guarantee that everything is out */
+ if (esc)
+ ptesc();
+ if (xfont != mfont)
+ ptfont();
+ if (xpts != mpts)
+ ptps();
+ if (lead)
+ ptlead();
+ OUT "x X " PUT;
+ xon++;
+ for (j = 1; cbits(pi[j]) != XOFF; j++)
+ outascii(pi[j]);
+ oput('\n');
+ xon--;
+ return j+1;
+ }
+ if (k < 040 && k != DRAWFCN)
+ return(outsize);
+ j = z = 0;
+ if (k != DRAWFCN) {
+ if (widcache[k].fontpts == (xfont<<8) + xpts && !setwdf) {
+ w = widcache[k].width;
+ bd = 0;
+ cs = 0;
+ } else
+ w = getcw(k);
+ if (cs) {
+ if (bd)
+ w += (bd - 1) * HOR;
+ j = (cs - w) / 2;
+ w = cs - j;
+ if (bd)
+ w -= (bd - 1) * HOR;
+ }
+ if (iszbit(i)) {
+ if (cs)
+ w = -j;
+ else
+ w = 0;
+ z = 1;
+ }
+ }
+ esc += j;
+ if (xfont != mfont)
+ ptfont();
+ if (xpts != mpts)
+ ptps();
+ if (lead)
+ ptlead();
+ /* put out the real character here */
+ if (k == DRAWFCN) {
+ if (esc)
+ ptesc();
+ w = 0;
+ dx = absmot(pi[3]);
+ if (isnmot(pi[3]))
+ dx = -dx;
+ dy = absmot(pi[4]);
+ if (isnmot(pi[4]))
+ dy = -dy;
+ switch (cbits(pi[1])) {
+ case DRAWCIRCLE: /* circle */
+ OUT "D%c %d\n", DRAWCIRCLE, dx PUT; /* dx is diameter */
+ hpos += dx;
+ break;
+ case DRAWELLIPSE:
+ OUT "D%c %d %d\n", DRAWELLIPSE, dx, dy PUT;
+ hpos += dx;
+ break;
+ case DRAWBUILD:
+ k = cbits(pi[2]);
+ OUT "D%c %d ", DRAWBUILD, dx PUT;
+ if (k < ALPHABET)
+ OUT "%c\n", k PUT;
+ else
+ ptchname(k);
+ hpos += dx;
+ break;
+ case DRAWLINE: /* line */
+ k = cbits(pi[2]);
+ OUT "D%c %d %d ", DRAWLINE, dx, dy PUT;
+ if (k < ALPHABET)
+ OUT "%c\n", k PUT;
+ else
+ ptchname(k);
+ hpos += dx;
+ vpos += dy;
+ break;
+ case DRAWARC: /* arc */
+ dx2 = absmot(pi[5]);
+ if (isnmot(pi[5]))
+ dx2 = -dx2;
+ dy2 = absmot(pi[6]);
+ if (isnmot(pi[6]))
+ dy2 = -dy2;
+ OUT "D%c %d %d %d %d\n", DRAWARC,
+ dx, dy, dx2, dy2 PUT;
+ hpos += dx + dx2;
+ vpos += dy + dy2;
+ break;
+
+ case 's': /* using 's' internally to avoid .tr ~ */
+ pi[1] = '~';
+ case DRAWSPLINE: /* spline */
+ default: /* something else; copy it like spline */
+ OUT "D%c %d %d", cbits(pi[1]), dx, dy PUT;
+ hpos += dx;
+ vpos += dy;
+ if (cbits(pi[3]) == DRAWFCN || cbits(pi[4]) == DRAWFCN) {
+ /* it was somehow defective */
+ OUT "\n" PUT;
+ break;
+ }
+ for (n = 5; cbits(pi[n]) != DRAWFCN; n += 2) {
+ dx = absmot(pi[n]);
+ if (isnmot(pi[n]))
+ dx = -dx;
+ dy = absmot(pi[n+1]);
+ if (isnmot(pi[n+1]))
+ dy = -dy;
+ OUT " %d %d", dx, dy PUT;
+ hpos += dx;
+ vpos += dy;
+ }
+ OUT "\n" PUT;
+ break;
+ }
+ for (n = 3; cbits(pi[n]) != DRAWFCN; n++)
+ ;
+ outsize = n + 1;
+ } else if (k < ALPHABET) {
+ /* try to go faster and compress output */
+ /* by printing nnc for small positive motion followed by c */
+ /* kludgery; have to make sure set all the vars too */
+ if (esc > 0 && esc < 100) {
+ oput(esc / 10 + '0');
+ oput(esc % 10 + '0');
+ oput(k);
+ hpos += esc;
+ esc = 0;
+ } else {
+ if (esc)
+ ptesc();
+ oput('c');
+ oput(k);
+ oput('\n');
+ }
+ } else {
+ if (esc)
+ ptesc();
+ ptchname(k);
+ }
+ if (bd) {
+ bd -= HOR;
+ if (esc += bd)
+ ptesc();
+ if (k < ALPHABET)
+ OUT "c%c\n", k PUT;
+ else
+ ptchname(k);
+ if (z)
+ esc -= bd;
+ }
+ esc += w;
+ return(outsize);
+}
+
+void ptchname(int k)
+{
+ char *chn = chname(k);
+
+ switch (chn[0]) {
+ case MBchar:
+ OUT "c%s\n", chn+1 PUT; /* \n not needed? */
+ break;
+ case Number:
+ OUT "N%s\n", chn+1 PUT;
+ break;
+ case Troffchar:
+ OUT "C%s\n", chn+1 PUT;
+ break;
+ default:
+ ERROR "illegal char type %s", chn WARN;
+ break;
+ }
+}
+
+void ptflush(void) /* get us to a clean output state */
+{
+ if (TROFF) {
+ /* ptesc(); but always H, no h */
+ hpos += esc;
+ OUT "\nH%d\n", hpos PUT;
+ esc = 0;
+ ptps();
+ ptfont();
+ ptlead();
+ }
+}
+
+void ptps(void)
+{
+ int i, j, k;
+
+ i = xpts;
+ for (j = 0; i > (k = pstab[j]); j++)
+ if (!k) {
+ k = pstab[--j];
+ break;
+ }
+ if (!ascii)
+ OUT "s%d\n", k PUT; /* really should put out string rep of size */
+ mpts = i;
+}
+
+void ptfont(void)
+{
+ mfont = xfont;
+ if (ascii)
+ return;
+ if (xfont > nfonts) {
+ ptfpcmd(0, fonts[xfont].longname, 0); /* Put the desired font in the
+ * fontcache of the filter */
+ OUT "f0\n" PUT; /* make sure that it gets noticed */
+ } else
+ OUT "f%d\n", xfont PUT;
+}
+
+void ptfpcmd(int f, char *s, char *longname)
+{
+ if (f > nfonts) /* a bit risky? */
+ f = 0;
+ if (longname) {
+ OUT "x font %d %s %s\n", f, s, longname PUT;
+ } else {
+ OUT "x font %d %s\n", f, s PUT;
+ }
+/* OUT "f%d\n", xfont PUT; /* need this for buggy version of adobe transcript */
+ /* which apparently believes that x font means */
+ /* to set the font, not just the position. */
+}
+
+void t_ptlead(void)
+{
+ vpos += lead;
+ if (!ascii)
+ OUT "V%d\n", vpos PUT;
+ lead = 0;
+}
+
+void ptesc(void)
+{
+ hpos += esc;
+ if (!ascii)
+ if (esc > 0) {
+ oput('h');
+ if (esc>=10 && esc<100) {
+ oput(esc/10 + '0');
+ oput(esc%10 + '0');
+ } else
+ OUT "%d", esc PUT;
+ } else
+ OUT "H%d\n", hpos PUT;
+ esc = 0;
+}
+
+void ptpage(int n) /* called at end of each output page, we hope */
+{
+ int i;
+
+ if (NROFF)
+ return;
+ ptlead();
+ vpos = 0;
+ if (ascii)
+ return;
+ OUT "p%d\n", n PUT; /* new page */
+ for (i = 0; i <= nfonts; i++)
+ if (fontlab[i]) {
+ if (fonts[i].truename)
+ OUT "x font %d %s %s\n", i, fonts[i].longname, fonts[i].truename PUT;
+ else
+ OUT "x font %d %s\n", i, fonts[i].longname PUT;
+ }
+ ptps();
+ ptfont();
+}
+
+void pttrailer(void)
+{
+ if (TROFF)
+ OUT "x trailer\n" PUT;
+}
+
+void ptstop(void)
+{
+ if (TROFF)
+ OUT "x stop\n" PUT;
+}
+
+void t_ptpause(void)
+{
+ if (ascii)
+ return;
+ ptlead();
+ vpos = 0;
+ pttrailer();
+ ptlead();
+ OUT "x pause\n" PUT;
+ flusho();
+ mpts = mfont = 0;
+ ptesc();
+ esc = po;
+ hpos = vpos = 0; /* probably in wrong place */
+}
diff --git a/src/cmd/troff/t11.c b/src/cmd/troff/t11.c
new file mode 100644
index 00000000..5511748c
--- /dev/null
+++ b/src/cmd/troff/t11.c
@@ -0,0 +1,255 @@
+#include "tdef.h"
+#include "fns.h"
+#include "ext.h"
+
+#define MAXCH NCHARS /* maximum number of global char names */
+char *chnames[MAXCH]; /* chnames[n-ALPHABET] -> name of char n */
+int nchnames; /* number of Cxy names currently seen */
+
+#define MAXPS 100 /* max number of point sizes */
+int pstab[MAXPS]; /* point sizes */
+int nsizes; /* number in DESC */
+
+Font fonts[MAXFONTS+1]; /* font info + ptr to width info */
+
+
+#define skipline(f) while (getc(f) != '\n')
+
+#define eq(s1, s2) (strcmp(s1, s2) == 0)
+
+getdesc(char *name)
+{
+ FILE *fin;
+ char cmd[100], s[100];
+ int i, v;
+
+ if ((fin = fopen(unsharp(name), "r")) == NULL)
+ return -1;
+ while (fscanf(fin, "%s", cmd) != EOF) {
+ if (strcmp(cmd, "res") == 0) {
+ fscanf(fin, "%d", &Inch);
+ } else if (strcmp(cmd, "hor") == 0) {
+ fscanf(fin, "%d", &Hor);
+ } else if (strcmp(cmd, "vert") == 0) {
+ fscanf(fin, "%d", &Vert);
+ } else if (strcmp(cmd, "unitwidth") == 0) {
+ fscanf(fin, "%d", &Unitwidth);
+ } else if (strcmp(cmd, "sizes") == 0) {
+ nsizes = 0;
+ while (fscanf(fin, "%d", &v) != EOF && v != 0 && nsizes < MAXPS)
+ pstab[nsizes++] = v;
+ } else if (strcmp(cmd, "fonts") == 0) {
+ fscanf(fin, "%d", &nfonts);
+ for (i = 1; i <= nfonts; i++) {
+ fscanf(fin, "%s", s);
+ fontlab[i] = PAIR(s[0], s[1]);
+ }
+ } else if (strcmp(cmd, "charset") == 0) { /* add any names */
+ while (fscanf(fin, "%s", s) != EOF)
+ chadd(s, Troffchar, Install);
+ break;
+ }
+ /* else
+ just skip anything else */
+ skipline(fin);
+ }
+ fclose(fin);
+ return 1;
+}
+
+static int checkfont(char *name)
+{ /* in case it's not really a font description file */
+ /* really paranoid, but consider \f. */
+ FILE *fp;
+ char buf[300], buf2[300];
+ int i, status = -1;
+
+ if ((fp = fopen(unsharp(name), "r")) == NULL)
+ return -1;
+ for (i = 1; i <= 10; i++) {
+ if (fgets(buf, sizeof buf, fp) == NULL)
+ break;
+ sscanf(buf, "%s", buf2);
+ if (buf2[0] == '#') {
+ i--;
+ continue;
+ }
+ if (eq(buf2, "name") || eq(buf2, "fontname") ||
+ eq(buf2, "special") || eq(buf2, "charset")) {
+ status = 1;
+ break;
+ }
+ }
+ fclose(fp);
+ return status;
+
+}
+
+getfont(char *name, int pos) /* create width tab for font */
+{
+ FILE *fin;
+ Font *ftemp = &fonts[pos];
+ Chwid chtemp[MAXCH];
+ static Chwid chinit;
+ int i, nw, n, wid, kern, code, type;
+ char buf[100], ch[100], s1[100], s2[100], s3[100], cmd[300];
+
+ /* fprintf(stderr, "read font %s onto %d\n", name, pos); */
+ if (checkfont(name) == -1)
+ return -1;
+ if ((fin = fopen(unsharp(name), "r")) == NULL)
+ return -1;
+ for (i = 0; i < ALPHABET; i++)
+ chtemp[i] = chinit; /* zero out to begin with */
+ ftemp->specfont = ftemp->ligfont = 0;
+ ftemp->defaultwidth = ftemp->spacewidth = Inch * Unitwidth / 72 / 3; /* should be rounded */
+ while (fscanf(fin, "%s", cmd) != EOF) {
+ if (strcmp(cmd, "name") == 0)
+ fscanf(fin, "%s", ftemp->longname);
+ else if (strcmp(cmd, "special") == 0)
+ ftemp->specfont = 1;
+ else if (strcmp(cmd, "ligatures") == 0) {
+ ftemp->ligfont = getlig(fin);
+ } else if (strcmp(cmd, "spacewidth") == 0) {
+ fscanf(fin, "%d", &ftemp->spacewidth);
+ } else if (strcmp(cmd, "defaultwidth") == 0) {
+ fscanf(fin, "%d", &ftemp->defaultwidth);
+ } else if (strcmp(cmd, "charset") == 0) {
+ wchar_t wc;
+ skipline(fin);
+ nw = ALPHABET;
+ while (fgets(buf, sizeof buf, fin) != NULL) {
+ sscanf(buf, "%s %s %s %s", ch, s1, s2, s3);
+ if (s1[0] != '"') { /* genuine new character */
+ sscanf(s1, "%d", &wid);
+ sscanf(s2, "%d", &kern);
+ code = strtol(s3, 0, 0); /* dec/oct/hex */
+ }
+ /* otherwise it's a synonym for prev character, */
+ /* so leave previous values intact */
+
+
+ /* decide what kind of alphabet it might come from here */
+
+
+ if (strlen(ch) == 1) { /* it's ascii */
+ n = ch[0]; /* origin includes non-graphics */
+ chtemp[n].num = ch[0];
+ } else if (ch[0] == '\\' && ch[1] == '0') {
+ n = strtol(ch+1, 0, 0); /* \0octal or \0xhex */
+ chtemp[n].num = n;
+#ifdef UNICODE
+ } else if (mbtowc(&wc, ch, strlen(ch)) > 1) {
+ chtemp[nw].num = chadd(ch, MBchar, Install);
+ n = nw;
+ nw++;
+#endif /*UNICODE*/
+ } else {
+ if (strcmp(ch, "---") == 0) { /* no name */
+ sprintf(ch, "%d", code);
+ type = Number;
+ } else
+ type = Troffchar;
+ chtemp[nw].num = chadd(ch, type, Install);
+ n = nw;
+ nw++;
+ }
+ chtemp[n].wid = wid;
+ chtemp[n].kern = kern;
+ chtemp[n].code = code;
+ /*fprintf(stderr, "font %2.2s char %4.4s num %3d wid %2d code %3d\n",
+ ftemp->longname, ch, n, wid, code);
+ */
+ }
+ break;
+ }
+ skipline(fin);
+ }
+ fclose(fin);
+ chtemp[' '].wid = ftemp->spacewidth; /* width of space on this font */
+ ftemp->nchars = nw;
+ if (ftemp->wp)
+ free(ftemp->wp); /* god help us if this wasn't allocated */
+ ftemp->wp = (Chwid *) malloc(nw * sizeof(Chwid));
+ if (ftemp->wp == NULL)
+ return -1;
+ for (i = 0; i < nw; i++)
+ ftemp->wp[i] = chtemp[i];
+/*
+ * printf("%d chars: ", nw);
+ * for (i = 0; i < nw; i++)
+ * if (ftemp->wp[i].num > 0 && ftemp->wp[i].num < ALPHABET) {
+ * printf("%c %d ", ftemp->wp[i].num, ftemp->wp[i].wid);
+ * else if (i >= ALPHABET)
+ * printf("%d (%s) %d ", ftemp->wp[i].num,
+ * chnames[ftemp->wp[i].num-ALPHABET], ftemp->wp[i].wid);
+ * }
+ * printf("\n");
+ */
+ return 1;
+}
+
+chadd(char *s, int type, int install) /* add s to global character name table; */
+{ /* or just look it up */
+
+ /* a temporary kludge: store the "type" as the first character */
+ /* of the string, so we can remember from whence it came */
+
+ char *p;
+ int i;
+
+/* fprintf(stderr, "into chadd %s %c %c\n", s, type, install); /* */
+ for (i = 0; i < nchnames; i++)
+ if (type == chnames[i][0] && eq(s, chnames[i]+1)) /* +1 since type at front */
+ break;
+/* fprintf(stderr, "i %d, nchnames %d\n", i, nchnames); /* */
+ if (i < nchnames) /* found same type and bytes at position i */
+ return ALPHABET + i;
+ else if (install == Lookup) /* not found, and we were just looking */
+ return -1;
+
+ chnames[nchnames] = p = (char *) malloc(strlen(s)+1+1); /* type + \0 */
+ if (p == NULL) {
+ ERROR "out of space adding character %s", s WARN;
+ return LEFTHAND;
+ }
+ if (nchnames >= NCHARS - ALPHABET) {
+ ERROR "out of table space adding character %s", s WARN;
+ return LEFTHAND;
+ }
+ strcpy(chnames[nchnames]+1, s);
+ chnames[nchnames][0] = type;
+/* fprintf(stderr, "installed %c%s at %d\n", type, s, nchnames); /* */
+ return nchnames++ + ALPHABET;
+}
+
+char *chname(int n) /* return string for char with index n */
+{ /* includes type char at front, to be peeled off elsewhere */
+ if (n >= ALPHABET && n < nchnames + ALPHABET)
+ return chnames[n-ALPHABET];
+ else
+ return "";
+}
+
+getlig(FILE *fin) /* pick up ligature list */
+{
+ int lig;
+ char temp[200];
+
+ lig = 0;
+ while (fscanf(fin, "%s", temp) != EOF && strcmp(temp, "0") != 0) {
+ if (strcmp(temp, "fi") == 0)
+ lig |= LFI;
+ else if (strcmp(temp, "fl") == 0)
+ lig |= LFL;
+ else if (strcmp(temp, "ff") == 0)
+ lig |= LFF;
+ else if (strcmp(temp, "ffi") == 0)
+ lig |= LFFI;
+ else if (strcmp(temp, "ffl") == 0)
+ lig |= LFFL;
+ else
+ fprintf(stderr, "illegal ligature %s ignored\n", temp);
+ }
+ return lig;
+}
diff --git a/src/cmd/troff/t6.c b/src/cmd/troff/t6.c
new file mode 100644
index 00000000..b778916c
--- /dev/null
+++ b/src/cmd/troff/t6.c
@@ -0,0 +1,881 @@
+/*
+ * t6.c
+ *
+ * width functions, sizes and fonts
+ */
+
+#include "tdef.h"
+#include "fns.h"
+#include "ext.h"
+
+int fontlab[MAXFONTS+1];
+int cstab[MAXFONTS+1];
+int ccstab[MAXFONTS+1];
+int bdtab[MAXFONTS+1];
+int sbold = 0;
+
+t_width(Tchar j)
+{
+ int i, k;
+
+ if (iszbit(j))
+ return 0;
+ if (ismot(j)) {
+ if (isvmot(j))
+ return(0);
+ k = absmot(j);
+ if (isnmot(j))
+ k = -k;
+ return(k);
+ }
+ i = cbits(j);
+ if (i < ' ') {
+ if (i == '\b')
+ return(-widthp);
+ if (i == PRESC)
+ i = eschar;
+ else if (i == HX)
+ return(0);
+ }
+ if (i == ohc)
+ return(0);
+ i = trtab[i];
+ if (i < ' ')
+ return(0);
+ if (sfbits(j) == oldbits) {
+ xfont = pfont;
+ xpts = ppts;
+ } else
+ xbits(j, 0);
+ if (i < nchnames + ALPHABET && widcache[i].fontpts == (xfont<<8) + xpts && !setwdf)
+ k = widcache[i].width;
+ else {
+ k = getcw(i);
+ if (bd)
+ k += (bd - 1) * HOR;
+ if (cs)
+ k = cs;
+ }
+ widthp = k;
+ return(k);
+}
+
+/*
+ * clear width cache-- s means just space
+ */
+void zapwcache(int s)
+{
+ int i;
+
+ if (s) {
+ widcache[' '].fontpts = 0;
+ return;
+ }
+ for (i=0; i<NWIDCACHE; i++)
+ widcache[i].fontpts = 0;
+}
+
+onfont(int n, int f) /* is char n on font f? */
+{
+ int i;
+ Font *fp = &fonts[f];
+ Chwid *cp, *ep;
+ char *np;
+
+ if (n < ALPHABET) {
+ if (fp->wp[n].num == n) /* ascii at front */
+ return n;
+ else
+ return -1;
+ }
+ cp = &fp->wp[ALPHABET];
+ ep = &fp->wp[fp->nchars];
+ for ( ; cp < ep; cp++) /* search others */
+ if (cp->num == n)
+ return cp - &fp->wp[0];
+ /* maybe it was a \N... */
+ np = chname(n);
+ if (*np == Number) {
+ i = atoi(np+1); /* sscanf(np+1, "%d", &i); */
+ cp = &fp->wp[0];
+ ep = &fp->wp[fp->nchars];
+ for ( ; cp < ep; cp++) { /* search others */
+ if (cp->code == i)
+ return cp - &fp->wp[0];
+ }
+ return -2; /* a \N that doesn't have an entry */
+ }
+ return -1; /* vanilla not found */
+}
+
+getcw(int i)
+{
+ int k, n, x;
+ Font *fp;
+ int nocache = 0;
+ if (i < ' ')
+ return 0;
+ bd = 0;
+ fp = &fonts[xfont];
+ if (i == ' ') { /* a blank */
+ k = (fp->spacewidth * spacesz + 6) / 12;
+ /* this nonsense because .ss cmd uses 1/36 em as its units */
+ /* and default is 12 */
+ } else if ((n = onfont(i, xfont)) >= 0) { /* on this font at n */
+ k = fp->wp[n].wid;
+ if (setwdf)
+ numtabp[CT].val |= fp->wp[n].kern;
+ } else if (n == -2) { /* \N with default width */
+
+ k = fp->defaultwidth;
+ } else { /* not on current font */
+ nocache = 1;
+ k = fp->defaultwidth; /* default-size space */
+ if (smnt) {
+ int ii, jj;
+ for (ii=smnt, jj=0; jj < nfonts; jj++, ii=ii % nfonts + 1) {
+ if ((n = onfont(i, ii)) >= 0) {
+ k = fonts[ii].wp[n].wid;
+ if (xfont == sbold)
+ bd = bdtab[ii];
+ if (setwdf)
+ numtabp[CT].val |= fonts[ii].wp[n].kern;
+ break;
+ }
+ }
+ }
+ }
+ if (!bd)
+ bd = bdtab[xfont];
+ if (cs = cstab[xfont]) {
+ nocache = 1;
+ if (ccs = ccstab[xfont])
+ x = ccs;
+ else
+ x = xpts;
+ cs = (cs * EMPTS(x)) / 36;
+ }
+ /* was (k & BYTEMASK); since .wid is unsigned, should never happen */
+ if (k < 0)
+ ERROR "can't happen: negative width %d in getcw %d\n", k, i WARN;
+ k = (k * xpts + (Unitwidth / 2)) / Unitwidth;
+ if (nocache|bd)
+ widcache[i].fontpts = 0;
+ else {
+ widcache[i].fontpts = (xfont<<8) + xpts;
+ widcache[i].width = k;
+ }
+ return(k);
+ /* Unitwidth is Units/Point, where
+ /* Units is the fundamental digitization
+ /* of the character set widths, and
+ /* Point is the number of goobies in a point
+ /* e.g., for cat, Units=36, Point=6, so Unitwidth=36/6=6
+ /* In effect, it's the size at which the widths
+ /* translate directly into units.
+ */
+}
+
+void xbits(Tchar i, int bitf)
+{
+ int k;
+
+ if(TROFF) {
+ xfont = fbits(i);
+ k = sbits(i);
+ if(k) {
+ xpts = pstab[k-1];
+ oldbits = sfbits(i);
+ pfont = xfont;
+ ppts = xpts;
+ return;
+ }
+ switch(bitf) {
+ case 0:
+ xfont = font;
+ xpts = pts;
+ break;
+ case 1:
+ xfont = pfont;
+ xpts = ppts;
+ break;
+ case 2:
+ xfont = mfont;
+ xpts = mpts;
+ }
+ }
+}
+
+
+/* these next two functions ought to be the same in troff and nroff, */
+/* but the data structures they search are different. */
+/* silly historical problem. */
+
+
+Tchar t_setch(int c)
+{
+ int j;
+ char temp[50];
+ char *s;
+
+ s = temp;
+ if (c == '(') { /* \(xx */
+ if ((*s++ = getach()) == 0 || (*s++ = getach()) == 0)
+ return(0);
+ } else { /* \C'...' */
+ c = getach();
+ while ((*s = getach()) != c && *s != 0 && s < temp + sizeof(temp) - 1)
+ s++;
+ }
+ *s = '\0';
+#ifdef UNICODE
+ return chadd(temp, Troffchar, Install) | chbits; /* add name even if haven't seen it */
+#else
+ if (NROFF) {
+ j = chadd(temp, Troffchar, Lookup);
+ if ( j == -1)
+ return 0;
+ else
+ return j | chbits;
+ } else
+ return chadd(temp, Troffchar, Install) | chbits; /* add name even if haven't seen it */
+
+#endif /*UNICODE*/
+}
+
+Tchar t_setabs(void) /* set absolute char from \N'...' */
+{
+ int n;
+ char temp[10];
+
+ getch(); /* delim */
+ n = 0;
+ n = inumb(&n);
+ getch(); /* delim */
+ if (nonumb)
+ return 0;
+ sprintf(temp, "%d", n); /* convert into "#n" */
+ n = chadd(temp, Number, Install);
+ return n | chbits;
+}
+
+
+/*
+ * fontlab[] is a cache that contains font information
+ * for each font.
+ * fontlab[] contains the 1- or 2-character name of the
+ * font current associated with that font.
+ * fonts 1..nfonts correspond to the mounted fonts;
+ * the last of these are the special fonts.
+ * If we don't use the (named) font in one of the
+ * standard positions, we install the name in the next
+ * free slot of fontlab[] and font[].
+ * Whenever we need info about the font, we
+ * read in the data into the next free slot with getfont.
+ * The ptfont() (t10.c) routine will tell
+ * the device filter to put the font always at position
+ * zero if xfont > nfonts, so no need to change these filters.
+ * Yes, this is a bit kludgy.
+ *
+ * This gives the new specs of findft:
+ * find the font name i, where i also can be a number.
+ * Installs the font(name) i when not present
+ * returns -1 on error
+ */
+
+
+t_findft(int i)
+{
+ int k;
+ Uchar *p;
+
+ p = unpair(i);
+
+ if (isdigit(p[0])) { /* first look for numbers */
+ k = p[0] - '0';
+ if (p[1] > 0 && isdigit(p[1]))
+ k = 10 * k + p[1] - '0';
+ if (k > 0 && k <= nfonts && k < smnt)
+ return(k); /* mounted font: .ft 3 */
+ if (fontlab[k] && k <= MAXFONTS) { /* translate */
+ return(k); /*number to a name */
+ } else {
+ fprintf(stderr, "troff: no font at position %d\n", k);
+ return(-1); /* wild number */
+ }
+ }
+
+ /*
+ * Now we look for font names
+ */
+ for (k = 1; fontlab[k] != i; k++) {
+ if (k > MAXFONTS)
+ return(-1); /* running out of fontlab space */
+ if (fontlab[k] == 0) { /* passed all existing names */
+ if (setfp(k, i, (char *) 0, 1) == -1)
+ return(-1);
+ else {
+ fontlab[k] = i; /* install the name */
+ return(k);
+ }
+ }
+ }
+ return(k); /* was one of the existing names */
+}
+
+
+void caseps(void)
+{
+ int i;
+
+ if (TROFF) {
+ if(skip())
+ i = apts1;
+ else {
+ noscale++;
+ i = inumb(&apts); /* this is a disaster for fractional point sizes */
+ noscale = 0;
+ if(nonumb)
+ i = apts1;
+ }
+ casps1(i);
+ }
+}
+
+
+void casps1(int i)
+{
+
+/*
+ * in olden times, it used to ignore changes to 0 or negative.
+ * this is meant to allow the requested size to be anything,
+ * in particular so eqn can generate lots of \s-3's and still
+ * get back by matching \s+3's.
+
+ if (i <= 0)
+ return;
+*/
+ apts1 = apts;
+ apts = i;
+ pts1 = pts;
+ pts = findps(i);
+ mchbits();
+}
+
+
+findps(int i)
+{
+ int j, k;
+
+ for (j=k=0 ; pstab[j] != 0 ; j++)
+ if (abs(pstab[j]-i) < abs(pstab[k]-i))
+ k = j;
+
+ return(pstab[k]);
+}
+
+
+void t_mchbits(void)
+{
+ int i, j, k;
+
+ i = pts;
+ for (j = 0; i > (k = pstab[j]); j++)
+ if (!k) {
+ j--;
+ break;
+ }
+ chbits = 0;
+ setsbits(chbits, ++j);
+ setfbits(chbits, font);
+ sps = width(' ' | chbits);
+ zapwcache(1);
+}
+
+void t_setps(void)
+{
+ int i, j;
+
+ i = cbits(getch());
+ if (isdigit(i)) { /* \sd or \sdd */
+ i -= '0';
+ if (i == 0) /* \s0 */
+ j = apts1;
+ else if (i <= 3 && (ch=getch()) && isdigit(j = cbits(ch))) { /* \sdd */
+ j = 10 * i + j - '0';
+ ch = 0;
+ } else /* \sd */
+ j = i;
+ } else if (i == '(') { /* \s(dd */
+ j = cbits(getch()) - '0';
+ j = 10 * j + cbits(getch()) - '0';
+ if (j == 0) /* \s(00 */
+ j = apts1;
+ } else if (i == '+' || i == '-') { /* \s+, \s- */
+ j = cbits(getch());
+ if (isdigit(j)) { /* \s+d, \s-d */
+ j -= '0';
+ } else if (j == '(') { /* \s+(dd, \s-(dd */
+ j = cbits(getch()) - '0';
+ j = 10 * j + cbits(getch()) - '0';
+ }
+ if (i == '-')
+ j = -j;
+ j += apts;
+ }
+ casps1(j);
+}
+
+
+Tchar t_setht(void) /* set character height from \H'...' */
+{
+ int n;
+ Tchar c;
+
+ getch();
+ n = inumb(&apts);
+ getch();
+ if (n == 0 || nonumb)
+ n = apts; /* does this work? */
+ c = CHARHT;
+ c |= ZBIT;
+ setsbits(c, n);
+ setfbits(c, pts); /* sneaky, CHARHT font bits are size bits */
+ return(c);
+}
+
+Tchar t_setslant(void) /* set slant from \S'...' */
+{
+ int n;
+ Tchar c;
+
+ getch();
+ n = 0;
+ n = inumb(&n);
+ getch();
+ if (nonumb)
+ n = 0;
+ c = SLANT;
+ c |= ZBIT;
+ setsfbits(c, n+180);
+ return(c);
+}
+
+
+void caseft(void)
+{
+ if (!TROFF) {
+ n_caseft();
+ return;
+ }
+ skip();
+ setfont(1);
+}
+
+
+void t_setfont(int a)
+{
+ int i, j;
+
+ if (a)
+ i = getrq();
+ else
+ i = getsn();
+ if (!i || i == 'P') {
+ j = font1;
+ goto s0;
+ }
+ if (/* i == 'S' || */ i == '0') /* an experiment -- why can't we change to it? */
+ return;
+ if ((j = findft(i)) == -1)
+ if ((j = setfp(0, i, (char*) 0, 1)) == -1) /* try to put it in position 0 */
+ return;
+s0:
+ font1 = font;
+ font = j;
+ mchbits();
+}
+
+
+void t_setwd(void)
+{
+ int base, wid;
+ Tchar i;
+ int delim, emsz, k;
+ int savhp, savapts, savapts1, savfont, savfont1, savpts, savpts1;
+
+ base = numtabp[ST].val = numtabp[SB].val = wid = numtabp[CT].val = 0;
+ if (ismot(i = getch()))
+ return;
+ delim = cbits(i);
+ savhp = numtabp[HP].val;
+ numtabp[HP].val = 0;
+ savapts = apts;
+ savapts1 = apts1;
+ savfont = font;
+ savfont1 = font1;
+ savpts = pts;
+ savpts1 = pts1;
+ setwdf++;
+ while (cbits(i = getch()) != delim && !nlflg) {
+ k = width(i);
+ wid += k;
+ numtabp[HP].val += k;
+ if (!ismot(i)) {
+ emsz = (INCH/72) * xpts;
+ } else if (isvmot(i)) {
+ k = absmot(i);
+ if (isnmot(i))
+ k = -k;
+ base -= k;
+ emsz = 0;
+ } else
+ continue;
+ if (base < numtabp[SB].val)
+ numtabp[SB].val = base;
+ if ((k = base + emsz) > numtabp[ST].val)
+ numtabp[ST].val = k;
+ }
+ setn1(wid, 0, (Tchar) 0);
+ numtabp[HP].val = savhp;
+ apts = savapts;
+ apts1 = savapts1;
+ font = savfont;
+ font1 = savfont1;
+ pts = savpts;
+ pts1 = savpts1;
+ mchbits();
+ setwdf = 0;
+}
+
+
+Tchar t_vmot(void)
+{
+ dfact = lss;
+ vflag++;
+ return t_mot();
+}
+
+
+Tchar t_hmot(void)
+{
+ dfact = EM;
+ return t_mot();
+}
+
+
+Tchar t_mot(void)
+{
+ int j, n;
+ Tchar i;
+
+ j = HOR;
+ getch(); /*eat delim*/
+ if (n = atoi0()) {
+ if (vflag)
+ j = VERT;
+ i = makem(quant(n, j));
+ } else
+ i = 0;
+ getch();
+ vflag = 0;
+ dfact = 1;
+ return(i);
+}
+
+
+Tchar t_sethl(int k)
+{
+ int j;
+ Tchar i;
+
+ j = EM / 2;
+ if (k == 'u')
+ j = -j;
+ else if (k == 'r')
+ j = -2 * j;
+ vflag++;
+ i = makem(j);
+ vflag = 0;
+ return(i);
+}
+
+
+Tchar t_makem(int i)
+{
+ Tchar j;
+
+ if (i >= 0)
+ j = i;
+ else
+ j = -i;
+ if (Hor > 1 && !vflag)
+ j = (j + Hor/2)/Hor * Hor;
+ j |= MOT;
+ if (i < 0)
+ j |= NMOT;
+ if (vflag)
+ j |= VMOT;
+ return(j);
+}
+
+
+Tchar getlg(Tchar i)
+{
+ Tchar j, k;
+ int lf;
+
+ if (!TROFF)
+ return i;
+ if ((lf = fonts[fbits(i)].ligfont) == 0) /* font lacks ligatures */
+ return(i);
+ j = getch0();
+ if (cbits(j) == 'i' && (lf & LFI))
+ j = LIG_FI;
+ else if (cbits(j) == 'l' && (lf & LFL))
+ j = LIG_FL;
+ else if (cbits(j) == 'f' && (lf & LFF)) {
+ if ((lf & (LFFI|LFFL)) && lg != 2) {
+ k = getch0();
+ if (cbits(k)=='i' && (lf&LFFI))
+ j = LIG_FFI;
+ else if (cbits(k)=='l' && (lf&LFFL))
+ j = LIG_FFL;
+ else {
+ *pbp++ = k;
+ j = LIG_FF;
+ }
+ } else
+ j = LIG_FF;
+ } else {
+ *pbp++ = j;
+ j = i;
+ }
+ return(i & SFMASK | j);
+}
+
+
+void caselg(void)
+{
+
+ if(TROFF) {
+ skip();
+ lg = atoi0();
+ if (nonumb)
+ lg = 1;
+ }
+}
+
+void casefp(void)
+{
+ int i, j;
+
+ if (!TROFF) {
+ n_casefp();
+ return;
+ }
+ skip();
+ i = cbits(getch());
+ if (isdigit(i)) {
+ i -= '0';
+ j = cbits(getch());
+ if (isdigit(j))
+ i = 10 * i + j - '0';
+ }
+ if (i <= 0 || i > nfonts)
+ ERROR "fp: bad font position %d", i WARN;
+ else if (skip() || !(j = getrq()))
+ ERROR "fp: no font name" WARN;
+ else if (skip() || !getname())
+ setfp(i, j, (char*) 0, 1);
+ else /* 3rd argument = filename */
+ setfp(i, j, nextf, 1);
+}
+
+char *strdupl(const char *s) /* make a copy of s */
+{
+ char *t;
+
+ t = (char *) malloc(strlen(s) + 1);
+ if (t == NULL)
+ ERROR "out of space in strdupl(%s)", s FATAL;
+ strcpy(t, s);
+ return t;
+}
+
+setfp(int pos, int f, char *truename, int print) /* mount font f at position pos[0...nfonts] */
+{
+ char pathname[NS], shortname[NS], *sl;
+
+ zapwcache(0);
+ if (truename)
+ strcpy(shortname, truename);
+ else
+ strcpy(shortname, (char *) unpair(f));
+ if (truename && strrchr(truename, '/')) { /* .fp 1 R dir/file: use verbatim */
+ sprintf(pathname, "%s", truename);
+ if (fonts[pos].truename)
+ free(fonts[pos].truename);
+ fonts[pos].truename = strdupl(truename);
+ } else if (truename) { /* synonym: .fp 1 R Avant */
+ sprintf(pathname, "%s/dev%s/%s", fontdir, devname, truename);
+ truename = 0; /* so doesn't get repeated by ptfpcmd */
+ } else /* vanilla: .fp 5 XX */
+ sprintf(pathname, "%s/dev%s/%s", fontdir, devname, shortname);
+ if (truename == 0 && fonts[pos].truename != 0) {
+ free(fonts[pos].truename);
+ fonts[pos].truename = 0;
+ }
+ if (getfont(pathname, pos) < 0) {
+ ERROR "Can't open font file %s", pathname WARN;
+ return -1;
+ }
+ if (print && !ascii) {
+ ptfpcmd(pos, fonts[pos].longname, truename);
+ ptfont();
+ }
+ if (pos == smnt) {
+ smnt = 0;
+ sbold = 0;
+ }
+ fontlab[pos] = f;
+ if (smnt == 0 && fonts[pos].specfont)
+ smnt = pos;
+ bdtab[pos] = cstab[pos] = ccstab[pos] = 0;
+ return pos;
+}
+
+/*
+ * .cs request; don't check legality of optional arguments
+ */
+void casecs(void)
+{
+ int i, j;
+
+ if (TROFF) {
+ int savtr = trace;
+
+ trace = 0;
+ noscale++;
+ skip();
+ if (!(i = getrq()) || (i = findft(i)) < 0)
+ goto rtn;
+ skip();
+ cstab[i] = atoi0();
+ skip();
+ j = atoi0();
+ if(nonumb)
+ ccstab[i] = 0;
+ else
+ ccstab[i] = findps(j);
+ rtn:
+ zapwcache(0);
+ noscale = 0;
+ trace = savtr;
+ }
+}
+
+
+void casebd(void)
+{
+ int i, j, k;
+
+ if (!TROFF) {
+ n_casebd();
+ return;
+ }
+ zapwcache(0);
+ k = 0;
+bd0:
+ if (skip() || !(i = getrq()) || (j = findft(i)) == -1) {
+ if (k)
+ goto bd1;
+ else
+ return;
+ }
+ if (j == smnt) {
+ k = smnt;
+ goto bd0;
+ }
+ if (k) {
+ sbold = j;
+ j = k;
+ }
+bd1:
+ skip();
+ noscale++;
+ bdtab[j] = atoi0();
+ noscale = 0;
+}
+
+
+void casevs(void)
+{
+ int i;
+
+ if (!TROFF) {
+ n_casevs();
+ return;
+ }
+ skip();
+ vflag++;
+ dfact = INCH; /* default scaling is points! */
+ dfactd = 72;
+ res = VERT;
+ i = inumb(&lss);
+ if (nonumb)
+ i = lss1;
+ if (i < VERT)
+ i = VERT;
+ lss1 = lss;
+ lss = i;
+}
+
+
+void casess(void)
+{
+ int i;
+
+ if(TROFF) {
+ noscale++;
+ skip();
+ if(i = atoi0()) {
+ spacesz = i & 0177;
+ zapwcache(0);
+ sps = width(' ' | chbits);
+ }
+ noscale = 0;
+ }
+}
+
+
+Tchar t_xlss(void)
+{
+ /* stores \x'...' into two successive Tchars.
+ /* the first contains HX, the second the value,
+ /* encoded as a vertical motion.
+ /* decoding is done in n2.c by pchar().
+ */
+ int i;
+
+ getch();
+ dfact = lss;
+ i = quant(atoi0(), VERT);
+ dfact = 1;
+ getch();
+ if (i >= 0)
+ *pbp++ = MOT | VMOT | i;
+ else
+ *pbp++ = MOT | VMOT | NMOT | -i;
+ return(HX);
+}
+
+Uchar *unpair(int i)
+{
+ static Uchar name[3];
+
+ name[0] = i & SHORTMASK;
+ name[1] = (i >> SHORT) & SHORTMASK;
+ name[2] = 0;
+ return name;
+}
diff --git a/src/cmd/troff/tdef.h b/src/cmd/troff/tdef.h
new file mode 100644
index 00000000..e9e1f65c
--- /dev/null
+++ b/src/cmd/troff/tdef.h
@@ -0,0 +1,670 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <ctype.h>
+#include <string.h>
+
+#define NROFF (!TROFF)
+
+
+/* Site dependent definitions */
+
+#ifndef TMACDIR
+#define TMACDIR "lib/tmac/tmac."
+#endif
+#ifndef FONTDIR
+#define FONTDIR "lib/font"
+#endif
+#ifndef NTERMDIR
+#define NTERMDIR "lib/term/tab."
+#endif
+#ifndef TDEVNAME
+#define TDEVNAME "post"
+#endif
+#ifndef NDEVNAME
+#define NDEVNAME "37"
+#endif
+#ifndef TEXHYPHENS
+#define TEXHYPHENS "/usr/lib/tex/macros/hyphen.tex"
+#endif
+#ifndef ALTHYPHENS
+#define ALTHYPHENS "lib/tmac/hyphen.tex" /* another place to look */
+#endif
+
+typedef unsigned char Uchar;
+typedef unsigned short Ushort;
+
+typedef /*unsigned*/ long Tchar;
+
+typedef struct Blockp Blockp;
+typedef struct Diver Diver;
+typedef struct Stack Stack;
+typedef struct Divsiz Divsiz;
+typedef struct Contab Contab;
+typedef struct Numtab Numtab;
+typedef struct Numerr Numerr;
+typedef struct Env Env;
+typedef struct Term Term;
+typedef struct Chwid Chwid;
+typedef struct Font Font;
+typedef struct Spnames Spnames;
+typedef struct Wcache Wcache;
+typedef struct Tbuf Tbuf;
+
+/* this simulates printf into a buffer that gets flushed sporadically */
+/* the BSD goo is because SunOS sprintf doesn't return anything useful */
+
+#ifdef BSD4_2
+#define OUT (obufp += strlen(sprintf(obufp,
+#define PUT ))) > obuf+BUFSIZ ? flusho() : 1
+#else
+#define OUT (obufp += sprintf(obufp,
+#define PUT )) > obuf+BUFSIZ ? flusho() : 1
+#endif
+
+#define oputs(a) OUT "%s", a PUT
+#define oput(c) ( *obufp++ = (c), obufp > obuf+BUFSIZ ? flusho() : 1 )
+
+extern char errbuf[];
+#define ERROR sprintf(errbuf,
+#define WARN ), errprint()
+#define FATAL ), errprint(), exit(1)
+
+/* starting values for typesetting parameters: */
+
+#define PS 10 /* default point size */
+#define FT 1 /* default font position */
+#define ULFONT 2 /* default underline font */
+#define BDFONT 3 /* default emboldening font */
+#define BIFONT 4 /* default bold italic font */
+#define LL (unsigned) 65*INCH/10 /* line length; 39picas=6.5in */
+#define VS ((12*INCH)/72) /* initial vert space */
+
+
+#define EMPTS(pts) (((long)Inch*(pts) + 36) / 72)
+#define EM (TROFF? EMPTS(pts): t.Em)
+#define INCH (TROFF? Inch: 240)
+#define HOR (TROFF? Hor: t.Adj)
+#define VERT (TROFF? Vert: t.Vert)
+#define PO (TROFF? Inch: 0)
+#define SPS (TROFF? EMPTS(pts)/3: INCH/10)
+#define SS (TROFF? 12: INCH/10)
+#define ICS (TROFF? EMPTS(pts): 2*INCH/10)
+#define DTAB (TROFF? (INCH/2): 0)
+
+/* These "characters" are used to encode various internal functions
+/* Some make use of the fact that most ascii characters between
+/* 0 and 040 don't have any graphic or other function.
+/* The few that do have a purpose (e.g., \n, \b, \t, ...
+/* are avoided by the ad hoc choices here.
+/* See ifilt[] in n1.c for others -- 1, 2, 3, 5, 6, 7, 010, 011, 012
+*/
+
+#define LEADER 001
+#define IMP 004 /* impossible char; glues things together */
+#define TAB 011
+#define RPT 014 /* next character is to be repeated many times */
+#define CHARHT 015 /* size field sets character height */
+#define SLANT 016 /* size field sets amount of slant */
+#define DRAWFCN 017 /* next several chars describe arb drawing fcns */
+# define DRAWLINE 'l' /* line: 'l' dx dy char */
+# define DRAWCIRCLE 'c' /* circle: 'c' r */
+# define DRAWELLIPSE 'e' /* ellipse: 'e' rx ry */
+# define DRAWARC 'a' /* arc: 'a' dx dy dx dy */
+# define DRAWSPLINE '~' /* quadratic B spline: '~' dx dy dx dy ... */
+ /* other splines go thru too */
+/* NOTE: the use of ~ is a botch since it's often used in .tr commands */
+/* better to use a letter like s, but change it in the postprocessors too */
+/* for now, this is taken care of in n9.c and t10.c */
+# define DRAWBUILD 'b' /* built-up character (e.g., { */
+
+#define LEFT 020 /* \{ */
+#define RIGHT 021 /* \} */
+#define FILLER 022 /* \& and similar purposes */
+#define XON 023 /* \X'...' starts here */
+#define OHC 024 /* optional hyphenation character \% */
+#define CONT 025 /* \c character */
+#define PRESC 026 /* printable escape */
+#define UNPAD 027 /* unpaddable blank */
+#define XPAR 030 /* transparent mode indicator */
+#define FLSS 031 /* next Tchar contains vertical space */
+ /* used when recalling diverted text */
+#define WORDSP 032 /* paddable word space */
+#define ESC 033 /* current escape character */
+#define XOFF 034 /* \X'...' ends here */
+ /* matches XON, but they will probably never nest */
+ /* so could drop this when another control is needed */
+#define HX 035 /* next character is value of \x'...' */
+#define MOTCH 036 /* this "character" is really motion; used by cbits() */
+
+#define HYPHEN c_hyphen
+#define EMDASH c_emdash /* \(em */
+#define RULE c_rule /* \(ru */
+#define MINUS c_minus /* minus sign on current font */
+#define LIG_FI c_fi /* \(ff */
+#define LIG_FL c_fl /* \(fl */
+#define LIG_FF c_ff /* \(ff */
+#define LIG_FFI c_ffi /* \(Fi */
+#define LIG_FFL c_ffl /* \(Fl */
+#define ACUTE c_acute /* acute accent \(aa */
+#define GRAVE c_grave /* grave accent \(ga */
+#define UNDERLINE c_under /* \(ul */
+#define ROOTEN c_rooten /* root en \(rn */
+#define BOXRULE c_boxrule /* box rule \(br */
+#define LEFTHAND c_lefthand /* left hand for word overflow */
+#define DAGGER c_dagger /* dagger for end of sentence/footnote */
+
+#define HYPHALG 1 /* hyphenation algorithm: 0=>good old troff, 1=>tex */
+
+
+/* array sizes, and similar limits: */
+
+#define MAXFONTS 99 /* Maximum number of fonts in fontab */
+#define NM 90 /* requests + macros */
+#define NN NNAMES /* number registers */
+#define NNAMES 15 /* predefined reg names */
+#define NIF 15 /* if-else nesting */
+#define NS 128 /* name buffer */
+#define NTM 1024 /* tm buffer */
+#define NEV 3 /* environments */
+#define EVLSZ 10 /* size of ev stack */
+
+#define STACKSIZE (6*1024) /* stack for macros and strings in progress */
+#define NHYP 10 /* max hyphens per word */
+#define NHEX 512 /* byte size of exception word list */
+#define NTAB 100 /* tab stops */
+#define NSO 5 /* "so" depth */
+#define NMF 5 /* number of -m flags */
+#define WDSIZE 500 /* word buffer click size */
+#define LNSIZE 4000 /* line buffer click size */
+#define OLNSIZE 5000 /* output line buffer click; bigger for 'w', etc. */
+#define NDI 5 /* number of diversions */
+
+#define ALPHABET alphabet /* number of characters in basic alphabet. */
+ /* 128 for parochial USA 7-bit ascii, */
+ /* 256 for "European" mode with e.g., Latin-1 */
+
+ /* NCHARS must be greater than
+ ALPHABET (ascii stuff) + total number of distinct char names
+ from all fonts that will be run in this job (including
+ unnamed ones and \N's)
+ */
+
+#define NCHARS (8*1024) /* maximum size of troff character set*/
+
+
+ /* However for nroff you want only :
+ 1. number of special codes in charset of DESC, which ends up being the
+ value of nchtab and which must be less than 512.
+ 2. ALPHABET, which apparently is the size of the portion of the tables reserved
+ for special control symbols
+ Apparently the max N of \N is irrelevant; */
+ /* to allow \N of up to 254 with up to 338 special characters
+ you need NCHARS of 338 + ALPHABET = 466 */
+
+#define NROFFCHARS 1024 /* maximum size of nroff character set */
+
+#define NTRTAB NCHARS /* number of items in trtab[] */
+#define NWIDCACHE NCHARS /* number of items in widcache[] */
+
+#define NTRAP 20 /* number of traps */
+#define NPN 20 /* numbers in "-o" */
+#define FBUFSZ 512 /* field buf size words */
+#define IBUFSZ 4096 /* bytes */
+#define NC 1024 /* cbuf size words */
+#define NOV 10 /* number of overstrike chars */
+#define NPP 10 /* pads per field */
+
+/*
+ Internal character representation:
+ Internally, every character is carried around as
+ a 32 bit cookie, called a "Tchar" (typedef long).
+ Bits are numbered 31..0 from left to right.
+ If bit 15 is 1, the character is motion, with
+ if bit 16 it's vertical motion
+ if bit 17 it's negative motion
+ If bit 15 is 0, the character is a real character.
+ if bit 31 zero motion
+ bits 30..24 size
+ bits 23..16 font
+*/
+
+/* in the following, "L" should really be a Tchar, but ... */
+/* numerology leaves room for 16 bit chars */
+
+#define MOT (01uL << 16) /* motion character indicator */
+#define VMOT (01uL << 30) /* vertical motion bit */
+#define NMOT (01uL << 29) /* negative motion indicator */
+/* #define MOTV (MOT|VMOT|NMOT) /* motion flags */
+/* #define MAXMOT (~MOTV) /* maximum motion permitted */
+#define MAXMOT 0xFFFF
+
+#define ismot(n) ((n) & MOT)
+#define isvmot(n) (((n) & (MOT|VMOT)) == (MOT|VMOT)) /* must have tested MOT previously */
+#define isnmot(n) (((n) & (MOT|NMOT)) == (MOT|NMOT)) /* ditto */
+#define absmot(n) ((n) & 0xFFFF)
+
+#define ZBIT (01uL << 31) /* zero width char */
+#define iszbit(n) ((n) & ZBIT)
+
+#define FSHIFT 17
+#define SSHIFT (FSHIFT+7)
+#define SMASK (0177uL << SSHIFT) /* 128 distinct sizes */
+#define FMASK (0177uL << FSHIFT) /* 128 distinct fonts */
+#define SFMASK (SMASK|FMASK) /* size and font in a Tchar */
+#define sbits(n) (((n) >> SSHIFT) & 0177)
+#define fbits(n) (((n) >> FSHIFT) & 0177)
+#define sfbits(n) (((n) & SFMASK) >> FSHIFT)
+#define cbits(n) ((n) & 0x1FFFF) /* isolate character bits, */
+ /* but don't include motions */
+extern int realcbits(Tchar);
+
+#define setsbits(n,s) n = (n & ~SMASK) | (Tchar)(s) << SSHIFT
+#define setfbits(n,f) n = (n & ~FMASK) | (Tchar)(f) << FSHIFT
+#define setsfbits(n,sf) n = (n & ~SFMASK) | (Tchar)(sf) << FSHIFT
+#define setcbits(n,c) n = (n & ~0xFFFFuL | (c)) /* set character bits */
+
+#define BYTEMASK 0377
+#define BYTE 8
+
+#define SHORTMASK 0XFFFF
+#define SHORT 16
+
+#define TABMASK ((unsigned) INT_MAX >> 1)
+#define RTAB ((TABMASK << 1) & ~TABMASK)
+#define CTAB (RTAB << 1)
+
+#define TABBIT 02 /* bits in gchtab */
+#define LDRBIT 04
+#define FCBIT 010
+
+#define PAIR(A,B) (A|(B<<SHORT))
+
+
+extern int Inch, Hor, Vert, Unitwidth;
+
+struct Spnames
+{
+ int *n;
+ char *v;
+};
+
+extern Spnames spnames[];
+
+/*
+ String and macro definitions are stored conceptually in a giant array
+ indexed by type Offset. In olden times, this array was real, and thus
+ both huge and limited in size, leading to the "Out of temp file space"
+ error. In this version, the array is represented by a list of blocks,
+ pointed to by blist[].bp. Each block is of size BLK Tchars, and BLK
+ MUST be a power of 2 for the macros below to work.
+
+ The blocks associated with a particular string or macro are chained
+ together in the array blist[]. Each blist[i].nextoff contains the
+ Offset associated with the next block in the giant array, or -1 if
+ this is the last block in the chain. If .nextoff is 0, the block is
+ free.
+
+ To find the right index in blist for an Offset, divide by BLK.
+*/
+
+#define NBLIST 2048 /* starting number of blocks in all definitions */
+
+#define BLK 128 /* number of Tchars in a block; must be 2^N with defns below */
+
+#define rbf0(o) (blist[bindex(o)].bp[boffset(o)])
+#define bindex(o) ((o) / BLK)
+#define boffset(o) ((o) & (BLK-1))
+#define pastend(o) (((o) & (BLK-1)) == 0)
+/* #define incoff(o) ( (++o & (BLK-1)) ? o : blist[bindex(o-1)].nextoff ) */
+#define incoff(o) ( (((o)+1) & (BLK-1)) ? o+1 : blist[bindex(o)].nextoff )
+
+#define skipline(f) while (getc(f) != '\n')
+#define is(s) (strcmp(cmd, s) == 0)
+#define eq(s1, s2) (strcmp(s1, s2) == 0)
+
+
+typedef unsigned long Offset; /* an offset in macro/string storage */
+
+struct Blockp { /* info about a block: */
+ Tchar *bp; /* the data */
+ Offset nextoff; /* offset of next block in a chain */
+};
+
+extern Blockp *blist;
+
+#define RD_OFFSET (1 * BLK) /* .rd command uses block 1 */
+
+struct Diver { /* diversion */
+ Offset op;
+ int dnl;
+ int dimac;
+ int ditrap;
+ int ditf;
+ int alss;
+ int blss;
+ int nls;
+ int mkline;
+ int maxl;
+ int hnl;
+ int curd;
+};
+
+struct Stack { /* stack frame */
+ int nargs;
+ Stack *pframe;
+ Offset pip;
+ int pnchar;
+ Tchar prchar;
+ int ppendt;
+ Tchar pch;
+ Tchar *lastpbp;
+ int mname;
+};
+
+extern Stack s;
+
+struct Divsiz {
+ int dix;
+ int diy;
+};
+
+struct Contab { /* command or macro */
+ unsigned int rq;
+ Contab *link;
+ void (*f)(void);
+ Offset mx;
+ Offset emx;
+ Divsiz *divsiz;
+};
+
+#define C(a,b) {a, 0, b, 0, 0} /* how to initialize a contab entry */
+
+extern Contab contab[NM];
+
+struct Numtab { /* number registers */
+ unsigned int r; /* name */
+ int val;
+ short fmt;
+ short inc;
+ Numtab *link;
+};
+
+extern Numtab numtab[NN];
+
+#define PN 0
+#define NL 1
+#define YR 2
+#define HP 3
+#define CT 4
+#define DN 5
+#define MO 6
+#define DY 7
+#define DW 8
+#define LN 9
+#define DL 10
+#define ST 11
+#define SB 12
+#define CD 13
+#define PID 14
+
+struct Wcache { /* width cache, indexed by character */
+ short fontpts;
+ short width;
+};
+
+struct Tbuf { /* growable Tchar buffer */
+ Tchar *_bufp;
+ unsigned int _size;
+};
+
+/* the infamous environment block */
+
+#define ics envp->_ics
+#define sps envp->_sps
+#define spacesz envp->_spacesz
+#define lss envp->_lss
+#define lss1 envp->_lss1
+#define ll envp->_ll
+#define ll1 envp->_ll1
+#define lt envp->_lt
+#define lt1 envp->_lt1
+#define ic envp->_ic
+#define icf envp->_icf
+#define chbits envp->_chbits
+#define spbits envp->_spbits
+#define nmbits envp->_nmbits
+#define apts envp->_apts
+#define apts1 envp->_apts1
+#define pts envp->_pts
+#define pts1 envp->_pts1
+#define font envp->_font
+#define font1 envp->_font1
+#define ls envp->_ls
+#define ls1 envp->_ls1
+#define ad envp->_ad
+#define nms envp->_nms
+#define ndf envp->_ndf
+#define nmwid envp->_nmwid
+#define fi envp->_fi
+#define cc envp->_cc
+#define c2 envp->_c2
+#define ohc envp->_ohc
+#define tdelim envp->_tdelim
+#define hyf envp->_hyf
+#define hyoff envp->_hyoff
+#define hyphalg envp->_hyphalg
+#define un1 envp->_un1
+#define tabc envp->_tabc
+#define dotc envp->_dotc
+#define adsp envp->_adsp
+#define adrem envp->_adrem
+#define lastl envp->_lastl
+#define nel envp->_nel
+#define admod envp->_admod
+#define wordp envp->_wordp
+#define spflg envp->_spflg
+#define linep envp->_linep
+#define wdend envp->_wdend
+#define wdstart envp->_wdstart
+#define wne envp->_wne
+#define ne envp->_ne
+#define nc envp->_nc
+#define nb envp->_nb
+#define lnmod envp->_lnmod
+#define nwd envp->_nwd
+#define nn envp->_nn
+#define ni envp->_ni
+#define ul envp->_ul
+#define cu envp->_cu
+#define ce envp->_ce
+#define in envp->_in
+#define in1 envp->_in1
+#define un envp->_un
+#define wch envp->_wch
+#define pendt envp->_pendt
+#define pendw envp->_pendw
+#define pendnf envp->_pendnf
+#define spread envp->_spread
+#define it envp->_it
+#define itmac envp->_itmac
+#define hyptr envp->_hyptr
+#define tabtab envp->_tabtab
+#define line envp->_line._bufp
+#define lnsize envp->_line._size
+#define word envp->_word._bufp
+#define wdsize envp->_word._size
+
+#define oline _oline._bufp
+#define olnsize _oline._size
+
+/*
+ * Note:
+ * If this structure changes in ni.c, you must change
+ * this as well, and vice versa.
+ */
+
+struct Env {
+ int _ics;
+ int _sps;
+ int _spacesz;
+ int _lss;
+ int _lss1;
+ int _ll;
+ int _ll1;
+ int _lt;
+ int _lt1;
+ Tchar _ic;
+ int _icf;
+ Tchar _chbits;
+ Tchar _spbits;
+ Tchar _nmbits;
+ int _apts;
+ int _apts1;
+ int _pts;
+ int _pts1;
+ int _font;
+ int _font1;
+ int _ls;
+ int _ls1;
+ int _ad;
+ int _nms;
+ int _ndf;
+ int _nmwid;
+ int _fi;
+ int _cc;
+ int _c2;
+ int _ohc;
+ int _tdelim;
+ int _hyf;
+ int _hyoff;
+ int _hyphalg;
+ int _un1;
+ int _tabc;
+ int _dotc;
+ int _adsp;
+ int _adrem;
+ int _lastl;
+ int _nel;
+ int _admod;
+ Tchar *_wordp;
+ int _spflg;
+ Tchar *_linep;
+ Tchar *_wdend;
+ Tchar *_wdstart;
+ int _wne;
+ int _ne;
+ int _nc;
+ int _nb;
+ int _lnmod;
+ int _nwd;
+ int _nn;
+ int _ni;
+ int _ul;
+ int _cu;
+ int _ce;
+ int _in;
+ int _in1;
+ int _un;
+ int _wch;
+ int _pendt;
+ Tchar *_pendw;
+ int _pendnf;
+ int _spread;
+ int _it;
+ int _itmac;
+ Tchar *_hyptr[NHYP];
+ long _tabtab[NTAB];
+ Tbuf _line;
+ Tbuf _word;
+};
+
+extern Env env[];
+extern Env *envp;
+
+enum { MBchar = 'U', Troffchar = 'C', Number = 'N', Install = 'i', Lookup = 'l' };
+ /* U => utf, for instance; C => \(xx, N => \N'...' */
+
+
+
+struct Chwid { /* data on one character */
+ Ushort num; /* character number:
+ 0 -> not on this font
+ >= ALPHABET -> its number among all Cxy's */
+ Ushort code; /* char code for actual device. used for \N */
+ char *str; /* code string for nroff */
+ Uchar wid; /* width */
+ Uchar kern; /* ascender/descender */
+};
+
+struct Font { /* characteristics of a font */
+ int name; /* int name, e.g., BI (2 chars) */
+ char longname[64]; /* long name of this font (e.g., "Bembo" */
+ char *truename; /* path name of table if not in standard place */
+ int nchars; /* number of width entries for this font */
+ char specfont; /* 1 == special font */
+ int spacewidth; /* width of space on this font */
+ int defaultwidth; /* default width of characters on this font */
+ Chwid *wp; /* widths, etc., of the real characters */
+ char ligfont; /* 1 == ligatures exist on this font */
+};
+
+/* ligatures, ORed into ligfont */
+
+#define LFF 01
+#define LFI 02
+#define LFL 04
+#define LFFI 010
+#define LFFL 020
+
+/* tracing modes */
+#define TRNARGS 01 /* trace legality of numeric arguments */
+#define TRREQ 02 /* trace requests */
+#define TRMAC 04 /* trace macros */
+#define RQERR 01 /* processing request/macro */
+
+/* typewriter driving table structure */
+
+
+extern Term t;
+struct Term {
+ int bset; /* these bits have to be on */
+ int breset; /* these bits have to be off */
+ int Hor; /* #units in minimum horiz motion */
+ int Vert; /* #units in minimum vert motion */
+ int Newline; /* #units in single line space */
+ int Char; /* #units in character width */
+ int Em; /* ditto */
+ int Halfline; /* half line units */
+ int Adj; /* minimum units for horizontal adjustment */
+ char *twinit; /* initialize terminal */
+ char *twrest; /* reinitialize terminal */
+ char *twnl; /* terminal sequence for newline */
+ char *hlr; /* half-line reverse */
+ char *hlf; /* half-line forward */
+ char *flr; /* full-line reverse */
+ char *bdon; /* turn bold mode on */
+ char *bdoff; /* turn bold mode off */
+ char *iton; /* turn italic mode on */
+ char *itoff; /* turn italic mode off */
+ char *ploton; /* turn plot mode on */
+ char *plotoff; /* turn plot mode off */
+ char *up; /* sequence to move up in plot mode */
+ char *down; /* ditto */
+ char *right; /* ditto */
+ char *left; /* ditto */
+
+ Font tfont; /* widths and other info, as in a troff font */
+};
+
+extern Term t;
+
+/*
+ * for error reporting; keep track of escapes/requests with numeric arguments
+ */
+struct Numerr {
+ char type; /* request or escape? */
+ char esc; /* was escape sequence named esc */
+ char escarg; /* argument of esc's like \D'l' */
+ unsigned int req; /* was request or macro named req */
+};
diff --git a/src/cmd/troff/unansi b/src/cmd/troff/unansi
new file mode 100644
index 00000000..67aed817
--- /dev/null
+++ b/src/cmd/troff/unansi
@@ -0,0 +1,49 @@
+# The awk program cvt will convert the relatively sterotyped ansi c
+# in this troff distribution into older-style c, by munging function
+# declarations.
+
+# You will also have to edit fns.h, by
+# sed 's/(.*)/()/g' fns.h >foo; mv foo fns.h
+# check this before doing the move!
+
+# you will also have to make some editing changes in
+# tdef.h in the Contab structure: s/(void)/()/
+# you may have to fix up some function declarations
+# in n4.c, the ones with (*f)(Tchar).
+
+# you will surely also have header files to deal with.
+
+# the most obvious cases are dealt with by the following
+# commands. make sure you do this stuff on a copy!
+
+# function prototypes in n8.c probably belong in fns.h. readpats(void) must
+# be readpats() before cvt runs.
+
+sed \
+ -e 's/(void)/()/' \
+ -e 's/(Tchar[^)]*);/();/' \
+ -e 's/(char[^)]*);/();/' \
+ -e 's/(int[^)]*);/();/' \
+n8.c >foo
+mv foo n8.c
+
+for i in *.c
+do
+ cvt $i >foo
+ mv foo $i
+done
+
+sed 's/(.*)/()/g' fns.h >foo
+mv foo fns.h
+
+sed -e 's/(void)/()/g' -e '/stdlib/d' tdef.h >foo
+mv foo tdef.h
+
+# Compliers may not approve of void *setbrk() in fns.h and n3.c.
+
+sed 's/^void\*[ ]setbrk/char* setbrk/' fns.h >foo
+mv foo fns.h
+
+sed 's/^void \*setbrk/char *setbrk/' n3.c >foo
+mv foo n3.c
+