summaryrefslogtreecommitdiff
path: root/support/RTF-1_06a1
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/RTF-1_06a1
Initial commit
Diffstat (limited to 'support/RTF-1_06a1')
-rw-r--r--support/RTF-1_06a1/1.05-changes132
-rw-r--r--support/RTF-1_06a1/1.06-changes67
-rw-r--r--support/RTF-1_06a1/Imakefile105
-rw-r--r--support/RTF-1_06a1/Makefile425
-rw-r--r--support/RTF-1_06a1/Notes43
-rw-r--r--support/RTF-1_06a1/Porting30
-rw-r--r--support/RTF-1_06a1/README67
-rw-r--r--support/RTF-1_06a1/nwidth.trf40
-rw-r--r--support/RTF-1_06a1/reader.c1380
-rw-r--r--support/RTF-1_06a1/rtf-misc.ms203
-rw-r--r--support/RTF-1_06a1/rtf.h484
-rw-r--r--support/RTF-1_06a1/rtf.ms896
-rw-r--r--support/RTF-1_06a1/rtf2null.c55
-rw-r--r--support/RTF-1_06a1/rtf2text.c264
-rw-r--r--support/RTF-1_06a1/rtf2troff.c1140
-rw-r--r--support/RTF-1_06a1/rtf2troff.h289
-rw-r--r--support/RTF-1_06a1/rtf2troff.ms649
-rw-r--r--support/RTF-1_06a1/rtfdiag.c121
-rw-r--r--support/RTF-1_06a1/rtfindent.c109
-rw-r--r--support/RTF-1_06a1/rtfskel.c801
-rw-r--r--support/RTF-1_06a1/rtfwc.c131
-rw-r--r--support/RTF-1_06a1/trf-charmap.c364
-rw-r--r--support/RTF-1_06a1/trf-flush.c1157
-rw-r--r--support/RTF-1_06a1/trf-nwid.c91
-rw-r--r--support/RTF-1_06a1/trf-stack.c263
-rw-r--r--support/RTF-1_06a1/trf-table.c289
26 files changed, 9595 insertions, 0 deletions
diff --git a/support/RTF-1_06a1/1.05-changes b/support/RTF-1_06a1/1.05-changes
new file mode 100644
index 0000000000..9ff405538b
--- /dev/null
+++ b/support/RTF-1_06a1/1.05-changes
@@ -0,0 +1,132 @@
+Changes for distribution 1.05
+-----------------------------
+
+-----------------------------
+the RTF reader:
+
+unsigned chars are no longer used in the reader since the RTF specification
+implies a 7-bit character set. I was not sure about that before so used
+unsigned characters to be safe. The "get character" function still checks
+input characters, and panics if an 8-bit character is seen.
+
+Fixed bug in _RTFToken() where, if a control word was delimited by a space,
+the space was left at the end of rtfTextBuf.
+
+Color values in color table entries are -1 if the values were not specified
+for the entry. That means the default color should be used. In earlier
+versions, color 0 was assumed to be the default, but since any entry can
+be left unspecified, including the entry for color 0, the default color
+is left to the writer to decide.
+
+Instead of ignoring \r and \<10>, and treating \n like \par, \r and \n
+are ignored, and \<10> and \<13> are treated like \par.
+
+The font table destination reader now recognizes old style font tables,
+where entries in the table are not surrounded by braces.
+
+Fixed the stylesheet reader to recognize \sbasedon and \snext explicitly
+and use them to set the corresponding fields of RTFStyle structs accordingly,
+which it didn't do previously. Worse, none of the elements of the style were
+attached except the last. This means that style expansion was completely
+broken in 1.04. (Real brain-o-matic programming. Duh. Blush.)
+
+It also turns out that automatic style expansion (i.e., with no writer
+intervention required) is the wrong thing to do (due to the circumstances
+under which tabstops are overridden), so it's now up to the writer to
+call RTFExpandStyle() explicitly. There is little loss in this since
+style expansion was broken anyway.
+
+RTFGetFont(), RTFGetColor() and RTFGetStyle() didn't work unless you
+passed an argument of -1 or 0. Fixed.
+
+RTFInit() can be called multiple times for translators that wish to
+translate multiple files. Formerly the internal state that was built
+up would not have been disposed of.
+
+The reader now recognizes roughly 300 control symbols, or about twice as
+many as before. Some of the #define'd constant names have changed:
+
+rtfBrace -> rtfGroup
+rtfLBrace -> rtfBeginGroup
+rtfRBrace -> rtfEndGroup
+
+[rtfDestination, rtfRtf] -> [rtfVersion, -1]
+ Version number is parameter
+
+[rtfMacintosh, -1] -> [rtfCharSet, rtfMacChar]
+
+rtfFontStyle -> rtfFontFamily
+ Minor number symbols have different names, also.
+ rtfFType field of RTFColor structure changed correspondingly.
+
+rtfColorNum -> rtfForeColor
+
+rtfCurFNotePage ->rtfCurFNote
+
+rtfEndNotes -> rtfFNoteEndSect
+
+rtfLineRestart1 -> rtfLineRestart
+ This was a typo
+
+rtfAutoPageX -> rtfPageNumLeft
+rtfAutoPageY -> rtfPageNumTop
+
+rtfColumnWid -> rtfColumnSpace
+
+rtfComment -> rtfIComment
+
+rtfNewline was deleted
+rtfPageContinuous was deleted (use rtfPageCont)
+
+rtfCurPict (for \chpict) may be bogus. I'm not sure if \chpict is
+a legitimate control symbol or not.
+
+
+The functional interface also has many name changes and additions.
+
+RTFReadHook() -> RTFSetReadHook()
+Added RTFGetReadHook().
+
+RTFClassCallback() -> RTFSetClassCallback()
+Added RTFGetClassCallback().
+
+RTFDestinationCallback() -> RTFSetDestinationCallback()
+Added RTFGetDestinationCallback().
+
+Added RTFSkipGroup().
+Added RTFExpandStyle().
+Added RTFCheckCM(), RTFCheckCMM(), RTFCheckMM().
+Added RTFFree().
+
+Deleted RTFStyleExpansion().
+
+-----------------------------
+rtf2null:
+
+rtf2null echoes unknown symbols so that it can be used as a quick way of
+finding symbols that the reader doesn't recognize.
+
+-----------------------------
+rtf2text:
+
+More characters in >= 128 range handled. Can switch between character
+sets, although only Macintosh character set is handled.
+
+-----------------------------
+rtf2troff:
+
+Some fprintf's in FlushParState() had no stream argument, causing core dumps.
+Fixed.
+
+Underlining works better now (doesn't destroy multiple-character characters
+like \(de, writes smaller output).
+
+Stikeout works.
+
+A bit of top/bottom margin support and header/footer support added.
+
+More characters in >= 128 range handled. Can switch between character
+sets, although only Macintosh character set is handled.
+
+However, the whole thing is more complicated and probably has many new
+bugs.
diff --git a/support/RTF-1_06a1/1.06-changes b/support/RTF-1_06a1/1.06-changes
new file mode 100644
index 0000000000..781a11da63
--- /dev/null
+++ b/support/RTF-1_06a1/1.06-changes
@@ -0,0 +1,67 @@
+Changes for distribution 1.06
+-----------------------------
+
+Up through distribution 1.05, development was based on example RTF files
+generated only with Word for Macintosh 4.0 and 4.0C. I've since had access
+to Word for Windows 1.1, which generates RTF differing somewhat from
+WfM RTF. Experience with these differences led to some changes which make
+the reader (and thus the translators) more robust. For instance, you should
+not get style expansion loop error messages.
+
+-----------------------------
+the RTF reader:
+
+There is a new routine RTFSetToken() for synthesizing fake tokens.
+RTFToken() was renamed to RTFGetToken() for symmetry.
+
+Added a couple of symbols (brdrbar/rtfBorderBar and brdrbtw/rtfBorderBetween).
+
+Changed the strings "picwGoal" and "pichGoal" to "picwgoal" and
+"pichgoal", because the RTF spec has little g's in those. THEN I
+saw a file in which pic[wh]Goal were really used. Sigh. So now
+the reader accepts both. Maybe it should just be made case insensitive
+on control words...
+
+rtfCellMoveX -> rtfCellPos
+
+Stylesheet reader modified to correctly handle missing \sbasedon and \snext
+in stylesheet entries. rtfBasedOnNone (=222) is available as the symbolic
+constant explicitly indicating "this style is based on no other".
+
+There are default readers for the \info and \pict groups now (they
+just skip the group).
+
+
+-----------------------------
+rtfwc:
+
+Understands how to deal with multiple file arguments.
+(rtfdiag should do so, too, but doesn't yet.)
+
+
+-----------------------------
+rtf2troff:
+
+Headers and footers seem to work even worse than they did before.
+
+Yikes. I had never put in stuff to catch paper width or height changes.
+Fixed.
+
+Added some table support. Output is generated that must be run through
+tbl.
+
+Output text lines are now broken to reasonable length if possible.
+This prevents paragraphs from coming out as one lonnnnnnnnnnnnng line
+of text and makes the output more readable/editable.
+
+Underlining is now enabled by default instead of disabled. The output is
+still voluminous, but at least now is editable since lines are broken.
+
+The +u/-u and +s/-s options turn on/off underlining/strikethrough.
+
+Added support for handling different versions of troff that have different
+special character conventions, and for generating special character sequences
+used by macro packages (-me, -mm, -ms). Unfortunately, this is the only
+part of the output that is specialized for particular macro packages so far.
+
+Correctly processes input containing "\" characters.
diff --git a/support/RTF-1_06a1/Imakefile b/support/RTF-1_06a1/Imakefile
new file mode 100644
index 0000000000..6093560a7a
--- /dev/null
+++ b/support/RTF-1_06a1/Imakefile
@@ -0,0 +1,105 @@
+# any special -D's or other flags for compiling
+DEFINES = ${VARARGS_DEFINES}
+
+# any special -I's for compiling
+INCLUDES =
+
+# any special libraries needed for linking
+LIBRARIES =
+
+# stuff common to all translators
+COMMONSRCS = reader.c
+COMMONOBJS = reader.o
+
+# RTF-to-nothing translator (the minimal translator)
+NULLSRCS = rtf2null.c
+NULLOBJS = rtf2null.o ${COMMONOBJS}
+
+# RTF-to-troff
+TROFFSRCS = rtf2troff.c trf-charmap.c trf-stack.c trf-flush.c \
+ trf-table.c trf-nwid.c
+TROFFOBJS = rtf2troff.o trf-charmap.o trf-stack.o trf-flush.o \
+ trf-table.o trf-nwid.o ${COMMONOBJS}
+
+# RTF-to-text translator
+TEXTSRCS = rtf2text.c
+TEXTOBJS = rtf2text.o ${COMMONOBJS}
+
+# RTF diagnostic "translator"
+DIAGSRCS = rtfdiag.c
+DIAGOBJS = rtfdiag.o ${COMMONOBJS}
+
+# RTF word count "translator"
+WCSRCS = rtfwc.c
+WCOBJS = rtfwc.o ${COMMONOBJS}
+
+# skeleton RTF translator
+SKELSRCS = rtfskel.c
+SKELOBJS = rtfskel.o ${COMMONOBJS}
+
+# RTF file indenter ("beautifier")
+INDSRCS = rtfindent.c
+INDOBJS = rtfindent.o
+
+SRCS = ${COMMONSRCS} ${NULLSRCS} ${TROFFSRCS} ${DIAGSRCS} \
+ ${TEXTSRCS} ${WCSRCS} ${SKELSRCS} ${INDSRCS}
+
+
+NormalProgramTarget (rtf2null, ${NULLOBJS}, /**/, ${LIBRARIES})
+InstallProgramTarget (rtf2null, ${BINDIR})
+
+NormalProgramTarget (rtf2troff, ${TROFFOBJS}, /**/, ${LIBRARIES})
+InstallProgramTarget (rtf2troff, ${BINDIR})
+
+NormalProgramTarget (rtf2text, ${TEXTOBJS}, /**/, ${LIBRARIES})
+InstallProgramTarget (rtf2text, ${BINDIR})
+
+NormalProgramTarget (rtfdiag, ${DIAGOBJS}, /**/, ${LIBRARIES})
+InstallProgramTarget (rtfdiag, ${BINDIR})
+
+NormalProgramTarget (rtfwc, ${WCOBJS}, /**/, ${LIBRARIES})
+InstallProgramTarget (rtfwc, ${BINDIR})
+
+# this isn't installed anywhere...
+NormalProgramTarget (rtfskel, ${SKELOBJS}, /**/, ${LIBRARIES})
+
+NormalProgramTarget (rtfindent, ${INDOBJS}, /**/, ${LIBRARIES})
+InstallProgramTarget (rtfindent, ${BINDIR})
+
+DependTarget()
+
+# document formatting rules
+
+# ifndef MsDoc
+#ifdef UseSoelim
+# define MsDoc(target) @@\
+SoelimDependency() @@\
+ @@\
+target-doc:: target.ms ${SOELIMDEP} @@\
+ ${SOELIM} target.ms | ${TROFF} ${MSMACROS} | ${PRINTER}
+# else /* !UseSoelim */
+# define MsDoc(target) @@\
+target-doc:: target.ms @@\
+ ${TROFF} ${MSMACROS} target.ms | ${PRINTER}
+# endif /* UseSoelim */
+# endif /* MsDoc */
+
+# ifndef TblMsDoc
+#ifdef UseSoelim
+# define TblMsDoc(target) @@\
+SoelimDependency() @@\
+ @@\
+target-doc:: target.ms ${SOELIMDEP} @@\
+ ${SOELIM} target.ms | ${TBL} | ${TROFF} ${MSMACROS} | ${PRINTER}
+# else /* !UseSoelim */
+# define TblMsDoc(target) @@\
+target-doc:: target.ms @@\
+ ${TBL} target.ms | ${TROFF} ${MSMACROS} | ${PRINTER}
+# endif /* UseSoelim */
+# endif /* TblMsDoc */
+
+MsDoc (rtf)
+
+MsDoc (rtf-misc)
+
+MsDoc (rtf2troff)
diff --git a/support/RTF-1_06a1/Makefile b/support/RTF-1_06a1/Makefile
new file mode 100644
index 0000000000..ea6d69fe3e
--- /dev/null
+++ b/support/RTF-1_06a1/Makefile
@@ -0,0 +1,425 @@
+# Makefile generated by imake - do not edit!
+# $XConsortium: imake.c,v 1.51 89/12/12 12:37:30 jim Exp $
+
+###########################################################################
+# Makefile generated from "Imake.tmpl" and </tmp/IIf.a27531>.
+#
+# Platform-specific parameters may be set in the appropriate .cf
+# configuration files. Site-wide parameters may be set in the file
+# site.def. Full rebuilds are recommended if any parameters are changed.
+#
+#
+# If your C preprocessor doesn't define any unique symbols, you'll need
+# to set BOOTSTRAPCFLAGS when rebuilding imake (usually when doing
+# "make Makefile", "make Makefiles", or "make World").
+#
+# If you absolutely can't get imake to work, you'll need to set the
+# variables at the top of each Makefile as well as the dependencies at the
+# bottom (makedepend will do this automatically).
+#
+
+###########################################################################
+# platform-specific project configuration parameters
+# edit ultrix.pcf to change
+
+###########################################################################
+# platform-specific configuration parameters - edit ultrix.cf to change
+
+# platform: ultrix.cf 90/01/11
+# operating system: Ultrix-32 3.1
+
+###########################################################################
+# site-specific project configuration parameters - edit site.pdef to change
+
+###########################################################################
+# site-specific configuration parameters - edit site.def to change
+
+# site: Primate Center 89/12/22
+
+# System characteristics. Should be overridden as necessary in
+# platform-specific .cf file.
+
+###########################################################################
+# definitions common to all Makefiles - do not edit
+
+ SHELL = /bin/sh
+
+ DESTDIR =
+ TOP = .
+ CURRENT_DIR = .
+
+ VARARGS_DEFINES = -DVARARGS
+
+ AR = ar clq
+ BOOTSTRAPCFLAGS =
+ CC = cc
+ CPP = /lib/cpp $(STD_CPP_DEFINES)
+ PREPROCESSCMD = cc -E $(STD_CPP_DEFINES)
+ INSTALL = install
+ LD = ld
+ LINT = lint
+ LINTLIBFLAG = -C
+ LINTOPTS = -axz
+ LN = ln -s
+ MAKE = make
+ MV = mv
+ CP = cp
+ RANLIB = ranlib
+ RANLIBINSTFLAGS = -t
+ RM = rm -f
+ STD_INCLUDES =
+ STD_CPP_DEFINES =
+ STD_DEFINES =
+ EXTRA_LOAD_FLAGS =
+ EXTRA_LIBRARIES =
+ TAGS = ctags
+
+ INSTBINFLAGS = -m 0755 -o bin -g system
+ INSTUIDFLAGS = -m 04755 -o bin -g system
+ INSTGIDFLAGS = -m 02755 -o bin -g system
+ INSTUGIDFLAGS = -m 06755 -o bin -g system
+ INSTLIBFLAGS = -m 0664 -o bin -g system
+ INSTSCRIPTFLAGS = -m 0755 -o bin -g system
+ INSTINCFLAGS = -m 0444 -o bin -g system
+ INSTDATFLAGS = -m 0444 -o bin -g system
+ INSTMANFLAGS = -m 0444 -o bin -g system
+
+ INCLUDEPATH = $(DESTDIR)/usr/include
+
+ EXTRA_INCLUDES = ${PROJECT_INCLUDES}
+ ALLINCLUDES = $(EXTRA_INCLUDES) $(INCLUDES) $(STD_INCLUDES)
+ ALLDEFINES = $(ALLINCLUDES) $(STD_DEFINES) $(DEFINES)
+ CFLAGS = $(CDEBUGFLAGS) $(CCOPTIONS) $(ALLDEFINES)
+ LINTFLAGS = $(LINTOPTS) -DLINT $(ALLDEFINES)
+ LDLIBS = $(SYS_LIBRARIES) $(EXTRA_LIBRARIES)
+ LDOPTIONS = $(CDEBUGFLAGS) $(CCOPTIONS)
+
+ MANPATH = $(DESTDIR)/usr/man
+ MANSOURCEPATH = $(MANPATH)/man
+ MANDIR = $(MANSOURCEPATH)l
+ LIBMANDIR = LibmanDir
+ SYSMANDIR = SysmanDir
+
+ EQN = xeqn
+ MANMACROS = -man.new
+ MSMACROS = -ms
+ PIC = pic
+ PRINTER = lwa
+ SOELIM = soelim
+ TBL = tbl
+ TROFF = pstroff
+ NROFF = nroff
+
+ CDEBUGFLAGS = -O
+ CCOPTIONS =
+
+ RM_CMD = $(RM) *.CKP *.ln *.BAK *.bak *.o core errs ,* *.a .emacs_* tags TAGS make.log MakeOut
+
+###########################################################################
+# project-specific configuration parameters
+# Edit Project.ptmpl to change
+
+###########################################################################
+# project-specific project configuration parameters
+
+###########################################################################
+# Section 1. Cpp symbols
+
+# Project identfication - name and release level
+
+# Project-specific system characteristics
+
+# Project-specific system directories and file locations
+
+# Project-specific include file directories
+
+# Configuration tools (files and directories)
+
+# Extra commands required
+
+# Extra libraries required
+
+###########################################################################
+# Section 2. Makefile symbols; needs to be coordinated with Imake.tmpl
+
+# Project identfication - name and release level
+
+# Project-specific system characteristics
+
+# Project-specific system directories and file locations
+
+# Project-specific include file directories
+
+# Configuration tools (files and directories)
+
+# Extra commands required
+
+# Extra libraries required
+
+###########################################################################
+# Standard Project configuration parameters
+# Edit Project.tmpl to change
+
+###########################################################################
+# Standard project configuration parameters
+
+###########################################################################
+# Section 1. Cpp symbols
+
+# Project identfication - name and release level
+
+# Project-specific system directories and file locations
+
+# Project-specific include file directories
+
+# Configuration tools (files and directories)
+
+###########################################################################
+# Section 2. Makefile symbols; needs to be coordinated with Imake.tmpl
+
+# Project identfication - name and release level
+
+ PROJECTNAME = "(no project name)"
+ PROJECTRELEASE = "0.0"
+
+# Project-specific system directories and file locations
+
+ PATHSEP = /
+
+ BINDIR = $(DESTDIR)/usr/local
+ USRLIBDIR = $(DESTDIR)/usr/lib
+
+ TMPDIR = ${DESTDIR}/usr/tmp
+
+# Project-specific include file directories
+
+ INCLUDESRC = .
+
+ PROJECT_INCLUDES = -I${INCLUDESRC}
+
+# Configuration tools (files and directories)
+
+ STDCONFIGPATH = ${USRLIBDIR}/config
+ STDCONFIGDIR = ${STDCONFIGPATH}/WRPRC
+ PROJCONFIGDIR = ${TOP}/config
+
+ CONFIGSRC = $(TOP)/config
+ IMAKESRC = $(CONFIGSRC)
+
+ UTILSRC = $(TOP)/util
+ SCRIPTSRC = $(UTILSRC)/scripts
+ DEPENDSRC = $(UTILSRC)/makedepend
+ MSUBSRC = $(UTILSRC)/msub
+ SOELIMSRC = $(UTILSRC)/soelim
+
+ IMAKE = imake
+ DEPEND = makedepend
+ MSUB = msub
+ MKDIRHIER = /bin/sh $(SCRIPTSRC)/mkdirhier.sh
+
+ IMAKE_DEFINES =
+ IRULESRC = $(CONFIGSRC)
+ MACROFILE = ultrix.cf
+
+ IMAKE_CMD = $(IMAKE) -DUseInstalled -I$(NEWTOP)$(PROJCONFIGDIR) -I$(STDCONFIGDIR) $(IMAKE_DEFINES)
+
+ ICONFIGFILES = $(IRULESRC)/Imake.tmpl \
+ $(IRULESRC)/Imake.rules \
+ $(IRULESRC)/Project.tmpl \
+ $(IRULESRC)/$(MACROFILE) \
+ $(IRULESRC)/site.def \
+ Imakefile \
+ $(EXTRA_CONFIGFILES)
+
+###########################################################################
+# Project-specific imake rules
+# Edit Imake.prules to change
+
+###########################################################################
+# Standard imake rules
+# Edit Imake.rules to change
+
+###########################################################################
+# Imake rules.
+# Hacked from X Window System R3 and R4 imake rules.
+
+###########################################################################
+# start of Imakefile
+
+# any special -D's or other flags for compiling
+DEFINES = ${VARARGS_DEFINES}
+
+# any special -I's for compiling
+INCLUDES =
+
+# any special libraries needed for linking
+LIBRARIES =
+
+# stuff common to all translators
+COMMONSRCS = reader.c
+COMMONOBJS = reader.o
+
+# RTF-to-nothing translator (the minimal translator)
+NULLSRCS = rtf2null.c
+NULLOBJS = rtf2null.o ${COMMONOBJS}
+
+# RTF-to-troff
+TROFFSRCS = rtf2troff.c trf-charmap.c trf-stack.c trf-flush.c \
+ trf-table.c trf-nwid.c
+TROFFOBJS = rtf2troff.o trf-charmap.o trf-stack.o trf-flush.o \
+ trf-table.o trf-nwid.o ${COMMONOBJS}
+
+# RTF-to-text translator
+TEXTSRCS = rtf2text.c
+TEXTOBJS = rtf2text.o ${COMMONOBJS}
+
+# RTF diagnostic "translator"
+DIAGSRCS = rtfdiag.c
+DIAGOBJS = rtfdiag.o ${COMMONOBJS}
+
+# RTF word count "translator"
+WCSRCS = rtfwc.c
+WCOBJS = rtfwc.o ${COMMONOBJS}
+
+# skeleton RTF translator
+SKELSRCS = rtfskel.c
+SKELOBJS = rtfskel.o ${COMMONOBJS}
+
+# RTF file indenter ("beautifier")
+INDSRCS = rtfindent.c
+INDOBJS = rtfindent.o
+
+SRCS = ${COMMONSRCS} ${NULLSRCS} ${TROFFSRCS} ${DIAGSRCS} \
+ ${TEXTSRCS} ${WCSRCS} ${SKELSRCS} ${INDSRCS}
+
+all:: rtf2null
+
+clean::
+ $(RM) rtf2null
+rtf2null:: ${NULLOBJS}
+ $(RM) $@
+ $(CC) -o $@ ${NULLOBJS} $(LDOPTIONS) ${LIBRARIES} $(LDLIBS)
+
+install:: irtf2null
+irtf2null:: rtf2null
+ $(INSTALL) -c ${INSTBINFLAGS} rtf2null ${BINDIR}/rtf2null
+
+all:: rtf2troff
+
+clean::
+ $(RM) rtf2troff
+rtf2troff:: ${TROFFOBJS}
+ $(RM) $@
+ $(CC) -o $@ ${TROFFOBJS} $(LDOPTIONS) ${LIBRARIES} $(LDLIBS)
+
+install:: irtf2troff
+irtf2troff:: rtf2troff
+ $(INSTALL) -c ${INSTBINFLAGS} rtf2troff ${BINDIR}/rtf2troff
+
+all:: rtf2text
+
+clean::
+ $(RM) rtf2text
+rtf2text:: ${TEXTOBJS}
+ $(RM) $@
+ $(CC) -o $@ ${TEXTOBJS} $(LDOPTIONS) ${LIBRARIES} $(LDLIBS)
+
+install:: irtf2text
+irtf2text:: rtf2text
+ $(INSTALL) -c ${INSTBINFLAGS} rtf2text ${BINDIR}/rtf2text
+
+all:: rtfdiag
+
+clean::
+ $(RM) rtfdiag
+rtfdiag:: ${DIAGOBJS}
+ $(RM) $@
+ $(CC) -o $@ ${DIAGOBJS} $(LDOPTIONS) ${LIBRARIES} $(LDLIBS)
+
+install:: irtfdiag
+irtfdiag:: rtfdiag
+ $(INSTALL) -c ${INSTBINFLAGS} rtfdiag ${BINDIR}/rtfdiag
+
+all:: rtfwc
+
+clean::
+ $(RM) rtfwc
+rtfwc:: ${WCOBJS}
+ $(RM) $@
+ $(CC) -o $@ ${WCOBJS} $(LDOPTIONS) ${LIBRARIES} $(LDLIBS)
+
+install:: irtfwc
+irtfwc:: rtfwc
+ $(INSTALL) -c ${INSTBINFLAGS} rtfwc ${BINDIR}/rtfwc
+
+# this isn't installed anywhere...
+
+all:: rtfskel
+
+clean::
+ $(RM) rtfskel
+rtfskel:: ${SKELOBJS}
+ $(RM) $@
+ $(CC) -o $@ ${SKELOBJS} $(LDOPTIONS) ${LIBRARIES} $(LDLIBS)
+
+all:: rtfindent
+
+clean::
+ $(RM) rtfindent
+rtfindent:: ${INDOBJS}
+ $(RM) $@
+ $(CC) -o $@ ${INDOBJS} $(LDOPTIONS) ${LIBRARIES} $(LDLIBS)
+
+install:: irtfindent
+irtfindent:: rtfindent
+ $(INSTALL) -c ${INSTBINFLAGS} rtfindent ${BINDIR}/rtfindent
+
+depend::
+ $(DEPEND) -s "# DO NOT DELETE" -- $(ALLDEFINES) -- $(SRCS)
+
+# document formatting rules
+
+rtf-doc:: rtf.ms ${SOELIMDEP}
+ ${SOELIM} rtf.ms | ${TROFF} ${MSMACROS} | ${PRINTER}
+
+rtf-misc-doc:: rtf-misc.ms ${SOELIMDEP}
+ ${SOELIM} rtf-misc.ms | ${TROFF} ${MSMACROS} | ${PRINTER}
+
+rtf2troff-doc:: rtf2troff.ms ${SOELIMDEP}
+ ${SOELIM} rtf2troff.ms | ${TROFF} ${MSMACROS} | ${PRINTER}
+
+###########################################################################
+# common rules for all Makefiles - do not edit
+
+emptyrule::
+
+clean::
+ $(RM_CMD) \#*
+
+Makefile::
+ -@if [ -f Makefile ]; then \
+ echo " $(RM) Makefile.bak; $(MV) Makefile Makefile.bak"; \
+ $(RM) Makefile.bak; $(MV) Makefile Makefile.bak; \
+ else exit 0; fi
+ $(IMAKE_CMD) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT_DIR)
+
+tags::
+ $(TAGS) -w *.[ch]
+ $(TAGS) -xw *.[ch] > TAGS
+
+###########################################################################
+# empty rules for directories that do not have SUBDIRS - do not edit
+
+install::
+ @echo "install in $(CURRENT_DIR) done"
+
+install.man::
+ @echo "install.man in $(CURRENT_DIR) done"
+
+Makefiles::
+
+depend::
+
+###########################################################################
+# dependencies generated by makedepend
+
diff --git a/support/RTF-1_06a1/Notes b/support/RTF-1_06a1/Notes
new file mode 100644
index 0000000000..266a7f74ff
--- /dev/null
+++ b/support/RTF-1_06a1/Notes
@@ -0,0 +1,43 @@
+Need a mapping for symbol font if writer writing output format without
+symbol font capability. E.g., for troff, alpha -> \(*a.
+
+On error in destination readers - could read until closing "}" instead
+of panicing. (Assuming that no state push is done inside dest readers.)
+The program could continue this way.
+
+rtf version 0 files may have font tables in which the font entries don't
+have braces around them.
+
+The reader enforces very few syntactic constraints. For example, it
+does not enforce:
+\ertf\fIn\fR must follow first open brace.
+Charset control symbol must follow \ertf\fIn\fR.
+Default found (\edeff\fIn\fR), if given, must precede font table.
+Font table, stylesheet, color table, summary information group, document
+formatting properties must precede all document content text.
+Font table should precede stylesheet.
+
+The troff writer does not ignore groups which specify foreground or
+background colors.
+The RTF specification says "if the file is translated by software that
+does not display color," the group should be ignored.
+Aside from the fact that very little software displays color, it seems
+unnecessary to throw out color text instead of simply writing it out
+normally.
+
+Border symbols are found in the specification both under picture and
+paragraph descriptions. The reader treats them as paragraph attributes.
+
+Some footnote control symbols (\eftnsep, \eftnsepc, \eftncn) are listed
+in the specification as document formatting attributes. Since they begin
+a group, the reader treats them as destinations.
+
+\epgnstart and \elinestart are listed under section and documnent formatting
+properties. The reader treats them as document properties.
+
+The less complete specification has the wrong names for the section break
+symbols.
+
+Foreground and background color symbols \ecf and \ebf are listed under the
+color table description. The reader treats them as character formatting
+properties.
diff --git a/support/RTF-1_06a1/Porting b/support/RTF-1_06a1/Porting
new file mode 100644
index 0000000000..50784f4230
--- /dev/null
+++ b/support/RTF-1_06a1/Porting
@@ -0,0 +1,30 @@
+rtf2troff:
+
+You need bcopy. If you don't have one, you can write it easily. The
+prototype is:
+
+ bcopy (char *src, char *dest, int nBytes);
+
+copy nButes from source "src" to destination "dest". Some implementations
+work for overlapping source and destination, but that is not necessary
+for rtf2troff. If you don't have bcopy, but you do have memcpy, bcopy
+can be implemented as
+
+ # define bcopy(a,b,c) (void) memcpy(b,a,c)
+
+On a Macintosh you can use
+
+ # define bcopy(a,b,c) BlockMove(a,b,c)
+
+-------------------
+Some functions take a variable number of arguments; varargs.h is used
+if you have it. This is all controlled by VARARGS in the Makefile.
+If you use imake, the correct value should be selected automatically,
+otherwise you'll have to set it by hand.
+
+-------------------
+The table used to translate non-ASCII (> 127) characters are incomplete,
+and it is possible that the special sequences used to represent
+special characters are not present in all troff's. Check against your
+local documentation. Take a look at trf-charmap.c.
+-------------------
diff --git a/support/RTF-1_06a1/README b/support/RTF-1_06a1/README
new file mode 100644
index 0000000000..6917c8bcbd
--- /dev/null
+++ b/support/RTF-1_06a1/README
@@ -0,0 +1,67 @@
+RTF-stuff 1.06a1
+05 Apr 91 Paul DuBois dubois@primate.wisc.edu
+
+This directory contains source and documentation [sic] for a simple
+RTF (Rich Text Format) translation tool. Files in this format can be
+produced with, e.g., Microsoft Word, or on NeXT machines.
+
+If you use the Imakefile, you must obtain the WRPRC imake distribution.
+If you want to skip that and just use the Makefile you will have to edit
+some of the make variable definitions. Use "make -n" and "make -n install"
+to see what will happen on your machine first!
+
+Documentation that is in troff format should be formatted with the -ms
+macros.
+
+The WRPRC imake distribution is available via anonymous ftp to host
+indri.primate.wisc.edu (Internet address 128.104.230.11) in ~ftp/pub.
+
+The translators currently available are listed below. Most of them
+don't do anything interesting.
+
+rtf2null RTF -> nothing
+rtf2text RTF -> plain text
+rtf2troff RTF -> troff
+rtfwc "translates" RTF into character, word and paragraph count
+rtfdiag RTF diagnostic program, used mainly to test RTF reader
+rtfskel RTF translator skeleton, for use in building new translators
+
+Each translator uses a tool which reads an RTF input stream and passes
+pieces of it to a writer.
+
+There is also a tool, rtfindent, which reads an RTF file and writes it in
+somewhat more readable form. This is helpful when designing a translator,
+to see what RTF files look like, but the output should not be fed into
+a translator.
+
+Distribution files of interest:
+
+rtf.h RTF header file; include in any source file using
+ RTF-specific info.
+reader.c RTF reader. Must be part of any RTF translator. See the
+ sample translators for examples of use.
+rtfskel.c Skeleton translator. You can rip this apart to use as the
+ basis for new translators.
+Porting Some notes on machine dependencies.
+
+Version History:
+
+20 Jan 91 V1.00. Project conceived.
+
+07 Feb 91 V1.01. First release for FTP on indri.
+
+08 Feb 91 V1.02. Added rtfskel.
+
+08 Feb 91 V1.03. Style reprocessing and built-in destination readers were
+ actually tried in the balance. And found wanting. Fixed 'em.
+ Put some actually useful stuff in rtfdiag.
+
+09 Feb 91 V1.04. Renamed rtfAscii class to rtfText. Original name was poor
+ since character values can be outside ascii range (> 127).
+
+04 Mar 91 V1.05. Lots of changes, most notably that twice as many control
+ symbols are recognized by the reader. Also some bug fixes. See
+ "1.05-changes".
+
+05 Apr 91 V1.06a1. Alpha release of 1.06. See "1.06-changes". Major
+ thing is tbl support for rtf2troff.
diff --git a/support/RTF-1_06a1/nwidth.trf b/support/RTF-1_06a1/nwidth.trf
new file mode 100644
index 0000000000..3e9da95da9
--- /dev/null
+++ b/support/RTF-1_06a1/nwidth.trf
@@ -0,0 +1,40 @@
+.\" determine n-widths at different point sizes
+.\" run this through your troff and examine the output
+.de nw
+.ps \\$1
+.nr n \\w'n'u
+.ps
+Point size: \\$1\tn-width: \\nn
+.br
+..
+.nw 3
+.nw 4
+.nw 5
+.nw 6
+.nw 7
+.nw 8
+.nw 9
+.nw 10
+.nw 11
+.nw 12
+.nw 13
+.nw 14
+.nw 15
+.nw 16
+.nw 17
+.nw 18
+.nw 19
+.nw 20
+.nw 22
+.nw 24
+.nw 26
+.nw 28
+.nw 30
+.nw 32
+.nw 34
+.nw 36
+.nw 38
+.nw 40
+.nw 44
+.nw 48
+.nw 72
diff --git a/support/RTF-1_06a1/reader.c b/support/RTF-1_06a1/reader.c
new file mode 100644
index 0000000000..c3ed341bf5
--- /dev/null
+++ b/support/RTF-1_06a1/reader.c
@@ -0,0 +1,1380 @@
+/*
+ reader.c - RTF file reader. Distribution 1.06.
+
+ ASCII 10 (\n) and 13 (\r) are ignored and silently discarded.
+ (The read hook will still get a look at them.)
+
+ "\:" is not a ":", it's a control symbol. But some versions of
+ Word seem to write "\:" for ":". This reader treats "\:" as a
+ plain text ":"
+
+ This reader needs to catch \cf and \cb in the color table
+ reader? (Doesn't yet.)
+*/
+
+# include <stdio.h>
+# include <ctype.h>
+# include "rtf.h"
+
+
+/*
+ Return pointer to new element of type t, or NULL
+*/
+
+# define New(t) ((t *) RTFAlloc (sizeof (t)))
+
+
+extern char *index ();
+extern char *malloc ();
+extern char *strcpy ();
+
+
+/*
+ Public variables (listed in rtf.h)
+*/
+
+char rtfTextBuf[rtfBufSiz];
+int rtfTextLen;
+int rtfClass;
+int rtfMajor;
+int rtfMinor;
+int rtfParam;
+
+
+/*
+ Private stuff
+*/
+
+
+static RTFFont *fontList = NULL; /* these lists MUST be */
+static RTFColor *colorList = NULL; /* initialized to NULL */
+static RTFStyle *styleList = NULL;
+
+
+static FILE *rtffp = stdin;
+
+static int pushback = EOF;
+
+
+static void _RTFGetToken ();
+static int GetChar ();
+static int HexVal ();
+static void ReadFontTbl ();
+static void ReadColorTbl ();
+static void ReadStyleSheet ();
+static void ReadInfoGroup ();
+static void ReadPictGroup ();
+static void LookupInit ();
+static void Lookup ();
+static int Hash ();
+
+
+/*
+ Initialize the reader. This may be called multiple times.
+ The only thing not reset is the input stream.
+*/
+
+void RTFInit ()
+{
+int i;
+RTFColor *cp;
+RTFFont *fp;
+RTFStyle *sp;
+RTFStyleElt *eltList, *ep;
+
+ /* initialize lookup table */
+ LookupInit ();
+
+ for (i = 0; i < rtfMaxClass; i++)
+ RTFSetClassCallback (i, NULL);
+ for (i = 0; i < rtfMaxDestination; i++)
+ RTFSetDestinationCallback (i, NULL);
+
+ /* install built-in destination readers */
+ RTFSetDestinationCallback (rtfFontTbl, ReadFontTbl);
+ RTFSetDestinationCallback (rtfColorTbl, ReadColorTbl);
+ RTFSetDestinationCallback (rtfStyleSheet, ReadStyleSheet);
+ RTFSetDestinationCallback (rtfInfo, ReadInfoGroup);
+ RTFSetDestinationCallback (rtfPict, ReadPictGroup);
+
+ RTFSetReadHook (NULL);
+
+ /* dump old lists if necessary */
+
+ while (fontList != NULL)
+ {
+ fp = fontList->rtfNextFont;
+ RTFFree (fontList->rtfFName);
+ RTFFree ((char *) fontList);
+ fontList = fp;
+ }
+ while (colorList != NULL)
+ {
+ cp = colorList->rtfNextColor;
+ RTFFree ((char *) colorList);
+ colorList = cp;
+ }
+ while (styleList != NULL)
+ {
+ sp = styleList->rtfNextStyle;
+ eltList = styleList->rtfSSEList;
+ while (eltList != NULL)
+ {
+ ep = eltList->rtfNextSE;
+ RTFFree (eltList->rtfSEText);
+ RTFFree ((char *) eltList);
+ eltList = ep;
+ }
+ RTFFree (styleList->rtfSName);
+ RTFFree ((char *) styleList);
+ styleList = sp;
+ }
+
+ pushback = EOF;
+}
+
+
+/*
+ Set the reader's input stream to the given stream. Can
+ be used to redirect other than to the default (stdin).
+*/
+
+void RTFSetStream (stream)
+FILE *stream;
+{
+ rtffp = stream;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ Callback table manipulation routines
+*/
+
+
+/*
+ Install or return a writer callback for a token class
+*/
+
+static void (*ccb[rtfMaxClass]) (); /* class callbacks */
+
+void RTFSetClassCallback (class, callback)
+int class;
+void (*callback) ();
+{
+ if (class >= 0 && class < rtfMaxClass)
+ ccb[class] = callback;
+}
+
+
+void (*RTFGetClassCallback (class)) ()
+int class;
+{
+ if (class >= 0 && class < rtfMaxClass)
+ return (ccb[class]);
+ return (NULL);
+}
+
+
+/*
+ Install or return a writer callback for a destination type
+*/
+
+static void (*dcb[rtfMaxDestination]) (); /* destination callbacks */
+
+void RTFSetDestinationCallback (dest, callback)
+int dest;
+void (*callback) ();
+{
+ if (dest >= 0 && dest < rtfMaxDestination)
+ dcb[dest] = callback;
+}
+
+
+void (*RTFGetDestinationCallback (dest)) ()
+int dest;
+{
+ if (dest >= 0 && dest < rtfMaxDestination)
+ return (dcb[dest]);
+ return (NULL);
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ Token reading routines
+*/
+
+
+/*
+ Read the input stream, invoking the writer's callbacks
+ where appropriate.
+*/
+
+void RTFRead ()
+{
+ while (RTFGetToken () != rtfEOF)
+ RTFRouteToken ();
+}
+
+
+/*
+ Route a token. If it's a destination for which a reader is
+ installed, process the destination internally, otherwise
+ pass the token to the writer's class callback.
+*/
+
+void RTFRouteToken ()
+{
+void (*p) ();
+
+ if (rtfClass < 0 || rtfClass >= rtfMaxClass) /* watchdog */
+ {
+ fprintf (stderr, "Unknown class %d: %s", rtfClass, rtfTextBuf);
+ fprintf (stderr, " (reader malfunction)\n");
+ return;
+ }
+ if (RTFCheckCM (rtfControl, rtfDestination))
+ {
+ /* invoke destination-specific callback if there is one */
+ if ((p = RTFGetDestinationCallback (rtfMinor)) != NULL)
+ {
+ (*p) ();
+ return;
+ }
+ }
+ /* invoke class callback if there is one */
+ if ((p = RTFGetClassCallback (rtfClass)) != NULL)
+ (*p) ();
+}
+
+
+/*
+ Skip to the end of the current group. When this returns,
+ writers that maintain a state stack may want to call their
+ state unstacker; global vars will still be set to the group's
+ closing brace.
+*/
+
+void RTFSkipGroup ()
+{
+int level = 1;
+
+ while (RTFGetToken () != rtfEOF)
+ {
+ if (rtfClass == rtfGroup)
+ {
+ if (rtfMajor == rtfBeginGroup)
+ ++level;
+ else if (rtfMajor == rtfEndGroup)
+ {
+ if (--level < 1)
+ break; /* end of initial group */
+ }
+ }
+ }
+}
+
+
+/*
+ Read one token. Call the read hook if there is one. The
+ token class is the return value. Returns rtfEOF when there
+ are no more tokens.
+*/
+
+int RTFGetToken ()
+{
+void (*p) ();
+
+ for (;;)
+ {
+ _RTFGetToken ();
+ if ((p = RTFGetReadHook ()) != NULL)
+ (*p) (); /* give read hook a look at token */
+
+ /* Silently discard newlines and carriage returns. */
+ if (!(rtfClass == rtfText
+ && (rtfMajor == '\n' || rtfMajor == '\r')))
+ break;
+ }
+ return (rtfClass);
+}
+
+
+/*
+ Install or return a token reader hook.
+*/
+
+static void (*readHook) ();
+
+void RTFSetReadHook (f)
+void (*f) ();
+{
+ readHook = f;
+}
+
+
+void (*RTFGetReadHook ()) ()
+{
+ return (readHook);
+}
+
+
+static void _RTFGetToken ()
+{
+int sign;
+int c;
+
+ /* initialize token vars */
+
+ rtfClass = rtfUnknown;
+ rtfParam = 0;
+ rtfTextBuf[rtfTextLen = 0] = '\0';
+
+ /* get first character, which may be a pushback from previous token */
+
+ if (pushback != EOF)
+ {
+ c = pushback;
+ rtfTextBuf[rtfTextLen] = c;
+ rtfTextBuf[++rtfTextLen] = '\0';
+ pushback = EOF;
+ }
+ else if ((c = GetChar ()) == EOF)
+ {
+ rtfClass = rtfEOF;
+ return;
+ }
+
+ if (c == '{')
+ {
+ rtfClass = rtfGroup;
+ rtfMajor = rtfBeginGroup;
+ return;
+ }
+ if (c == '}')
+ {
+ rtfClass = rtfGroup;
+ rtfMajor = rtfEndGroup;
+ return;
+ }
+ if (c != '\\')
+ {
+ /*
+ Two possibilities here:
+ 1) ASCII 9, effectively like \tab control symbol
+ 2) literal text char
+ */
+ if (c == '\t') /* ASCII 9 */
+ {
+ rtfClass = rtfControl;
+ rtfMajor = rtfTab;
+ }
+ else
+ {
+ rtfClass = rtfText;
+ rtfMajor = c;
+ }
+ return;
+ }
+ if ((c = GetChar ()) == EOF)
+ {
+ /* early eof, whoops (class is rtfUnknown) */
+ return;
+ }
+ if (!isalpha (c))
+ {
+ /*
+ Three possibilities here:
+ 1) hex encoded text char, e.g., \'d5, \'d3
+ 2) special escaped text char, e.g., \{, \}
+ 3) control symbol, e.g., \_, \-, \|, \<10>
+ */
+ if (c == '\'') /* hex char */
+ {
+ int c2;
+
+ if ((c = GetChar ()) != EOF && (c2 = GetChar ()) != EOF)
+ {
+ /* should do isxdigit check! */
+ rtfClass = rtfText;
+ rtfMajor = HexVal (c) * 16 + HexVal (c2);
+ return;
+ }
+ /* early eof, whoops (class is rtfUnknown) */
+ return;
+ }
+
+ if (index (":{}\\", c) != NULL) /* escaped char */
+ {
+ rtfClass = rtfText;
+ rtfMajor = c;
+ return;
+ }
+
+ /* control symbol */
+ Lookup (rtfTextBuf); /* sets class, major, minor */
+ return;
+ }
+ /* control word */
+ while (isalpha (c))
+ {
+ if ((c = GetChar ()) == EOF)
+ break;
+ }
+
+ /*
+ At this point, the control word is all collected, so the
+ major/minor numbers are determined before the parameter
+ (if any) is scanned. There will be one too many characters
+ in the buffer, though, so fix up before and restore after
+ looking up.
+ */
+
+ if (c != EOF)
+ rtfTextBuf[rtfTextLen-1] = '\0';
+ Lookup (rtfTextBuf); /* sets class, major, minor */
+ if (c != EOF)
+ rtfTextBuf[rtfTextLen-1] = c;
+
+ /*
+ Should be looking at first digit of parameter if there
+ is one, unless it's negative. In that case, next char
+ is '-', so need to gobble next char, and remember sign.
+ */
+
+ sign = 1;
+ if (c == '-')
+ {
+ sign = -1;
+ c = GetChar ();
+ }
+ if (c != EOF)
+ {
+ while (isdigit (c)) /* gobble parameter */
+ {
+ rtfParam = rtfParam * 10 + c - '0';
+ if ((c = GetChar ()) == EOF)
+ break;
+ }
+ rtfParam *= sign;
+ }
+ /*
+ If control symbol delimiter was a blank, gobble it.
+ Otherwise the character is first char of next token, so
+ push it back for next call. In either case, delete the
+ delimiter from the token buffer.
+ */
+ if (c != EOF)
+ {
+ if (c != ' ')
+ pushback = c;
+ rtfTextBuf[--rtfTextLen] = '\0';
+ }
+ return;
+}
+
+
+/*
+ Distributions up through 1.04 assumed high bit could be set in
+ RTF file characters. Beginning with 1.05, that's not true, but
+ still check and die if such a character is found.
+*/
+
+static int GetChar ()
+{
+int c;
+
+ if ((c = getc (rtffp)) != EOF)
+ {
+ if (c & 0x80)
+ {
+ fprintf (stderr, "Char with high bit set (%#x) found\n", c);
+ exit (1);
+ }
+ rtfTextBuf[rtfTextLen] = c;
+ rtfTextBuf[++rtfTextLen] = '\0';
+ }
+ return (c);
+}
+
+
+static int HexVal (c)
+char c;
+{
+ if (isupper (c))
+ c = tolower (c);
+ if (isdigit (c))
+ return (c - '0'); /* '0'..'9' */
+ return (c - 'a' + 10); /* 'a'..'f' */
+}
+
+
+/*
+ Synthesize a token by setting the global variables to the
+ values supplied. Typically this is followed with a call
+ to RTFRouteToken().
+
+ If param is non-negative, it becomes part of the token text.
+*/
+
+void RTFSetToken (class, major, minor, param, text)
+int class, major, minor, param;
+char *text;
+{
+ rtfClass = class;
+ rtfMajor = major;
+ rtfMinor = minor;
+ rtfParam = param;
+ if (param >= 0)
+ sprintf (rtfTextBuf, "%s%d", text, param);
+ else
+ strcpy (rtfTextBuf, text);
+ rtfTextLen = strlen (rtfTextBuf);
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ Special destination readers. They gobble the destination so the
+ writer doesn't have to deal with them. That's wrong for any
+ translator that wants to process any of these itself. In that
+ case, these readers should be overridden by installing a different
+ destination callback.
+
+ The last token read by each of these reader will be the destination's
+ terminating '}', which will then be the current token. That token
+ is passed to RTFRouteToken() - the writer had already seen the '{'
+ that began the destination grou, and may have pushed a state; it also
+ needs to know at the end of the group that a state should be popped.
+
+ It's important that rtf.h and the control token lookup table list
+ as many symbols as possible, because these readers unfortunately
+ make strict assumptions about the input they expect, and a token
+ of class rtfUnknown will throw them off easily.
+*/
+
+
+/*
+ Read { \fonttbl ... } destination. Old font tables don't have
+ braces around each table entry; try to adjust for that.
+*/
+
+static void ReadFontTbl ()
+{
+RTFFont *fp;
+char buf[rtfBufSiz], *bp;
+int old = -1;
+
+ for (;;)
+ {
+ (void) RTFGetToken ();
+ if (RTFCheckCM (rtfGroup, rtfEndGroup))
+ break;
+ if (old < 0) /* first entry - determine tbl type */
+ {
+ if (RTFCheckCMM (rtfControl, rtfCharAttr, rtfFontNum))
+ old = 1; /* no brace */
+ else if (RTFCheckCM (rtfGroup, rtfBeginGroup))
+ old = 0; /* brace */
+ else
+ { /* can't tell! */
+ fprintf (stderr, "Bad font table-1\n");
+ exit (1);
+ }
+ }
+ if (old == 0) /* need to find "{" here */
+ {
+ if (!RTFCheckCM (rtfGroup, rtfBeginGroup))
+ {
+ fprintf (stderr, "Bad font table-2\n");
+ exit (1);
+ }
+ (void) RTFGetToken (); /* yes, skip to next token */
+ }
+ if ((fp = New (RTFFont)) == NULL)
+ {
+ fprintf (stderr, "Can't allocate font entry\n");
+ exit (1);
+ }
+ fp->rtfNextFont = fontList;
+ fontList = fp;
+ if (!RTFCheckCMM (rtfControl, rtfCharAttr, rtfFontNum))
+ {
+ fprintf (stderr, "Bad font table-3\n");
+ exit (1);
+ }
+ fp->rtfFNum = rtfParam;
+ (void) RTFGetToken ();
+ if (!RTFCheckCM (rtfControl, rtfFontFamily))
+ {
+ fprintf (stderr, "Bad font table-4\n");
+ exit (1);
+ }
+ fp->rtfFFamily = rtfMinor;
+ bp = buf;
+ while (RTFGetToken () == rtfText)
+ {
+ if (rtfMajor == ';')
+ break;
+ *bp++ = rtfMajor;
+ }
+ *bp = '\0';
+ if ((fp->rtfFName = RTFStrSave (buf)) == NULL)
+ {
+ fprintf (stderr, "Can't allocate font name\n");
+ exit (1);
+ }
+ if (old == 0) /* need to see "}" here */
+ {
+ (void) RTFGetToken ();
+ if (!RTFCheckCM (rtfGroup, rtfEndGroup))
+ {
+ fprintf (stderr, "Bad font table-5\n");
+ exit (1);
+ }
+ }
+ }
+ RTFRouteToken (); /* feed "}" back to router */
+}
+
+
+/*
+ The color table entries have color values of -1 if
+ the default color should be used for the entry (only
+ a semi-colon is given in the definition, no color values).
+ There will be a problem if a partial entry (1 or 2 but
+ not 3 color values) is given. The possibility is ignored
+ here.
+*/
+
+static void ReadColorTbl ()
+{
+RTFColor *cp;
+int cnum = 0;
+
+ for (;;)
+ {
+ (void) RTFGetToken ();
+ if (RTFCheckCM (rtfGroup, rtfEndGroup))
+ break;
+ if ((cp = New (RTFColor)) == NULL)
+ {
+ fprintf (stderr, "Can't allocate color entry\n");
+ exit (1);
+ }
+ cp->rtfCNum = cnum++;
+ cp->rtfCRed = cp->rtfCGreen = cp->rtfCBlue = -1;
+ cp->rtfNextColor = colorList;
+ colorList = cp;
+ for (;;)
+ {
+ if (!RTFCheckCM (rtfControl, rtfColorName))
+ break;
+ switch (rtfMinor)
+ {
+ case rtfRed: cp->rtfCRed = rtfParam; break;
+ case rtfGreen: cp->rtfCGreen = rtfParam; break;
+ case rtfBlue: cp->rtfCBlue = rtfParam; break;
+ }
+ RTFGetToken ();
+ }
+ if (!RTFCheckCM (rtfText, (int) ';'))
+ {
+ fprintf (stderr, "Bad color table\n");
+ exit (1);
+ }
+ }
+ RTFRouteToken (); /* feed "}" back to router */
+}
+
+
+/*
+ The "Normal" style definition doesn't contain any style number
+ (why?), all others do. Normal style is given style 0.
+*/
+
+static void ReadStyleSheet ()
+{
+RTFStyle *sp;
+RTFStyleElt *sep, *sepLast;
+char buf[rtfBufSiz], *bp;
+
+ for (;;)
+ {
+ (void) RTFGetToken ();
+ if (RTFCheckCM (rtfGroup, rtfEndGroup))
+ break;
+ if ((sp = New (RTFStyle)) == NULL)
+ {
+ fprintf (stderr, "Can't allocate style entry\n");
+ exit (1);
+ }
+ sp->rtfSNum = -1;
+ sp->rtfSBasedOn = rtfBasedOnNone;
+ sp->rtfSNextPar = -1;
+ sp->rtfSSEList = sepLast = NULL;
+ sp->rtfNextStyle = styleList;
+ sp->rtfExpanding = 0;
+ styleList = sp;
+ if (!RTFCheckCM (rtfGroup, rtfBeginGroup))
+ {
+ fprintf (stderr, "Bad stylesheet-1\n");
+ exit (1);
+ }
+ while (RTFGetToken () == rtfControl)
+ {
+ if (RTFCheckMM (rtfParAttr, rtfStyleNum))
+ {
+ sp->rtfSNum = rtfParam;
+ continue;
+ }
+ if (RTFCheckMM (rtfStyleAttr, rtfBasedOn))
+ {
+ sp->rtfSBasedOn = rtfParam;
+ continue;
+ }
+ if (RTFCheckMM (rtfStyleAttr, rtfNext))
+ {
+ sp->rtfSNextPar = rtfParam;
+ continue;
+ }
+ if ((sep = New (RTFStyleElt)) == NULL)
+ {
+ fprintf (stderr, "Can't allocate style element\n");
+ exit (1);
+ }
+ sep->rtfSEClass = rtfClass;
+ sep->rtfSEMajor = rtfMajor;
+ sep->rtfSEMinor = rtfMinor;
+ sep->rtfSEParam = rtfParam;
+ if ((sep->rtfSEText = RTFStrSave (rtfTextBuf)) == NULL)
+ {
+ fprintf (stderr, "Can't allocate style element\n");
+ exit (1);
+ }
+ if (sepLast == NULL) /* first style element */
+ sp->rtfSSEList = sep;
+ else /* add to end */
+ sepLast->rtfNextSE = sep;
+ sep->rtfNextSE = NULL;
+ sepLast = sep;
+ }
+ if (sp->rtfSNextPar == -1) /* \snext not given */
+ sp->rtfSNextPar = sp->rtfSNum; /* next is itself */
+ if (rtfClass != rtfText)
+ {
+ fprintf (stderr, "Bad stylesheet-2\n");
+ exit (1);
+ }
+ bp = buf;
+ while (rtfClass == rtfText)
+ {
+ if (rtfMajor == ';')
+ {
+ (void) RTFGetToken ();
+ break;
+ }
+ *bp++ = rtfMajor;
+ (void) RTFGetToken ();
+ }
+ *bp = '\0';
+ if (sp->rtfSNum < 0) /* no style number was specified */
+ { /* (only legal for Normal style) */
+ if (strcmp (buf, "Normal") != 0)
+ {
+ fprintf (stderr, "Bad stylesheet-3\n");
+ exit (1);
+ }
+ sp->rtfSNum = 0;
+ }
+ if ((sp->rtfSName = RTFStrSave (buf)) == NULL)
+ {
+ fprintf (stderr, "Can't allocate style name\n");
+ exit (1);
+ }
+ if (!RTFCheckCM (rtfGroup, rtfEndGroup))
+ {
+ fprintf (stderr, "Bad stylesheet-4\n");
+ exit (1);
+ }
+ }
+ RTFRouteToken (); /* feed "}" back to router */
+}
+
+
+static void ReadInfoGroup ()
+{
+ RTFSkipGroup ();
+ RTFRouteToken (); /* feed "}" back to router */
+}
+
+
+static void ReadPictGroup ()
+{
+ RTFSkipGroup ();
+ RTFRouteToken (); /* feed "}" back to router */
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ Routines to return pieces of stylesheet, or font or color tables
+*/
+
+
+RTFStyle *RTFGetStyle (num)
+int num;
+{
+RTFStyle *s;
+
+ if (num == -1)
+ return (styleList);
+ for (s = styleList; s != NULL; s = s->rtfNextStyle)
+ {
+ if (s->rtfSNum == num)
+ break;
+ }
+ return (s); /* NULL if not found */
+}
+
+
+RTFFont *RTFGetFont (num)
+int num;
+{
+RTFFont *f;
+
+ if (num == -1)
+ return (fontList);
+ for (f = fontList; f != NULL; f = f->rtfNextFont)
+ {
+ if (f->rtfFNum == num)
+ break;
+ }
+ return (f); /* NULL if not found */
+}
+
+
+RTFColor *RTFGetColor (num)
+int num;
+{
+RTFColor *c;
+
+ if (num == -1)
+ return (colorList);
+ for (c = colorList; c != NULL; c = c->rtfNextColor)
+ {
+ if (c->rtfCNum == num)
+ break;
+ }
+ return (c); /* NULL if not found */
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+
+/*
+ Expand style n, if there is such a style.
+*/
+
+void RTFExpandStyle (n)
+int n;
+{
+RTFStyle *s;
+RTFStyleElt *se;
+
+ if (n == -1 || (s = RTFGetStyle (n)) == NULL)
+ return;
+ if (s->rtfExpanding != 0)
+ {
+ fprintf (stderr, "Style expansion loop, style %d\n", n);
+ exit (1);
+ }
+ s->rtfExpanding = 1; /* set expansion flag for loop detection */
+ /*
+ Expand "based-on" style. This is done by synthesizing
+ the token that the writer needs to see in order to trigger
+ another style expansion, and feeding to token back through
+ the router so the writer sees it.
+ */
+ RTFSetToken (rtfControl, rtfParAttr, rtfStyleNum, s->rtfSBasedOn, "\\s");
+ RTFRouteToken ();
+ /*
+ Now route the tokens unique to this style
+ */
+ for (se = s->rtfSSEList; se != NULL; se = se->rtfNextSE)
+ {
+ rtfClass = se->rtfSEClass;
+ rtfMajor = se->rtfSEMajor;
+ rtfMinor = se->rtfSEMinor;
+ rtfParam = se->rtfSEParam;
+ strcpy (rtfTextBuf, se->rtfSEText);
+ rtfTextLen = strlen (rtfTextBuf);
+ RTFRouteToken ();
+ }
+ s->rtfExpanding = 0; /* done - clear expansion flag */
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ Control symbol lookup routines
+*/
+
+
+typedef struct RTFKey RTFKey;
+
+struct RTFKey
+{
+ int rtfKMajor; /* major number */
+ int rtfKMinor; /* minor number */
+ char *rtfKStr; /* symbol name */
+ int rtfKHash; /* symbol name hash value */
+};
+
+/*
+ A minor number of -1 means the token has no minor number
+ (all valid minor numbers are >= 0).
+*/
+
+static RTFKey rtfKey[] =
+{
+ rtfSpecialChar, rtfCurHeadPict, "chpict", 0, /* ?? */
+
+ rtfSpecialChar, rtfCurHeadDate, "chdate", 0,
+ rtfSpecialChar, rtfCurHeadTime, "chtime", 0,
+ rtfSpecialChar, rtfCurHeadPage, "chpgn", 0,
+ rtfSpecialChar, rtfCurFNote, "chftn", 0,
+ rtfSpecialChar, rtfCurAnnotRef, "chatn", 0,
+ rtfSpecialChar, rtfFNoteSep, "chftnsep", 0,
+ rtfSpecialChar, rtfFNoteCont, "chftnsepc", 0,
+ rtfSpecialChar, rtfFormula, "|", 0,
+ rtfSpecialChar, rtfNoBrkSpace, "~", 0,
+ rtfSpecialChar, rtfNoReqHyphen, "-", 0,
+ rtfSpecialChar, rtfNoBrkHyphen, "_", 0,
+ rtfSpecialChar, rtfCell, "cell", 0,
+ rtfSpecialChar, rtfRow, "row", 0,
+ rtfSpecialChar, rtfPar, "par", 0,
+ rtfSpecialChar, rtfPar, "\n", 0,
+ rtfSpecialChar, rtfPar, "\r", 0,
+ rtfSpecialChar, rtfSect, "sect", 0,
+ rtfSpecialChar, rtfPage, "page", 0,
+ rtfSpecialChar, rtfColumn, "column", 0,
+ rtfSpecialChar, rtfLine, "line", 0,
+ rtfSpecialChar, rtfTab, "tab", 0,
+ rtfSpecialChar, rtfOptDest, "*", 0,
+ rtfSpecialChar, rtfIIntVersion, "vern", 0,
+ rtfSpecialChar, rtfICreateTime, "creatim", 0,
+ rtfSpecialChar, rtfIRevisionTime, "revtim", 0,
+ rtfSpecialChar, rtfIPrintTime, "printim", 0,
+ rtfSpecialChar, rtfIBackupTime, "buptim", 0,
+ rtfSpecialChar, rtfIEditTime, "edmins", 0,
+ rtfSpecialChar, rtfIYear, "yr", 0,
+ rtfSpecialChar, rtfIMonth, "mo", 0,
+ rtfSpecialChar, rtfIDay, "dy", 0,
+ rtfSpecialChar, rtfIHour, "hr", 0,
+ rtfSpecialChar, rtfIMinute, "min", 0,
+ rtfSpecialChar, rtfINPages, "nofpages", 0,
+ rtfSpecialChar, rtfINWords, "nofwords", 0,
+ rtfSpecialChar, rtfINChars, "nofchars", 0,
+ rtfSpecialChar, rtfIIntID, "id", 0,
+
+ rtfCharAttr, rtfPlain, "plain", 0,
+ rtfCharAttr, rtfBold, "b", 0,
+ rtfCharAttr, rtfItalic, "i", 0,
+ rtfCharAttr, rtfStrikeThru, "strike", 0,
+ rtfCharAttr, rtfOutline, "outl", 0,
+ rtfCharAttr, rtfShadow, "shad", 0,
+ rtfCharAttr, rtfSmallCaps, "scaps", 0,
+ rtfCharAttr, rtfAllCaps, "caps", 0,
+ rtfCharAttr, rtfInvisible, "v", 0,
+ rtfCharAttr, rtfFontNum, "f", 0,
+ rtfCharAttr, rtfFontSize, "fs", 0,
+ rtfCharAttr, rtfExpand, "expnd", 0,
+ rtfCharAttr, rtfUnderline, "ul", 0,
+ rtfCharAttr, rtfWUnderline, "ulw", 0,
+ rtfCharAttr, rtfDUnderline, "uld", 0,
+ rtfCharAttr, rtfDbUnderline, "uldb", 0,
+ rtfCharAttr, rtfNoUnderline, "ulnone", 0,
+ rtfCharAttr, rtfSuperScript, "up", 0,
+ rtfCharAttr, rtfSubScript, "dn", 0,
+ rtfCharAttr, rtfRevised, "revised", 0,
+ rtfCharAttr, rtfForeColor, "cf", 0,
+ rtfCharAttr, rtfBackColor, "cb", 0,
+
+ rtfParAttr, rtfParDef, "pard", 0,
+ rtfParAttr, rtfStyleNum, "s", 0,
+ rtfParAttr, rtfQuadLeft, "ql", 0,
+ rtfParAttr, rtfQuadRight, "qr", 0,
+ rtfParAttr, rtfQuadJust, "qj", 0,
+ rtfParAttr, rtfQuadCenter, "qc", 0,
+ rtfParAttr, rtfFirstIndent, "fi", 0,
+ rtfParAttr, rtfLeftIndent, "li", 0,
+ rtfParAttr, rtfRightIndent, "ri", 0,
+ rtfParAttr, rtfSpaceBefore, "sb", 0,
+ rtfParAttr, rtfSpaceAfter, "sa", 0,
+ rtfParAttr, rtfSpaceBetween, "sl", 0,
+ rtfParAttr, rtfInTable, "intbl", 0,
+ rtfParAttr, rtfKeep, "keep", 0,
+ rtfParAttr, rtfKeepNext, "keepn", 0,
+ rtfParAttr, rtfSideBySide, "sbys", 0,
+ rtfParAttr, rtfPBBefore, "pagebb", 0,
+ rtfParAttr, rtfNoLineNum, "noline", 0,
+ rtfParAttr, rtfTabPos, "tx", 0,
+ rtfParAttr, rtfTabRight, "tqr", 0,
+ rtfParAttr, rtfTabCenter, "tqc", 0,
+ rtfParAttr, rtfTabDecimal, "tqdec", 0,
+ rtfParAttr, rtfTabBar, "tb", 0,
+ rtfParAttr, rtfBorderTop, "brdrt", 0,
+ rtfParAttr, rtfBorderBottom, "brdrb", 0,
+ rtfParAttr, rtfBorderLeft, "brdrl", 0,
+ rtfParAttr, rtfBorderRight, "brdrr", 0,
+ rtfParAttr, rtfBorderBar, "bar", 0,
+ rtfParAttr, rtfBorderBox, "box", 0,
+ rtfParAttr, rtfBorderBetween, "brdrbtw", 0,
+ rtfParAttr, rtfBorderSingle, "brdrs", 0,
+ rtfParAttr, rtfBorderThick, "brdrth", 0,
+ rtfParAttr, rtfBorderShadow, "brdrsh", 0,
+ rtfParAttr, rtfBorderDouble, "brdrdb", 0,
+ rtfParAttr, rtfBorderDot, "brdrdot", 0,
+ rtfParAttr, rtfBorderHair, "brdrhair", 0,
+ rtfParAttr, rtfLeaderDot, "tldot", 0,
+ rtfParAttr, rtfLeaderHyphen, "tlhyph", 0,
+ rtfParAttr, rtfLeaderUnder, "tlul", 0,
+ rtfParAttr, rtfLeaderThick, "tlth", 0,
+ rtfParAttr, rtfBorderSpace, "brsp", 0,
+
+ rtfSectAttr, rtfSectDef, "sectd", 0,
+ /*rtfSectAttr, rtfNoBreak, "nobreak", 0,
+ rtfSectAttr, rtfColBreak, "colbreak", 0,
+ rtfSectAttr, rtfPageBreak, "pagebreak", 0,
+ rtfSectAttr, rtfEvenBreak, "evenbreak", 0,
+ rtfSectAttr, rtfOddBreak, "oddbreak", 0,*/
+ rtfSectAttr, rtfNoBreak, "sbknone", 0,
+ rtfSectAttr, rtfColBreak, "sbkcol", 0,
+ rtfSectAttr, rtfPageBreak, "sbkpage", 0,
+ rtfSectAttr, rtfEvenBreak, "sbkeven", 0,
+ rtfSectAttr, rtfOddBreak, "sbkodd", 0,
+ rtfSectAttr, rtfPageCont, "pgncont", 0,
+ rtfSectAttr, rtfPageStarts, "pgnstarts", 0,
+ rtfSectAttr, rtfPageRestart, "pgnrestart", 0,
+ rtfSectAttr, rtfPageDecimal, "pgndec", 0,
+ rtfSectAttr, rtfPageURoman, "pgnucrm", 0,
+ rtfSectAttr, rtfPageLRoman, "pgnlcrm", 0,
+ rtfSectAttr, rtfPageULetter, "pgnucltr", 0,
+ rtfSectAttr, rtfPageLLetter, "pgnlcltr", 0,
+ rtfSectAttr, rtfPageNumLeft, "pgnx", 0,
+ rtfSectAttr, rtfPageNumTop, "pgny", 0,
+ rtfSectAttr, rtfHeaderY, "headery", 0,
+ rtfSectAttr, rtfFooterY, "footery", 0,
+ rtfSectAttr, rtfLineModulus, "linemod", 0,
+ rtfSectAttr, rtfLineDist, "linex", 0,
+ rtfSectAttr, rtfLineStarts, "linestarts", 0,
+ rtfSectAttr, rtfLineRestart, "linerestart", 0,
+ rtfSectAttr, rtfLineRestartPg, "lineppage", 0,
+ rtfSectAttr, rtfLineCont, "linecont", 0,
+ rtfSectAttr, rtfTopVAlign, "vertalt", 0,
+ rtfSectAttr, rtfBottomVAlign, "vertal", 0,
+ rtfSectAttr, rtfCenterVAlign, "vertalc", 0,
+ rtfSectAttr, rtfJustVAlign, "vertalj", 0,
+ rtfSectAttr, rtfColumns, "cols", 0,
+ rtfSectAttr, rtfColumnSpace, "colsx", 0,
+ rtfSectAttr, rtfColumnLine, "linebetcol", 0,
+ rtfSectAttr, rtfENoteHere, "endnhere", 0,
+ rtfSectAttr, rtfTitleSpecial, "titlepg", 0,
+
+ rtfDocAttr, rtfPaperWidth, "paperw", 0,
+ rtfDocAttr, rtfPaperHeight, "paperh", 0,
+ rtfDocAttr, rtfLeftMargin, "margl", 0,
+ rtfDocAttr, rtfRightMargin, "margr", 0,
+ rtfDocAttr, rtfTopMargin, "margt", 0,
+ rtfDocAttr, rtfBottomMargin, "margb", 0,
+ rtfDocAttr, rtfFacingPage, "facingp", 0,
+ rtfDocAttr, rtfGutterWid, "gutter", 0,
+ rtfDocAttr, rtfDefTab, "deftab", 0,
+ rtfDocAttr, rtfWidowCtrl, "widowctrl", 0,
+ rtfDocAttr, rtfHyphHotZone, "hyphhotz", 0,
+ rtfDocAttr, rtfFNoteEndSect, "endnotes", 0,
+ rtfDocAttr, rtfFNoteEndDoc, "enddoc", 0,
+ rtfDocAttr, rtfFNoteBottom, "ftnbj", 0,
+ rtfDocAttr, rtfFNoteText, "ftntj", 0,
+ rtfDocAttr, rtfFNoteStart, "ftnstart", 0,
+ rtfDocAttr, rtfFNoteRestart, "ftnrestart", 0,
+ rtfDocAttr, rtfPageStart, "pgnstart", 0,
+ rtfDocAttr, rtfLineStart, "linestart", 0,
+ rtfDocAttr, rtfLandscape, "landscape", 0,
+ rtfDocAttr, rtfFracWidth, "fracwidth", 0,
+ rtfDocAttr, rtfNextFile, "nextfile", 0,
+ rtfDocAttr, rtfTemplate, "template", 0,
+ rtfDocAttr, rtfMakeBackup, "makeback", 0,
+ rtfDocAttr, rtfRTFDefault, "defformat", 0,
+ rtfDocAttr, rtfRevisions, "revisions", 0,
+ rtfDocAttr, rtfMirrorMargin, "margmirror", 0,
+ rtfDocAttr, rtfRevDisplay, "revprop", 0,
+ rtfDocAttr, rtfRevBar, "revbar", 0,
+
+ rtfStyleAttr, rtfBasedOn, "sbasedon", 0,
+ rtfStyleAttr, rtfNext, "snext", 0,
+
+ rtfPictAttr, rtfMacQD, "macpict", 0,
+ rtfPictAttr, rtfWinMetafile, "wmetafile", 0,
+ rtfPictAttr, rtfWinBitmap, "wbitmap", 0,
+ rtfPictAttr, rtfPicWid, "picw", 0,
+ rtfPictAttr, rtfPicHt, "pich", 0,
+ rtfPictAttr, rtfPicGoalWid, "picwgoal", 0,
+ rtfPictAttr, rtfPicGoalWid, "picwGoal", 0,
+ rtfPictAttr, rtfPicGoalHt, "pichgoal", 0,
+ rtfPictAttr, rtfPicGoalHt, "pichGoal", 0,
+ rtfPictAttr, rtfPicScaleX, "picscalex", 0,
+ rtfPictAttr, rtfPicScaleY, "picscaley", 0,
+ rtfPictAttr, rtfPicScaled, "picscaled", 0,
+ rtfPictAttr, rtfPicCropTop, "piccropt", 0,
+ rtfPictAttr, rtfPicCropBottom, "piccropb", 0,
+ rtfPictAttr, rtfPicCropLeft, "piccropl", 0,
+ rtfPictAttr, rtfPicCropRight, "piccropr", 0,
+ rtfPictAttr, rtfPixelBits, "wbmbitspixel", 0,
+ rtfPictAttr, rtfBitmapPlanes, "wbmplanes", 0,
+ rtfPictAttr, rtfBitmapWid, "wbmwidthbytes", 0,
+ rtfPictAttr, rtfPicBinary, "bin", 0,
+
+ rtfDestination, rtfPict, "pict", 0,
+ rtfDestination, rtfFootnote, "footnote", 0,
+ rtfDestination, rtfHeader, "header", 0,
+ rtfDestination, rtfHeaderLeft, "headerl", 0,
+ rtfDestination, rtfHeaderRight, "headerr", 0,
+ rtfDestination, rtfHeaderFirst, "headerf", 0,
+ rtfDestination, rtfFooter, "footer", 0,
+ rtfDestination, rtfFooterLeft, "footerl", 0,
+ rtfDestination, rtfFooterRight, "footerr", 0,
+ rtfDestination, rtfFooterFirst, "footerf", 0,
+ rtfDestination, rtfFNSep, "ftnsep", 0,
+ rtfDestination, rtfFNContSep, "ftnsepc", 0,
+ rtfDestination, rtfFNContNotice, "ftncn", 0,
+ rtfDestination, rtfInfo, "info", 0,
+ rtfDestination, rtfStyleSheet, "stylesheet", 0,
+ rtfDestination, rtfFontTbl, "fonttbl", 0,
+ rtfDestination, rtfColorTbl, "colortbl", 0,
+ rtfDestination, rtfAnnotation, "annotation", 0,
+ rtfDestination, rtfAnnotID, "atnid", 0,
+ rtfDestination, rtfField, "field", 0,
+ rtfDestination, rtfFieldInst, "fldinst", 0,
+ rtfDestination, rtfFieldResult, "fldrslt", 0,
+ rtfDestination, rtfIndex, "xe", 0,
+ rtfDestination, rtfIndexBold, "bxe", 0,
+ rtfDestination, rtfIndexItalic, "ixe", 0,
+ rtfDestination, rtfIndexText, "txe", 0,
+ rtfDestination, rtfIndexRange, "rxe", 0,
+ rtfDestination, rtfTOC, "tc", 0,
+ rtfDestination, rtfBookmarkStart, "bkmkstart", 0,
+ rtfDestination, rtfBookmarkEnd, "bkmkend", 0,
+ rtfDestination, rtfITitle, "title", 0,
+ rtfDestination, rtfISubject, "subject", 0,
+ rtfDestination, rtfIAuthor, "author", 0,
+ rtfDestination, rtfIOperator, "operator", 0,
+ rtfDestination, rtfIKeywords, "keywords", 0,
+ rtfDestination, rtfIComment, "comment", 0,
+ rtfDestination, rtfIVersion, "version", 0,
+ rtfDestination, rtfIDoccomm, "doccomm", 0,
+
+ rtfTOCAttr, rtfTOCType, "tcf", 0,
+ rtfTOCAttr, rtfTOCLevel, "tcl", 0,
+
+ rtfFontFamily, rtfFFNil, "fnil", 0,
+ rtfFontFamily, rtfFFRoman, "froman", 0,
+ rtfFontFamily, rtfFFSwiss, "fswiss", 0,
+ rtfFontFamily, rtfFFModern, "fmodern", 0,
+ rtfFontFamily, rtfFFScript, "fscript", 0,
+ rtfFontFamily, rtfFFDecor, "fdecor", 0,
+ rtfFontFamily, rtfFFTech, "ftech", 0,
+
+ rtfColorName, rtfRed, "red", 0,
+ rtfColorName, rtfGreen, "green", 0,
+ rtfColorName, rtfBlue, "blue", 0,
+
+ rtfCharSet, rtfMacCharSet, "mac", 0,
+ rtfCharSet, rtfAnsiCharSet, "ansi", 0,
+ rtfCharSet, rtfPcCharSet, "pc", 0,
+ rtfCharSet, rtfPcaCharSet, "pca", 0,
+
+ rtfTblAttr, rtfCellBordBottom, "clbrdrb", 0,
+ rtfTblAttr, rtfCellBordTop, "clbrdrt", 0,
+ rtfTblAttr, rtfCellBordLeft, "clbrdrl", 0,
+ rtfTblAttr, rtfCellBordRight, "clbrdrr", 0,
+ rtfTblAttr, rtfRowDef, "trowd", 0,
+ rtfTblAttr, rtfRowLeft, "trql", 0,
+ rtfTblAttr, rtfRowRight, "trqr", 0,
+ rtfTblAttr, rtfRowCenter, "trqc", 0,
+ rtfTblAttr, rtfRowGapH, "trgaph", 0,
+ rtfTblAttr, rtfRowHt, "trrh", 0,
+ rtfTblAttr, rtfRowLeftEdge, "trleft", 0,
+ rtfTblAttr, rtfCellPos, "cellx", 0,
+ rtfTblAttr, rtfMergeRngFirst, "clmgf", 0,
+ rtfTblAttr, rtfMergePrevious, "clmrg", 0,
+
+ rtfFieldAttr, rtfFieldDirty, "flddirty", 0,
+ rtfFieldAttr, rtfFieldEdited, "fldedit", 0,
+ rtfFieldAttr, rtfFieldLocked, "fldlock", 0,
+ rtfFieldAttr, rtfFieldPrivate, "fldpriv", 0,
+
+ rtfPosAttr, rtfPosX, "posx", 0,
+ rtfPosAttr, rtfPosXCenter, "posxc", 0,
+ rtfPosAttr, rtfPosXInside, "posxi", 0,
+ rtfPosAttr, rtfPosXLeft, "posxl", 0,
+ rtfPosAttr, rtfPosXOutSide, "posxo", 0,
+ rtfPosAttr, rtfPosXRight, "posxr", 0,
+ rtfPosAttr, rtfPosY, "posy", 0,
+ rtfPosAttr, rtfPosYInline, "posyil", 0,
+ rtfPosAttr, rtfPosYTop, "posyt", 0,
+ rtfPosAttr, rtfPosYCenter, "posyc", 0,
+ rtfPosAttr, rtfPosYBottom, "posyb", 0,
+ rtfPosAttr, rtfAbsWid, "absw", 0,
+ rtfPosAttr, rtfTextDist, "dxfrtext", 0,
+ rtfPosAttr, rtfRPosMargV, "pvmrg", 0,
+ rtfPosAttr, rtfRPosPageV, "pvpg", 0,
+ rtfPosAttr, rtfRPosMargH, "phmrg", 0,
+ rtfPosAttr, rtfRPosPageH, "phpg", 0,
+ rtfPosAttr, rtfRPosColH, "phcol", 0,
+
+ rtfVersion, -1, "rtf", 0,
+ rtfDefFont, -1, "deff", 0,
+
+ 0, -1, NULL, 0
+};
+
+
+/*
+ Initialize lookup table hash values
+*/
+
+static void LookupInit ()
+{
+static int inited = 0;
+RTFKey *rp;
+
+ if (inited == 0)
+ {
+ for (rp = rtfKey; rp->rtfKStr != NULL; rp++)
+ rp->rtfKHash = Hash (rp->rtfKStr);
+ ++inited;
+ }
+}
+
+
+/*
+ Determine major and minor number of control token. If it's
+ not found, the class turns into rtfUnknown.
+*/
+
+static void Lookup (s)
+char *s;
+{
+RTFKey *rp;
+int hash;
+
+ ++s; /* skip over the leading \ character */
+ hash = Hash (s);
+ for (rp = rtfKey; rp->rtfKStr != NULL; rp++)
+ {
+ if (hash == rp->rtfKHash && strcmp (s, rp->rtfKStr) == 0)
+ {
+ rtfClass = rtfControl;
+ rtfMajor = rp->rtfKMajor;
+ rtfMinor = rp->rtfKMinor;
+ return;
+ }
+ }
+ rtfClass = rtfUnknown;
+}
+
+
+/*
+ Compute hash value of symbol
+*/
+
+static int Hash (s)
+char *s;
+{
+char c;
+int val = 0;
+
+ while ((c = *s++) != '\0')
+ val += (int) c;
+ return (val);
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ Memory allocation routines
+*/
+
+
+/*
+ Return pointer to block of size bytes, or NULL if there's
+ not enough memory available.
+*/
+
+char *RTFAlloc (size)
+int size;
+{
+ return (malloc (size));
+}
+
+
+/*
+ Saves a string on the heap and returns a pointer to it.
+*/
+
+
+char *RTFStrSave (s)
+char *s;
+{
+char *p;
+
+ if ((p = RTFAlloc (strlen (s) + 1)) == NULL)
+ return (NULL);
+ return (strcpy (p, s));
+}
+
+
+void RTFFree (p)
+char *p;
+{
+ if (p != NULL)
+ free (p);
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+
+/*
+ Token comparison routines
+*/
+
+int RTFCheckCM (class, major)
+int class, major;
+{
+ return (rtfClass == class && rtfMajor == major);
+}
+
+
+int RTFCheckCMM (class, major, minor)
+int class, major, minor;
+{
+ return (rtfClass == class && rtfMajor == major && rtfMinor == minor);
+}
+
+
+int RTFCheckMM (major, minor)
+int major, minor;
+{
+ return (rtfMajor == major && rtfMinor == minor);
+}
diff --git a/support/RTF-1_06a1/rtf-misc.ms b/support/RTF-1_06a1/rtf-misc.ms
new file mode 100644
index 0000000000..eb2af43618
--- /dev/null
+++ b/support/RTF-1_06a1/rtf-misc.ms
@@ -0,0 +1,203 @@
+.\"
+.\" troff -ms % | lpr
+.\"
+.\" revision date - change whenever this file is edited
+.ds RD 4 April 1991
+.nr PO 1.2i \" page offset 1.2 inches
+.nr PD .7v \" inter-paragraph distance
+.\"
+.EH 'RTF Miscellanea'- % -''
+.OH ''- % -'RTF Miscellanea'
+.OF 'Revision date:\0\0\*(RD''Printed:\0\0\n(dy \*(MO 19\n(yr'
+.EF 'Revision date:\0\0\*(RD''Printed:\0\0\n(dy \*(MO 19\n(yr'
+.\"
+.\" subscript strings
+.ds < \s-2\v'.4m'
+.ds > \v'-.4m'\s+2
+.\"
+.\" I - italic font (taken from -ms and changed)
+.de I
+.nr PQ \\n(.f
+.if t \&\\$3\\f2\\$1\\fP\&\\$2
+.if n .if \\n(.$=1 \&\\$1
+.if n .if \\n(.$>1 \&\\$1\c
+.if n .if \\n(.$>1 \&\\$2
+..
+.TL
+RTF Miscellany
+.AU
+Paul DuBois
+dubois@primate.wisc.edu
+.AI
+Wisconsin Regional Primate Research Center
+Revision date:\0\0\*(RD
+.SH
+Introduction
+.LP
+This document contains a few scribblings about things which don't seem to be
+covered in the RTF specification.
+Any or all conjectures here may be false; if so, I'd like to know about it.
+Counterexamples or references to corrections would be appreciated, as my
+conclusions are based on observation.
+.LP
+Nomenclature:
+.DS
+WfM Word for Macintosh
+WfW Word for Windows
+.DE
+.SH
+Page Orientation
+.LP
+WfM and WfW write the paper width and height correctly,
+but don't write ``\elandscape'' into landscape documents.
+I consider this a bug.
+Another bug is that if you read such an RTF document back into WfM (and
+maybe WfW), it sets the page orientation back to portrait.
+.SH
+Tab Handling
+.LP
+When a new group begins (with ``{''), it inherits the tab stops of the group
+within which it occurs.
+However, if any tabs are explicitly set within the group, they
+override the inherited set.
+.LP
+The same is true with regard to tabs stops that a group may get as a
+result of a style setting.
+If tabs are set within the style, they override inherited tabs.
+Again, however, if tabs are explicitly set within the group, they
+override not only any inherited tabs, but any tabs that may have been
+set within the style.
+.LP
+For translator purposes, the upshot is that it's necessary to know
+when a style is being expanded (so you know to override inherited
+tabs), and when the expansion is done (so you know when to override
+style tabs).
+.LP
+Tabs may be associated with a leader character, and may have a
+justification attribute.
+I have seen an RTF specification (non-Microsoft) which claimed that
+justifications apply to the last specified tab position.
+My experience is that the opposite is true.
+(The Microsoft spec seems to be silent on this point.)
+The leader character does indeed apply to following tab positions,
+but the justification attribute applies to the next tab position
+specified.
+If no justification is given, the tab defaults to left-justified.
+.LP
+For translators, this means that if a justification indicator occurs, you
+apply it when the next tabstop position is given, otherwise the tabstop
+is left-justified.
+.SH
+Styles
+.LP
+The ``Normal'' style definition does not seem to ever include a style
+number within it, unlike all others.
+I assume it's style 0, since other styles that are based on the
+Normal style have ``\esbasedon0'' as part of their definition.
+The Normal style also includes the control word ``\esbasedon222'', but
+style 222 is never defined.
+Presumably this is a way of indicating ``not based on any other style,''
+although why the value 222 was chosen is beyond me.
+.LP
+Stylesheet entries may also leave out the ``\esbasedon'' control word
+(WfW does this).
+In this case, the default should be 222.
+I've only seen this in Normal style entries.
+.LP
+I have not seen any documents where the ``\esnext'' control word is
+left out, but if it were, presumably the style should be its own next
+style.
+.SH
+Restoring Defaults
+.LP
+Apparently, when ``\epard'' is encountered, the way to restore paragraph
+defaults is to restore not only all the static initial paragraph formatting
+values, but also to apply the Normal style.
+.LP
+The control word ``\eplain'' is much like ``\epard'' but for characters.
+Why it's not ``\echard'' I don't know, but the effect is not only to restore
+character style to plain, but also default font size, expansion value, etc.
+.SH
+Special Characters
+.LP
+Different character sets may be specified in RTF documents (e.g., ``\eansi'',
+``\emac''), and characters within one set may have no representation in
+another set.
+For instance, the Apple character in the Macintosh character set has
+no counterpart in the ANSI character set.
+This constitutes a failure of RTF to provide machine independence.
+.SH
+Fonts
+.LP
+The default font (specified with ``\edeff'') need not be included in
+the font table.
+Don't assume it will be there.
+.LP
+The font name for a given font may vary among systems.
+``Times Roman'' in WfM is ``Tms Rmn'' in WfW.
+The font family may also differ.
+WfM associates ``\eftech'' with the Symbol font, whereas WfW associates
+it with ``\efdecor''.
+Another failure of machine independence.
+.LP
+Presumably the font name differences are related to the method (or
+lack of it) provided by underlying system software for referring to
+fonts from within programs.
+Translators, which may be writing output for target systems having an
+entirely different set of conventions, should provide their own
+mechanism for mapping RTF font names onto the fonts that are
+available.
+.LP
+It is instructive to observe that WfM and WfW do not do particularly
+well at figuring out the fonts used in an RTF document created by each other.
+.SH
+Tables
+.LP
+The Microsoft RTF specification says very little about the constraints on
+the order in which table formatting control words may appear.
+The inferences below are based on inspection of several RTF tables, but as
+this is an inductive process, it's hard to say whether they are generally
+true, or only true of those files at which I've looked.
+.LP
+Cells are like tabs in that a cell may have a position and other
+attributes.
+The position applies to the right edge.
+The other attributes, if specified, occur
+.I before
+the position specifier.
+.LP
+In the table layout information at the beginning of the table,
+cell border control words are
+.I followed
+immediately by a border type control word.
+This is one place where a translator may want to read ahead in the input
+stream to get the border type.
+It appears that more than one border type word may follow the cell border
+control word, ``\eclbrdrb\ebrdrsh\ebrdrs''.
+.LP
+It appears that (i) ``\etrowd'' occurs as the first control word of a table;
+(ii) the row ends with ``\erow'';
+(iii) everything between specifies the format and content of the row.
+It further appears that the table ``state'' is completely independent of
+the grouping level.
+.LP
+Cells begin with the
+.I first
+``\eintbl'' and after
+.I each
+``\ecell'' control word.
+Cells end after each ``\ecell'' and ``\erow'' control word.
+Cells can
+.I not
+be assumed to begin with every ``\eintbl'' since every paragraph within
+a table cell begins with that control word.
+.LP
+Tabs specified within a cell are relative to the left edge of the cell,
+not the left margin of the page.
+.LP
+WfM seems to write an empty cell at the end of each row.
+For instance, if there are three cells, there will be three token sequences,
+each ending with ``\ecell'', then another sequence (typically ``\epard
+\eintbl'') ending with ``\erow''.
+This probably corresponds to the ghost column you see at the end of tables
+when you select them or show formatting codes.
diff --git a/support/RTF-1_06a1/rtf.h b/support/RTF-1_06a1/rtf.h
new file mode 100644
index 0000000000..30e4cb4bb8
--- /dev/null
+++ b/support/RTF-1_06a1/rtf.h
@@ -0,0 +1,484 @@
+/*
+ rtf.h - RTF document processing stuff. Distribution 1.06.
+*/
+
+
+/*
+ Twentieths of a point (twips) per inch (Many RTF measurements
+ are in twips per inch (tpi) units). Assumes 72 points/inch.
+*/
+
+# define rtfTpi 1440
+
+/*
+ RTF buffer size (avoids BUFSIZ, which differs across systems)
+*/
+
+# define rtfBufSiz 1024
+
+/*
+ Tokens are associated with up to three classification numbers:
+
+ Class number: Broadest (least detailed) breakdown. For programs
+ that only care about gross token distinctions.
+ Major/minor numbers: Within their class, tokens have a major
+ number, and may also have a minor number to further
+ distinquish tokens with the same major number.
+
+ *** Class, major and minor token numbers are all >= 0 ***
+
+ Tokens that can't be classified are put in the "unknown" class.
+ For such, the major and minor numbers are meaningless, although
+ rtfTextBuf may be of interest then.
+
+ Text tokens are a single character, and the major number indicates
+ the character value (note: can be non-ascii, i.e., greater than 127).
+ There is no minor number.
+
+ Control symbols may have a parameter value, which will be found in
+ rtfParam.
+
+ RTFToken() return value is the class number, but it sets all the
+ global token vars.
+
+ rtfEOF is a fake token used by the reader; the writer never sees
+ it (except in the token reader hook, if it installs one).
+*/
+
+
+/*
+ Information pertaining to last token read by RTFToken. The
+ text is exactly as it occurs in the input file, e.g., "\{"
+ will be found in rtfTextBuf as "\{", even though it means "{".
+ These variables are also set when styles are reprocessed.
+*/
+
+extern char rtfTextBuf[rtfBufSiz]; /* text of token */
+extern int rtfTextLen; /* length of token in rtfTextBuf */
+extern int rtfClass; /* token class */
+extern int rtfMajor; /* token major number */
+extern int rtfMinor; /* token minor number */
+extern int rtfParam; /* control symbol parameter */
+
+
+/*
+ Token classes (must be zero-based and sequential)
+*/
+
+# define rtfUnknown 0
+# define rtfGroup 1
+# define rtfText 2
+# define rtfControl 3
+# define rtfEOF 4
+# define rtfMaxClass 5 /* highest class + 1 */
+
+/*
+ Brace class major numbers
+*/
+
+# define rtfBeginGroup 0
+# define rtfEndGroup 1
+
+/*
+ Control class major and minor numbers.
+*/
+
+# define rtfVersion 0
+
+# define rtfDefFont 1
+
+# define rtfCharSet 2
+# define rtfAnsiCharSet 0
+# define rtfMacCharSet 1
+# define rtfPcCharSet 2
+# define rtfPcaCharSet 3
+
+
+/* destination minor numbers should be zero-based, sequential */
+
+# define rtfDestination 3
+# define rtfPict 0
+# define rtfFootnote 1
+# define rtfHeader 2
+# define rtfHeaderLeft 3
+# define rtfHeaderRight 4
+# define rtfHeaderFirst 5
+# define rtfFooter 6
+# define rtfFooterLeft 7
+# define rtfFooterRight 8
+# define rtfFooterFirst 9
+# define rtfFNSep 10
+# define rtfFNContSep 11
+# define rtfFNContNotice 12
+# define rtfInfo 13
+# define rtfStyleSheet 14
+# define rtfFontTbl 15
+# define rtfColorTbl 16
+# define rtfField 17
+# define rtfFieldInst 18
+# define rtfFieldResult 19
+# define rtfIndex 20
+# define rtfIndexBold 21
+# define rtfIndexItalic 22
+# define rtfIndexText 23
+# define rtfIndexRange 24
+# define rtfTOC 25
+# define rtfBookmarkStart 26
+# define rtfBookmarkEnd 27
+# define rtfITitle 28
+# define rtfISubject 29
+# define rtfIAuthor 30
+# define rtfIOperator 31
+# define rtfIKeywords 32
+# define rtfIComment 33
+# define rtfIVersion 34
+# define rtfIDoccomm 35
+# define rtfMaxDestination 36 /* highest dest + 1 */
+
+# define rtfFontFamily 4
+# define rtfFFNil 0
+# define rtfFFRoman 1
+# define rtfFFSwiss 2
+# define rtfFFModern 3
+# define rtfFFScript 4
+# define rtfFFDecor 5
+# define rtfFFTech 6
+
+# define rtfColorName 5
+# define rtfRed 0
+# define rtfGreen 1
+# define rtfBlue 2
+
+# define rtfSpecialChar 6
+# define rtfCurHeadPage 0
+# define rtfCurFNote 1
+# define rtfCurHeadPict 2 /* valid? */
+# define rtfCurHeadDate 3
+# define rtfCurHeadTime 4
+# define rtfFormula 5
+# define rtfNoBrkSpace 6
+# define rtfNoReqHyphen 7
+# define rtfNoBrkHyphen 8
+# define rtfPage 9
+# define rtfLine 10
+# define rtfPar 11
+# define rtfSect 12
+# define rtfTab 13
+# define rtfCell 14
+# define rtfRow 15
+# define rtfCurAnnot 16
+# define rtfAnnotation 17
+# define rtfAnnotID 18
+# define rtfCurAnnotRef 19
+# define rtfFNoteSep 20
+# define rtfFNoteCont 21
+# define rtfColumn 22
+# define rtfOptDest 23
+# define rtfIIntVersion 24
+# define rtfICreateTime 25
+# define rtfIRevisionTime 26
+# define rtfIPrintTime 27
+# define rtfIBackupTime 28
+# define rtfIEditTime 29
+# define rtfIYear 30
+# define rtfIMonth 31
+# define rtfIDay 32
+# define rtfIHour 33
+# define rtfIMinute 34
+# define rtfINPages 35
+# define rtfINWords 36
+# define rtfINChars 37
+# define rtfIIntID 38
+
+# define rtfStyleAttr 7
+# define rtfBasedOn 0
+# define rtfNext 1
+
+# define rtfDocAttr 8
+# define rtfPaperWidth 0
+# define rtfPaperHeight 1
+# define rtfLeftMargin 2
+# define rtfRightMargin 3
+# define rtfTopMargin 4
+# define rtfBottomMargin 5
+# define rtfFacingPage 6
+# define rtfGutterWid 7
+# define rtfDefTab 8
+# define rtfWidowCtrl 9
+# define rtfHyphHotZone 10
+# define rtfFNoteEndSect 11
+# define rtfFNoteEndDoc 12
+# define rtfFNoteText 13
+# define rtfFNoteBottom 14
+# define rtfFNoteStart 15
+# define rtfFNoteRestart 16
+# define rtfPageStart 17
+# define rtfLineStart 18
+# define rtfLandscape 19
+# define rtfFracWidth 20
+# define rtfNextFile 21
+# define rtfTemplate 22
+# define rtfMakeBackup 23
+# define rtfRTFDefault 24
+# define rtfRevisions 25
+# define rtfMirrorMargin 26
+# define rtfRevDisplay 27
+# define rtfRevBar 28
+
+# define rtfSectAttr 9
+# define rtfSectDef 0
+# define rtfNoBreak 1
+# define rtfColBreak 2
+# define rtfPageBreak 3
+# define rtfEvenBreak 4
+# define rtfOddBreak 5
+# define rtfPageStarts 6
+# define rtfPageCont 7
+# define rtfPageRestart 8
+# define rtfPageDecimal 9
+# define rtfPageURoman 10
+# define rtfPageLRoman 11
+# define rtfPageULetter 12
+# define rtfPageLLetter 13
+# define rtfPageNumLeft 14
+# define rtfPageNumTop 15
+# define rtfHeaderY 16
+# define rtfFooterY 17
+# define rtfLineModulus 18
+# define rtfLineDist 19
+# define rtfLineStarts 20
+# define rtfLineRestart 21
+# define rtfLineRestartPg 22
+# define rtfLineCont 23
+# define rtfTopVAlign 24
+# define rtfBottomVAlign 25
+# define rtfCenterVAlign 26
+# define rtfJustVAlign 27
+# define rtfColumns 28
+# define rtfColumnSpace 29
+# define rtfColumnLine 30
+# define rtfENoteHere 31
+# define rtfTitleSpecial 32
+
+# define rtfTblAttr 10
+# define rtfCellBordBottom 0
+# define rtfCellBordTop 1
+# define rtfCellBordLeft 2
+# define rtfCellBordRight 3
+# define rtfRowDef 4
+# define rtfRowLeft 5
+# define rtfRowRight 6
+# define rtfRowCenter 7
+# define rtfRowGapH 8
+# define rtfRowHt 9
+# define rtfRowLeftEdge 10
+# define rtfCellPos 11
+# define rtfMergeRngFirst 12
+# define rtfMergePrevious 13
+
+# define rtfParAttr 11
+# define rtfParDef 0
+# define rtfStyleNum 1
+# define rtfQuadLeft 2
+# define rtfQuadRight 3
+# define rtfQuadJust 4
+# define rtfQuadCenter 5
+# define rtfFirstIndent 6
+# define rtfLeftIndent 7
+# define rtfRightIndent 8
+# define rtfSpaceBefore 9
+# define rtfSpaceAfter 10
+# define rtfSpaceBetween 11
+# define rtfInTable 12
+# define rtfKeep 13
+# define rtfKeepNext 14
+# define rtfSideBySide 15
+# define rtfPBBefore 16
+# define rtfNoLineNum 17
+# define rtfTabPos 18
+# define rtfTabRight 19
+# define rtfTabCenter 20
+# define rtfTabDecimal 21
+# define rtfTabBar 22
+# define rtfBorderTop 23
+# define rtfBorderBottom 24
+# define rtfBorderLeft 25
+# define rtfBorderRight 26
+# define rtfBorderBox 27
+# define rtfBorderBar 28
+# define rtfBorderBetween 29
+# define rtfBorderSingle 30
+# define rtfBorderThick 31
+# define rtfBorderShadow 32
+# define rtfBorderDouble 33
+# define rtfBorderDot 34
+# define rtfBorderHair 35
+# define rtfBorderSpace 36
+# define rtfLeaderDot 37
+# define rtfLeaderHyphen 38
+# define rtfLeaderUnder 39
+# define rtfLeaderThick 40
+
+# define rtfCharAttr 12
+# define rtfPlain 0
+# define rtfBold 1
+# define rtfItalic 2
+# define rtfStrikeThru 3
+# define rtfOutline 4
+# define rtfShadow 5
+# define rtfSmallCaps 6
+# define rtfAllCaps 7
+# define rtfInvisible 8
+# define rtfFontNum 9
+# define rtfFontSize 10
+# define rtfExpand 11
+# define rtfUnderline 12
+# define rtfWUnderline 13
+# define rtfDUnderline 14
+# define rtfDbUnderline 15
+# define rtfNoUnderline 16
+# define rtfSuperScript 17
+# define rtfSubScript 18
+# define rtfRevised 19
+# define rtfForeColor 20
+# define rtfBackColor 21
+
+# define rtfPictAttr 13
+# define rtfMacQD 0
+# define rtfWinMetafile 1
+# define rtfWinBitmap 2
+# define rtfPicWid 3
+# define rtfPicHt 4
+# define rtfPicGoalWid 5
+# define rtfPicGoalHt 6
+# define rtfPicScaleX 7
+# define rtfPicScaleY 8
+# define rtfPicScaled 9
+# define rtfPicCropTop 10
+# define rtfPicCropBottom 11
+# define rtfPicCropLeft 12
+# define rtfPicCropRight 13
+# define rtfPixelBits 14
+# define rtfBitmapPlanes 15
+# define rtfBitmapWid 16
+# define rtfPicBinary 17
+
+# define rtfFieldAttr 14
+# define rtfFieldDirty 0
+# define rtfFieldEdited 1
+# define rtfFieldLocked 2
+# define rtfFieldPrivate 3
+
+# define rtfTOCAttr 15
+# define rtfTOCType 0
+# define rtfTOCLevel 1
+
+# define rtfPosAttr 16
+# define rtfPosX 0
+# define rtfPosXCenter 1
+# define rtfPosXInside 2
+# define rtfPosXLeft 3
+# define rtfPosXOutSide 4
+# define rtfPosXRight 5
+# define rtfPosY 6
+# define rtfPosYInline 7
+# define rtfPosYTop 8
+# define rtfPosYCenter 9
+# define rtfPosYBottom 10
+# define rtfAbsWid 11
+# define rtfTextDist 12
+# define rtfRPosMargV 13
+# define rtfRPosPageV 14
+# define rtfRPosMargH 15
+# define rtfRPosPageH 16
+# define rtfRPosColH 17
+
+
+
+/*
+ RTF font, color and style structures. Used for font table,
+ color table, and stylesheet processing.
+*/
+
+typedef struct RTFFont RTFFont;
+typedef struct RTFColor RTFColor;
+typedef struct RTFStyle RTFStyle;
+typedef struct RTFStyleElt RTFStyleElt;
+
+
+struct RTFFont
+{
+ char *rtfFName; /* font name */
+ int rtfFNum; /* font number */
+ int rtfFFamily; /* font family */
+ RTFFont *rtfNextFont; /* next font in list */
+};
+
+
+/*
+ Color values are -1 if the default color for the the color
+ number should be used. The default color is writer-dependent.
+*/
+
+struct RTFColor
+{
+ int rtfCNum; /* color number */
+ int rtfCRed; /* red value */
+ int rtfCGreen; /* green value */
+ int rtfCBlue; /* blue value */
+ RTFColor *rtfNextColor; /* next color in list */
+};
+
+
+struct RTFStyle
+{
+ char *rtfSName; /* style name */
+ int rtfSNum; /* style number */
+ int rtfSBasedOn; /* style this one's based on */
+ int rtfSNextPar; /* style next paragraph style */
+ RTFStyleElt *rtfSSEList; /* list of style words */
+ int rtfExpanding; /* non-zero = being expanded */
+ RTFStyle *rtfNextStyle; /* next style in style list */
+};
+
+# define rtfBasedOnNone 222 /* "no based-on style" */
+
+
+struct RTFStyleElt
+{
+ int rtfSEClass; /* token class */
+ int rtfSEMajor; /* token major number */
+ int rtfSEMinor; /* token minor number */
+ int rtfSEParam; /* control symbol parameter */
+ char *rtfSEText; /* text of symbol */
+ RTFStyleElt *rtfNextSE; /* next element in style */
+};
+
+
+/*
+ Public RTF reader routines
+*/
+
+extern void RTFInit ();
+extern void RTFSetStream ();
+extern void RTFSetClassCallback ();
+extern void (*RTFGetClassCallback ()) ();
+extern void RTFSetDestinationCallback ();
+extern void (*RTFGetDestinationCallback ()) ();
+extern void RTFRead ();
+extern int RTFGetToken (); /* writer should rarely need this */
+extern void RTFSetToken ();
+extern void RTFSetReadHook ();
+extern void (*RTFGetReadHook ()) ();
+extern void RTFRouteToken ();
+extern void RTFSkipGroup ();
+extern void RTFExpandStyle ();
+extern int RTFCheckCM ();
+extern int RTFCheckCMM ();
+extern int RTFCheckMM ();
+extern RTFFont *RTFGetFont ();
+extern RTFColor *RTFGetColor ();
+extern RTFStyle *RTFGetStyle ();
+extern char *RTFAlloc ();
+extern char *RTFStrSave ();
+extern void RTFFree ();
diff --git a/support/RTF-1_06a1/rtf.ms b/support/RTF-1_06a1/rtf.ms
new file mode 100644
index 0000000000..2b060bb202
--- /dev/null
+++ b/support/RTF-1_06a1/rtf.ms
@@ -0,0 +1,896 @@
+.\"
+.\" tbl % | xroff -ms | lpr
+.\"
+.\" revision date - change whenever this file is edited
+.ds RD 5 April 1991
+.nr PO 1.2i \" page offset 1.2 inches
+.nr PD .7v \" inter-paragraph distance
+.\"
+.EH 'RTF Processing Tool'- % -'Distribution 1.06a1'
+.OH 'Distribution 1.06a1'- % -'RTF Processing Tool'
+.OF 'Revision date:\0\0\*(RD''Printed:\0\0\n(dy \*(MO 19\n(yr'
+.EF 'Revision date:\0\0\*(RD''Printed:\0\0\n(dy \*(MO 19\n(yr'
+.\"
+.\" subscript strings
+.ds < \s-2\v'.4m'
+.ds > \v'-.4m'\s+2
+.\"
+.\" I - italic font (taken from -ms and changed)
+.de I
+.nr PQ \\n(.f
+.if t \&\\$3\\f2\\$1\\fP\&\\$2
+.if n .if \\n(.$=1 \&\\$1
+.if n .if \\n(.$>1 \&\\$1\c
+.if n .if \\n(.$>1 \&\\$2
+..
+.de IS \" interface routine description header start
+.DS L
+.ta .8i
+.ft B
+..
+.de IE \" interface routine description header end
+.DE
+.ft R
+..
+.TL
+A Tool for RTF Processing
+.sp .5v
+Version 1.06a1
+.AU
+Paul DuBois
+dubois@primate.wisc.edu
+.AI
+Wisconsin Regional Primate Research Center
+Revision date:\0\0\*(RD
+.NH
+Introduction
+.LP
+This document describes a general purpose tool for processing RTF
+files\*-an RTF reader which may be configured in a
+well-defined manner to allow it to be used with a variety of writers
+generating different output formats.
+This provides a method for generating RTF-to-\fIXXX\fR translators.
+In theory.
+.LP
+I assume that you have some familiarity with
+RTF syntax and semantics, and that you're willing to study the source
+code of the RTF distribution described here.
+If you don't have the RTF specification, you can get it from the FTP site
+listed under ``Distribution Availability.''
+References to ``the specification'' refer to this document.
+.LP
+If you use this tool and find that you have an RTF file that won't pass
+through the sample translator
+.I rtf2null ,
+or for which
+.I rtf2null
+announces unknown symbols, please contact me so the tool can
+be improved.
+It is best if you can supply the RTF file for which this behavior is observed.
+.NH
+Theory of Operation
+.NH 2
+Translator Architecture
+.LP
+There are three components to an RTF translator (at least as conceived
+here): reader code, writer code, and setup code.
+These break down as follows.
+.IP reader\0\0
+Responsible for peeling tokens out of the input stream,
+classifying them, and causing the writer to process them.
+.IP writer\0\0
+Responsible for translating tokens from the input
+stream into the required output format.
+.IP setup\0\0
+Responsible for making sure the reader and writer are initialized, and
+for calling the reader, to cause translation to occur.
+.LP
+This architecture allows the reader to remain constant, so that different
+translaters can be built by supplying different writer and setup code.
+.LP
+In practice, to build a new translator, you supply a
+.I main()
+function and the writer code, and link in the RTF reader.
+.I main()
+includes the setup code and is responsible to see that the following are done:
+.IP \(bu
+.nr PD 0v
+Process command-line arguments
+.IP \(bu
+Configure the reader, which may involve:
+.RS
+.IP \(bu
+Reset the input stream if necessary
+.IP \(bu
+Configure other reader behavior, such as whether to
+process the font and color tables internally.
+.IP \(bu
+Install writer callbacks into the reader so it knows what functions to
+call when various kinds of tokens occur
+.RE
+.IP \(bu
+Initialize the writer
+.IP \(bu
+Call the reader to process input stream
+.IP \(bu
+.nr PD .7v
+Terminate the writer
+.LP
+The minimal translator looks something like this:
+.LP
+.DS
+# include <stdio.h>
+# include "rtf.h"
+
+int main ()
+{
+ RTFInit ();
+ RTFRead ();
+ exit (0);
+}
+.DE
+.LP
+This initializes the reader, and calls it to read
+.I stdin .
+The writer portion is null (i.e., there is no writer), so all that happens
+is that the reader tokenizes the input and discards it.
+That isn't very interesting;
+most of the sample translators are examples of more elaborate translators.
+.NH 2
+Reader Operation
+.LP
+Tokens are classified using up to three numbers: token class, and major and
+minor numbers.
+The class number can be:
+.LP
+.DS
+.ta 1.5i
+rtfUnknown unrecognized token
+rtfGroup ``{'' or ``}''
+rtfText plain text character
+rtfControl token beginning with ``\e''
+rtfEOF fake class number; indicates end of input stream
+.DE
+.LP
+There are some exceptions.
+A few tokens beginning with ``\e'' actually belong to other classes,
+a tab character is treated like ``\etab'',
+and unrecognized tokens are put in class
+.I rtfUnknown
+no matter what they look like.
+.LP
+Within a class, tokens are assigned a major number, and perhaps a
+minor number.
+For the
+.I rtfText
+class, the major number is the value of the character (0..255), and there
+is no minor number.
+For the
+.I rtfControl
+class, most tokens have both a major and minor number.
+For instance, all paragraph attribute control symbols have major number
+.I rtfParAttr
+and a minor number indicating which property, such as
+.I rtfLeftIndent
+or
+.I rtfSpaceBefore .
+A few oddball control tokens have no minor number.
+.LP
+A ``plain text'' character can be a literal character, a character specified
+in hex notation (``\e\`\fIxx\fR'') or one of the special escaped characters
+(``\e{'', ``\e}'', ``\e\e'').
+The sequence ``\e:'' is treated as a plain text colon.
+This is arguably wrong; the rationale is given later under the
+description of the
+.I RTFGetToken()
+function.
+.LP
+Ideally, there should never be any tokens in the
+.I rtfUnknown
+class, but as the RTF standard continues to develop, unknown tokens are
+inevitable.
+.LP
+To write a translator, you'll need to familiarize yourself with
+the token classification scheme by reading
+.I rtf.h .
+A skeleton translator
+.I rtfskel.c
+is included with the distribution and may be used as a basis for new
+translators.
+.LP
+Each time a token is read, several global variables are set.
+.I rtfClass ,
+.I rtfMajor ,
+and
+.I rtfMinor
+indicate the token class, and major and minor numbers.
+(The major and minor numbers may be meaningless depending on the kind
+of token.)
+Control symbols may have a parameter value, e.g., ``\emargr720''
+specifies a right margin (in units of 720 twentieths of a point).
+The parameter value is stored in
+.I rtfParam .
+The text of the token (including the parameter text) is placed in
+.I rtfTextBuf
+and its length in
+.I rtfTextLen .
+.LP
+If no parameter value is given,
+.I rtfParam
+is 0, which is indistinguishable from an explicitly specified
+parameter of ``0''.
+If you need to tell the difference, examine
+.I rtfTextBuf[rtfTextLen-1]
+to see if it's a digit or not.
+.LP
+The reader assumes a 7-bit character set.
+The specification indicates that character values \(>= 128 may be encoded with
+the ``\e'\fIxx\fR'' sequence.
+If the reader sees a character with the high bit set, it prints a message
+and exits.
+.LP
+Generally, a translator will configure the RTF reader
+to call particular writer
+functions when certain kinds of tokens are encountered in the input
+stream.
+These functions are known as
+.I "class callbacks" .
+Writer callbacks can be registered with the reader using
+.I RTFSetClassCallback()
+for each token class.
+.LP
+The reader reads each token, classifies it, and sends it to a token routing
+function
+.I RTFRouteToken() ,
+tries to find a writer callback function to process the token.
+Tokens in a given
+class are ignored if no callback is registered for the class.
+.LP
+Class callbacks make it quite easy to receive notification when
+certain types of tokens occur in the input.
+For instance, a crude RTF text extractor could be written by
+installing a callback function for the
+.I rtfText
+class.\**
+.FS
+The reasons this is a crude translator are that:
+(i) some text characters occur in contexts where the characters
+are not intended to be output, e.g., font tables, stylesheets; (ii)
+character values greater than 127 probably should be translated into the normal
+ASCII range; (iii) some control symbols like ``\etab'' represent
+output text characters.
+The sample translator
+.I rtf2text
+addresses these problems in a (slightly) more sophisticated manner.
+.FE
+Whenever the function is invoked,
+.I rtfMajor
+will contain a value in the range 0..255 representing the character value.
+.LP
+.DS
+# include <stdio.h>
+# include "rtf.h"
+
+void TextCallback ()
+{
+ putchar (rtfMajor);
+}
+
+int main ()
+{
+ RTFInit ();
+ RTFSetClassCallback (rtfText, TextCallback);
+ RTFRead ();
+ exit (0);
+}
+.DE
+.LP
+Callbacks for the
+.I rtfControl
+and
+.I rtfGroup
+classes
+typically operate by selecting on the token major number to determine
+the action to take.
+A callback for the
+.I rtfGroup
+class usually will do something like this:
+.LP
+.DS
+void BraceCallback ()
+{
+ switch (rtfMajor)
+ {
+ case rtfBeginGroup:
+ \fI...push state...\fR
+ break;
+ case rtfEndGroup:
+ \fI...pop state...\fR
+ break;
+ }
+}
+.DE
+.NH 2
+Destination Readers
+.LP
+Grouping in RTF documents occurs within braces ``{'' and ``}''.
+One kind of group is the
+.I destination .
+The token immediately following the opening brace is a destination
+control symbol.
+These indicate such things as headers, footers, footnotes, etc.
+.LP
+Three destinations which specify information for internal use (i.e.,
+information which affects
+output but isn't itself written) are the font table, color table and
+stylesheet.
+Since these three destinations occur so commonly and have a special syntax,
+the RTF reader by default gobbles them up itself when it recognizes them.
+The functions which do this are called
+.I "destination readers"
+and are probably the nearest thing in the reader to what might be
+called parsers.
+They are installed by default so that translators can be written
+without the burden of understanding the syntax or digesting the
+contents of these destinations.
+Each of them constructs a list of the entries specified in the
+destination and the reader includes functions providing access to
+these lists.
+.LP
+Translators can turn off or override these defaults with
+.I RTFSetDestinationCallback()
+if necessary.
+To override one, pass the address of a different destination reader
+function.
+To turn one off, pass NULL.
+.LP
+Destination callbacks may be called for any destination, not just
+.I rtfFontTbl ,
+.I rtfColorTbl
+and
+.I rtfStyleSheet .
+Destinations for which no callback is registered are not treated
+specially.
+.LP
+Other destinations for which there is a default
+reader are the information (``\einfo'') and picture (``\epict'')
+destinations; all they do is skip to the end of the group.
+.NH 3
+Using the Built-in Destination Readers
+.LP
+The font table, color table and stylesheet information is maintained
+internally, and the reader either acts on that information itself, or
+allows itself to be queried by the writer about it, as described
+below.
+These descriptions do not apply if the translator shuts off or
+overrides the default destination readers, of course.
+.LP
+\fBStylesheet\*-\fRThe reader acts on this itself.
+When the stylesheet destination is encountered, the style contents are
+remembered.
+Thereafter, whenever the writer receives notification that a style number
+control symbol (``\es\fInnn\fR'') has occurred, it can call
+.I RTFExpandStyle(rtfParam)
+to cause the style to be expanded.
+The reader consults contents of the stylesheet and each
+token in the style definition is routed in turn back to the writer.
+This effects a sort of macro expansion.
+.LP
+If the writer doesn't care about style expansion, it simply refrains
+from calling
+.I RTFExpandStyle() .
+.LP
+If the writer wants information about a style, it can call
+.I RTFGetStyle() .
+.LP
+\fBFont table\*-\fRFor each entry in the font table, the font number,
+type and name are maintained by the reader.
+The writer finds out that a font number has been specified in the input
+when its control class callback is invoked and
+.I rtfMajor
+\(eq
+.I rtfCharAttr
+and
+.I rtfMinor
+\(eq
+.I rtfFontNum .
+To obtain a pointer to the appropriate
+.I RTFFont
+structure, the reader function
+.I RTFGetFont(rtfParam)
+may be called.
+.LP
+\fBColor table\*-\fRFor each entry in the color table, the color number
+is maintained along with the red, green and blue values.
+The writer finds out that a color number has been specified in the input
+when its control class callback is invoked and
+.I rtfMajor
+\(eq
+.I rtfCharAttr
+and
+.I rtfMinor
+\(eq
+.I rtfColorNum .
+To obtain a pointer to the appropriate
+.I RTFColor
+structure, the reader function
+.I RTFGetColor(rtfParam)
+may be called.
+.LP
+One subtle point about the built-in destination readers:
+destinations cannot be recognized until
+.I after
+the occurrence of the ``{'' symbol that begins the destination.
+This means the writer, if it maintains a state stack, will already
+have pushed a state.
+In order to allow the writer to properly pop that state in response
+to the ``}'', these
+destination readers feed the ``}'' back into the token router after
+they pull it from the input stream.
+What the writer actually sees is a ``{'' followed immediately by a
+``}''.
+.LP
+Applications that maintain a state stack may find it necessary to do
+something similar if they supply their own destination readers.
+.NH
+Programming Interface
+.LP
+Source files using the RTF reader should #include
+.I rtf.h .
+.I reader.c
+should be compiled to produce
+.I reader.o ,
+which should be part of the final application link.
+.LP
+The best way to learn how these source files work is to study the sample
+translators, which vary in complexity from very simple (e.g.,
+.I rtf2text ,
+.I rtfwc ),
+to wretchedly messy (e.g.,
+.I rtf2troff ).
+You should be aware that one implication of the way the translators
+are built (callbacks and switch statements)
+is that it's quite easy to build them incrementally.
+You can start with a very bare-bones model, and start plugging in
+callbacks as you progress.
+Within the callbacks, your switch statements can progressively handle
+more cases.
+.LP
+An alternative approach is to start with a copy of
+.I rtfskel.c ,
+which includes a full set of class callbacks and complete switch statements
+for all tokens.
+Each case is empty; you simply add code for those cases you want to handle.
+You can also rip out the code for the cases you know you'll never care about.
+.NH 2
+Global variables
+.LP
+The global RTF reader variables are:
+.LP
+.DS
+.ta .6i 2i
+int rtfClass; token class
+int rtfMajor; token major number
+int rtfMinor; token minor number
+int rtfParam; parameter value for control symbols
+char rtfTextBuf[rtfBufSiz]; token text
+int rtfTextLen; length of token text
+.DE
+.LP
+These variables always apply to the token with which the writer should
+be concerned.
+This may be either the last token read or the current token within a
+style which is being reprocessed.
+.NH 2
+Functions
+.IS
+void RTFInit ()
+.IE
+Initialize the RTF reader.
+This is the first RTF routine that should be called.
+It performs some initialization such as computing hash values for the
+token lookup table and installation of the built-in destination readers.
+.LP
+.I RTFInit()
+may be called multiple times.
+Each invocation resets the reader's state completely, except that the input
+stream is not disturbed.
+.IS
+void RTFRead ()
+.IE
+.I RTFRead()
+calls
+.I RTFGetToken()
+to tokenize the input stream
+and
+.I RTFRouteToken()
+to process each token, until input is exhausted.
+When
+.I RTFRead()
+returns, input has been completely read and the writer can perform any
+cleanup or termination needed.
+.LP
+If you want to read multiple files per invocation of your translator,
+you should do all your setup prior to each call to
+.I RTFRead() .
+That is, you should call
+.I RTFInit() ,
+install callbacks, etc., then call
+.I RTFRead() .
+.IS
+void RTFRouteToken ()
+.IE
+This routine decides what to do with the current token and routes it
+to the correct place for processing.
+Usually this is directly to the writer via a class callback.
+The token is
+.I not
+passed to the writer (i.e., the class callback is bypassed) when it
+is a destination token for which a reader callback is installed.
+.LP
+By default, built-in readers are installed
+for font table, color table, stylesheet and information and picture
+group destinations.
+The built-in readers can be disabled
+if the writer wants to see all tokens directly.
+.IS
+int RTFGetToken ()
+.IE
+Reads one token from the input stream, classifies it, sets the global
+variables, and returns the class number.
+If the class is
+.I rtfEOF
+the end of the input stream has been reached.
+Newlines (``\en'') and carriage returns (``\er'')
+are silently discarded by
+.I RTFGetToken() ,
+as they have no meaning.
+Both are passed to the token hook if one is installed, however.
+.LP
+The sequence ``\e:'' is treated as a plain text character, with
+.I rtfClass
+set to
+.I rtfText
+and
+.I rtfMajor
+set to the colon ASCII code.
+Strictly speaking, ``\e:'' is the control word for an index
+subentry, but some versions of Microsoft Word write out plain text
+colons with a preceding backslash, while others don't.
+This unfortunate ambiguity results in an ugly dilemma.
+It seems the lesser burden to require translators to recognize
+that plain text colons should ``really'' be treated as index subentry
+indicators
+while inside of an index entry destination, than to recognize that an
+index subentry control word should ``really'' be treated as a plain
+text colon everywhere else.
+.LP
+Writers probably should not need to use
+.I RTFGetToken()
+directly unless they install their own destination readers.
+One reason you might want to call it is to implement a ``peek at next token''
+capability.
+Call
+.I RTFGetToken()
+and examine the global variables.
+Then call
+.I RTFRouteToken()
+to cause the symbol to be processed normally.
+This way you get to look at the token before it goes through the usual routing
+mechanism.
+.IS
+void RTFSetToken (class, major, minor, param, text)
+int class, major, minor, param;
+char *text;
+.IE
+It is sometimes useful to construct a fake token and run it through the
+token router to cause the effects of the token to be applied.
+.I RTFSetToken()
+allows you to do this, by setting the reader's global variables to the
+values supplied.
+If
+.I param
+is non-negative, the token text
+.I rtfTextBuf
+is constructed from
+.I text
+and
+.I param ,
+otherwise
+.I rtfTextBuf
+is just copied from
+.I text .
+.IS
+void RTFSetReadHook (f)
+void (*f) ();
+.IE
+Install a function to be called by
+.I RTFGetToken()
+after each token is read from the input stream.
+The function takes no arguments and returns no value.
+Within the function,
+information about the current token can be obtained from the global
+variables.
+This function is for token examination purposes only, and should not
+modify those variables.
+.IS
+void (*RTFGetReadHook ()) ()
+.IE
+Returns a pointer to the current read hook, or NULL if there isn't one.
+.IS
+void RTFSkipGroup ()
+.IE
+This function can be called to skip to the end of the current group (including
+any subgroups).
+It's useful for explicitly ignoring ``\e*\e\fIdest\fR'' groups, where
+.I dest
+is an unrecognized destination, or for causing groups that you don't want
+to deal with to effectively ``disappear'' from the input stream.
+.LP
+Calling this function in the middle of expanding a style may cause problems.
+However, it is typically called when you have just seen a destination symbol,
+which won't happen during a style expansion\*-I think.
+.LP
+Be careful with this function if your writer maintains a state stack,
+because you will already have pushed a state when the opening group
+brace was seen.
+After
+.I RTFSkipGroup()
+returns, the group closing brace has been read, and you'll need to pop
+a state.
+All global token variables will still be set to the closing brace, so
+you may only need to call
+.I RTFRouteToken()
+to cause the state to be unstacked.
+.IS
+void RTFExpandStyle (num)
+int num;
+.IE
+Performs style expansion of the given style number, or does nothing
+if there is no such style.
+The writer should call this when it notices that the current token
+is a style number indicator.
+.IS
+void RTFSetStream (stream)
+FILE *stream;
+.IE
+Redirects the RTF reader to the given stream.
+This should be called before any reading is done.
+The default input stream is
+.I stdin .
+An alternative to
+.I RTFSetStream()
+is to simply
+.I freopen()
+the input file on
+.I stdin
+(that's what all the sample translators do).
+.LP
+The input stream is
+.I not
+modified by
+.I RTFInit() .
+.IS
+void RTFSetClassCallback (class, callback)
+int class;
+void (*callback) ();
+.IE
+Installs a writer callback function for the given token class.
+The first argument is a class number, the second is the function to
+call when tokens from that class are encountered in the input stream.
+This will cause
+.I RTFRouteToken()
+to invoke the callback when it encounters a token in the class.
+If
+.I callback
+is NULL (which is the default for all classes),
+tokens in the class are ignored, i.e., discarded.
+.LP
+The callback should take no arguments and return no value.
+Within the callback,
+information about the current token can be obtained from the global
+variables.
+.LP
+Installing a callback for the
+.I rtfEOF
+``class'' is silly and has no effect.
+.IS
+void (*RTFGetClassCallback (class)) ()
+int class;
+.IE
+Returns a pointer to the callback function for the given token class,
+or NULL if there isn't one.
+.IS
+void RTFSetDestinationCallback (dest, callback)
+int dest;
+void (*callback) ();
+.IE
+Installs a callback function for the given destination
+.I dest "" (
+is a token minor number).
+When
+.I RTFRouteToken()
+sees a token with class
+.I rtfControl
+and major number
+.I rtfDestination ,
+it checks whether there is a callback for the destination indicated by
+the minor number.
+If so, it invokes it.
+If
+.I callback
+is NULL, the given destination is not treated specially (the control
+class callback is invoked as usual).
+By default, destination callbacks are installed for the font table, color
+table, stylesheet, and information and picture group.
+.LP
+The callback should take no arguments and return no value.
+When the functon is invoked, the current token will be the destination
+token following the destination's initial opening brace ``{''.
+(For optional destinations, the destination token follows the ``\e*''
+symbol.)
+.IS
+void (*RTFGetDestinationCallback (dest)) ()
+int dest;
+.IE
+Returns a pointer to the callback function for the given token class,
+or NULL if there isn't one.
+.IS
+RTFStyle *RTFGetStyle (num)
+int num;
+.IE
+Returns a pointer to the
+.I RTFStyle
+structure for the given style number.
+The ``Normal'' style number is 0.
+Pass \-1 to get a pointer to the first style in the list.
+Styles are not stored in any particular order.
+.LP
+Be sure to check the result; it might be NULL.
+.LP
+This function is meaningless if the default stylesheet destination
+reader is overridden.
+.IS
+RTFFont *RTFGetFont (num)
+int num;
+.IE
+Returns a pointer to the
+.I RTFFont
+structure for the given font number.
+Pass \-1 to get a pointer to the first font in the list.
+Fonts are not stored in any particular order.
+.LP
+Be sure to check the result; it might be NULL.
+In particular, you might think that passing the number specified with
+the ``\edeff'' (default font) control symbol would always yield a
+valid font structure, but that's not true.
+The default font might not be listed in the font table.
+.LP
+This function is meaningless if the default font table destination
+reader is overridden.
+.IS
+RTFColor *RTFGetColor (num)
+int num;
+.IE
+Returns a pointer to the
+.I RTFColor
+structure for the given color number.
+(I think black is 0.)
+Pass \-1 to get a pointer to the first color in the list.
+Colors are not stored in any particular order.
+If the color values in the entry are \-1, the default color should be used.
+The default color is writer-dependent.
+.LP
+Be sure to check the result; it might be NULL.
+I think this means you should use the default color.
+.LP
+This function is meaningless if the default color table destination
+reader is overridden.
+.IS
+int RTFCheckCM (class, major)
+int class, major;
+.IE
+Returns non-zero if
+.I rtfClass
+and
+.I rtfMajor
+are equal to
+.I class
+and
+.I major ,
+respectively, zero otherwise.
+.IS
+int RTFCheckCMM (class, major, minor)
+int class, major, minor;
+.IE
+Returns non-zero if
+.I rtfClass ,
+.I rtfMajor
+and
+.I rtfMinor
+are equal to
+.I class ,
+.I major
+and
+.I minor ,
+respectively, zero otherwise.
+.IS
+int RTFCheckMM (major, minor)
+int major, minor;
+.IE
+Returns non-zero if
+.I rtfMajor
+and
+.I rtfMinor
+are equal to
+.I major
+and
+.I minor ,
+respectively, zero otherwise.
+.IS
+char *RTFAlloc (size)
+int size;
+.IE
+Returns a pointer to a block of memory
+.I size
+bytes long, or NULL if insufficient memory was available.
+.IS
+char *RTFStrSave (s)
+char *s;
+.IE
+Allocates a block of memory big enough for a copy of the given string
+(including terminating null byte), copies the string into it, and returns
+a pointer to the copy.
+Returns NULL if insufficient memory was available.
+.IS
+void RTFFree (p)
+char *p;
+.IE
+Frees the block of memory pointed to by
+.I p ,
+which should have been allocated by
+.I RTFAlloc()
+or
+.I RTFStrSave() .
+It is safe to pass NULL to this routine.
+.NH
+Distribution Availability
+.LP
+This software may be redistributed without restriction and used for
+any purpose whatsoever.
+.LP
+The RTF distribution is available for anonymous
+.I ftp
+access in the
+.I ~ftp/pub/RTF
+directory on host
+.I indri.primate.wisc.edu
+(Internet address 128.104.230.11).
+Updates appear there as they become available.
+.LP
+A version of the RTF specification is available in this directory,
+as either a binhex'ed Word for Macintosh document, or in RTF format.
+It is known to have a few errors, as it's a scanned version of a paper
+copy.
+Some of these errors have been fixed, but others remain (see, for instance,
+the example table text on page 17).
+The document is not quite as up to date as the one sent out by Microsoft,
+but it is much more complete
+than the one beginning ``Specification for RTF'' that may be found on
+some other archive sites.
+.LP
+If you do not have Internet access, send a request to one of the following:
+.DS
+.ta 1.2i
+Internet: software-request@primate.wisc.edu
+UUCP: rhesus!software-request
+.DE
+Bug reports and questions should be sent to one of these addresses as
+well.
+.LP
+If you use this software as the basis for a translater not included in
+the current collection, please consider contributing it for inclusion
+in a future distribution.
+In particular, an RTF-to-LaTeX translator seems to be an item of interest.
+I don't use LaTeX myself and am unlikely to write one, but it would probably
+be fairly popular.
diff --git a/support/RTF-1_06a1/rtf2null.c b/support/RTF-1_06a1/rtf2null.c
new file mode 100644
index 0000000000..44818f92fc
--- /dev/null
+++ b/support/RTF-1_06a1/rtf2null.c
@@ -0,0 +1,55 @@
+/*
+ rtf2null - RTF-to-nothing translator
+
+ Example only: demonstrates a minimal translator. Does nothing,
+ with the single exception that unknown tokens are echoed. This
+ allows rtf2null to be used as a "find unknown tokens" filter.
+
+ 07 Feb 91 Paul DuBois dubois@primate.wisc.edu
+
+ 07 Feb 91 V1.0. Created.
+ 24 Feb 91 V1.01. Added unknown token class callback.
+*/
+
+# include <stdio.h>
+# include "rtf.h"
+
+static void Unknown ();
+
+
+int main (argc, argv)
+int argc;
+char **argv;
+{
+ RTFInit ();
+
+ --argc;
+ ++argv;
+
+ /* not clever; only allows stdin or one named file to be read */
+
+ if (argc > 0)
+ {
+ if (freopen (argv[0], "r", stdin) == NULL)
+ {
+ fprintf (stderr, "Can't open \"%s\"\n", argv[0]);
+ exit (1);
+ }
+ }
+
+ RTFSetClassCallback (rtfUnknown, Unknown);
+ RTFRead ();
+
+ exit (0);
+}
+
+
+/*
+ Echo any unknown tokens. This helps to find out where
+ reader needs to be made smarter.
+*/
+
+static void Unknown ()
+{
+ fprintf (stderr, "Unknown symbol %s\n", rtfTextBuf);
+}
diff --git a/support/RTF-1_06a1/rtf2text.c b/support/RTF-1_06a1/rtf2text.c
new file mode 100644
index 0000000000..61aedd661e
--- /dev/null
+++ b/support/RTF-1_06a1/rtf2text.c
@@ -0,0 +1,264 @@
+/*
+ rtf2text - read rtf input, write text of document (text extraction).
+
+ This installs callbacks for the ascii and control token classes.
+ The control class is necessary so that special characters such as
+ \par, \tab, \sect, etc. can be converted.
+
+ It's problematic what to do with text in headers and footers, and
+ what to do about tables.
+
+ This really is quite a stupid program, for instance, it could keep
+ track of the current leader character and dump that out when a tab
+ is encountered.
+
+ 04 Feb 91 Paul DuBois dubois@primate.wisc.edu
+
+ 04 Feb 91 V1.0. Created.
+ 27 Feb 91 V1.01. Updated for distribution 1.05.
+*/
+
+# include <stdio.h>
+# include "rtf.h"
+
+
+/*
+ structure for mapping character values >= 128 to text strings
+ for different character sets.
+*/
+
+typedef struct CharMap CharMap;
+
+struct CharMap
+{
+ int charVal;
+ char *charStr;
+};
+
+extern CharMap ansiCharMap[]; /* these are defined below */
+extern CharMap macCharMap[];
+extern CharMap pcCharMap[];
+extern CharMap pcaCharMap[];
+
+/*
+ Default is ANSI but I hope we don't see \ansi, since its char
+ map is empty...
+*/
+
+CharMap *charMap = ansiCharMap;
+
+
+static void Text ();
+static void Control ();
+static void CharSet ();
+static void Destination ();
+static void SpecialChar ();
+
+
+int main (argc, argv)
+int argc;
+char **argv;
+{
+ RTFInit ();
+
+ --argc;
+ ++argv;
+
+ /* not clever; only allows stdin or one named file to be read */
+
+ if (argc > 0)
+ {
+ if (freopen (argv[0], "r", stdin) == NULL)
+ {
+ fprintf (stderr, "Can't open \"%s\"\n", argv[0]);
+ exit (1);
+ }
+ }
+
+ /* install class callbacks and process the input stream */
+
+ RTFSetClassCallback (rtfText, Text);
+ RTFSetClassCallback (rtfControl, Control);
+ RTFRead ();
+
+ exit (0);
+}
+
+static void Text ()
+{
+ PutChar (rtfMajor);
+}
+
+
+static void Control ()
+{
+ switch (rtfMajor)
+ {
+ case rtfCharSet:
+ CharSet ();
+ break;
+ case rtfDestination:
+ Destination ();
+ break;
+ case rtfSpecialChar:
+ SpecialChar ();
+ break;
+ }
+}
+
+
+static void CharSet ()
+{
+ switch (rtfMinor)
+ {
+ case rtfAnsiCharSet:
+ charMap = ansiCharMap;
+ break;
+ case rtfMacCharSet:
+ charMap = macCharMap;
+ break;
+ case rtfPcCharSet:
+ charMap = pcCharMap;
+ break;
+ case rtfPcaCharSet:
+ charMap = pcaCharMap;
+ break;
+ }
+}
+
+
+/*
+ This function notices destinations that should be ignored
+ and skips to their ends. This keeps, for instance, picture
+ data from being considered as plain text.
+*/
+
+static void Destination ()
+{
+ switch (rtfMinor)
+ {
+ case rtfPict:
+ case rtfFNContSep:
+ case rtfFNContNotice:
+ case rtfInfo:
+ case rtfIndexRange:
+ case rtfITitle:
+ case rtfISubject:
+ case rtfIAuthor:
+ case rtfIOperator:
+ case rtfIKeywords:
+ case rtfIComment:
+ case rtfIVersion:
+ case rtfIDoccomm:
+ RTFSkipGroup ();
+ break;
+ }
+}
+
+
+static void SpecialChar ()
+{
+ switch (rtfMinor)
+ {
+ case rtfPage:
+ case rtfSect:
+ case rtfRow:
+ case rtfLine:
+ case rtfPar:
+ PutChar ('\n');
+ break;
+ case rtfCell:
+ PutChar (' '); /* make sure cells are separated */
+ break;
+ case rtfNoBrkSpace:
+ PutChar (' ');
+ break;
+ case rtfTab:
+ PutChar ('\t');
+ break;
+ case rtfNoBrkHyphen:
+ PutChar ('-');
+ break;
+ }
+}
+
+
+/*
+ Eventually this should keep track of the destination of the
+ current state and only write text when in the initial state.
+*/
+
+PutChar (c)
+int c;
+{
+CharMap *cmp;
+char *p = "X";
+
+ if (c < 128)
+ putchar (c);
+ else
+ {
+ for (cmp = charMap; cmp->charStr != NULL; cmp++)
+ {
+ if (c == cmp->charVal)
+ {
+ p = cmp->charStr;
+ break;
+ }
+ }
+ fputs (p, stdout);
+ }
+}
+
+
+CharMap ansiCharMap [] =
+{
+ 0, NULL
+};
+
+
+CharMap macCharMap [] =
+{
+ 0xa0, "+", /* dagger */
+ 0xa1, "deg.", /* degree */
+ 0xa2, "cents", /* cent */
+ 0xa5, "o", /* bullet */
+ 0xa7, "B", /* German B? */
+ 0xa8, "reg.", /* registered */
+ 0xa9, "(c)", /* copyright */
+ 0xaa, "(TM)", /* trademark */
+ 0xab, "'", /* acute accent */
+ 0xad, "!=", /* not equal */
+ 0xae, "AE", /* joined A-E */
+ 0xb1, "+/-", /* plus or minus */
+ 0xb2, "<=", /* less than or equal */
+ 0xb3, ">=", /* greater than or equal */
+ 0xb5, "u", /* micro */
+ 0xb6, "d", /* delta */
+ 0xbe, "ae", /* joined a-e */
+ 0xc5, "~", /* approximately */
+ 0xc7, "<<", /* alternate quote */
+ 0xc8, ">>", /* alternate end-quote*/
+ 0xc9, "...", /* ellipsis */
+ 0xca, " ", /* unbreakable space */
+ 0xd0, "-", /* short dash */
+ 0xd1, "--", /* long dash */
+ 0xd2, "\"", /* left curly double quote */
+ 0xd3, "\"", /* right curly double quote */
+ 0xd4, "`", /* left curly single quote */
+ 0xd5, "'", /* right curly single quote */
+ 0xd6, "/", /* divide */
+ 0, NULL
+};
+
+
+CharMap pcCharMap [] =
+{
+ 0, NULL
+};
+
+
+CharMap pcaCharMap [] =
+{
+ 0, NULL
+};
diff --git a/support/RTF-1_06a1/rtf2troff.c b/support/RTF-1_06a1/rtf2troff.c
new file mode 100644
index 0000000000..ee3edfa78a
--- /dev/null
+++ b/support/RTF-1_06a1/rtf2troff.c
@@ -0,0 +1,1140 @@
+/*
+ Trap positions should be flushed *before* the .ev, unfortunately,
+ they might not be changed until after the .ev is already out! Agh.
+
+ Allow these options:
+ -h disable headers/footers
+ +h enable headers/footers (default)
+
+ Bottom position should be written in terms of page length, which
+ should be stored in a register.
+
+ Need -me, -mm, -ms specific stuff. Is there a way of detecting
+ them from within troff?
+
+ Allow header/footer suppression? (for cases where the code written
+ is just completely wrong.)
+
+ Need to handle \titlepg.
+
+ rtf2troff - read rtf input, write troff output
+
+ Syntax: rtf2troff options file
+
+ Options:
+ -e echo token information
+ -me write -me specific output
+ -mm write -mm specific output
+ -ms write -ms specific output
+ -s disable strikethrough
+ +s enable strikethrough (default)
+ -t troff specify troff version
+ -u disable underlining
+ +u enable underlining (default)
+
+ This translator was written to be used with the Primate Center's
+ troff-variant (xroff). xroff dependencies are bracketed within
+ "if (xroff) { ... }" constructions.
+
+ 29 Jan 91 Paul DuBois dubois@primate.wisc.edu
+
+ 29 Jan 91 V1.0. Created.
+ 31 Jan 91 Made to work. :-)
+ 27 Feb 91 V1.01. Updated for distribution 1.05.
+ 28 Feb 91 V1.02. Began updating for distribution 1.06.
+
+ --
+
+ troff puts paragraph markers at the beginning of paragraphs,
+ RTF puts 'em at end; the difference is a pain.
+
+ "Small caps" is done by \s-1 ... \s+1 and capitalizing everything
+ in between.
+
+ Good underlining is hard to do in troff; each character is
+ underlined individually, which generates an abysmal amount of
+ output. Strikethrough output is even worse.
+
+ --
+
+ Deficiencies are myriad. They include, but are by no means
+ limited to:
+
+ No formula support.
+
+ Poor table support. Tabs within cells are botched. Tables are
+ always centered. Tables often come out looking pretty ugly.
+
+ space before, after and between don't appear to always work.
+
+ troff has no decimal tabs; they are treated as (ugh) right justified
+ tabs.
+
+ Vertical lines ("bar tabs") are unsupported.
+
+ Poor font support (only R, I, B, not even I+B). Font table ignored.
+
+ Line numbering ignored, for no good reason.
+
+ Only normal and continuous underlining are supported.
+
+ No outline or shadow, since troff can't do that.
+
+ All-caps, small-caps doesn't work for non-ASCII characters (> 127)
+ or special (mapped) characters. (Of course, why should it?)
+
+ Default space between lines should be "auto" - but how to do that?
+
+ Mixing of leader characters within a paragraph is not supported.
+
+ Is nTabs = 0 handled incorrectly?
+
+ Mechanism for handling invisible text is inconsistent.
+ It's hard to do correctly...particularly as not everything
+ is ignored when \v is in effect, and I'm not sure exactly
+ what governs whether something is ignored or not.
+*/
+
+# include <stdio.h>
+# include <sys/types.h>
+# include <ctype.h>
+# include "rtf.h"
+# include "rtf2troff.h"
+
+
+int tvers = TROFF;
+int mvers = noMacros;
+
+
+State *is; /* current internal state */
+DocState *ids; /* internal document state */
+SectState *iss; /* internal section state */
+ParState *ips; /* internal paragraph state */
+CharState *ics; /* internal character state */
+
+State *ws; /* written state */
+DocState *wds; /* written document state */
+SectState *wss; /* written section state */
+ParState *wps; /* written paragraph state */
+CharState *wcs; /* written character state */
+
+
+/*
+ Whether internal state has been changed since written state
+ was last synchronized to it. Initially true so that internal
+ state will be flushed when first content character is written.
+*/
+
+int docStateChanged = 1; /* document properties have changed */
+int sectStateChanged = 1; /* section properties have changed */
+int parStateChanged = 1; /* paragraph properties have changed */
+int charStateChanged = 1; /* character properties have changed */
+
+
+/*
+ Indirection level for escape (\) processing. Incremented
+ during macro/diversion collection.
+*/
+
+int indirectionLevel = 0;
+
+
+static int haveTables = 0; /* non-zero if any seen */
+static TblState tableState;
+TblState *its = &tableState;
+int inTable = 0; /* whether in table cell or not */
+
+
+/*
+ Default output stream
+*/
+
+FILE *f = stdout;
+
+static int allowUnderline = 1;
+static int allowStrikeThru = 1;
+
+static char *usage = "Usage: rtf2troff [-e] [-me|-mm|-ms] [-s|+s] [-t troff] [-u|+u] file";
+
+
+static void TokenEcho ();
+
+static void Unknown ();
+static void Text ();
+static void Group ();
+static void Control ();
+static void BeginDestination ();
+static void EndDestination ();
+static void Destination ();
+static void CharSet ();
+static void SpecialChar ();
+static void DocAttr ();
+static void SectAttr ();
+static void ParAttr ();
+static void CharAttr ();
+
+
+static void SetNextTabType ();
+static void SetNextTabPos ();
+static void SetTabChar ();
+
+
+int main (argc, argv)
+int argc;
+char **argv;
+{
+char *troff = "troff";
+char *macros = NULL;
+
+ RTFInit ();
+
+ /*
+ Process arguments. The -t and -me|-mm|-ms arguments
+ must be remembered and applied *in that order* after
+ argument processing, or char maps may not be selected
+ properly.
+ */
+ --argc;
+ ++argv;
+ while (argc > 1 && **argv == '-')
+ {
+ if (strcmp ("-e", *argv) == 0)
+ RTFSetReadHook (TokenEcho);
+ else if (strcmp ("-s", *argv) == 0)
+ allowStrikeThru = 0;
+ else if (strcmp ("+s", *argv) == 0)
+ allowStrikeThru = 1;
+ else if (strcmp ("-u", *argv) == 0)
+ allowUnderline = 0;
+ else if (strcmp ("+u", *argv) == 0)
+ allowUnderline = 1;
+ else if (strcmp ("-t", *argv) == 0)
+ {
+ if (argc < 2)
+ {
+ fprintf (stderr, "%s\n", usage);
+ exit (1);
+ }
+ --argc;
+ ++argv;
+ troff = *argv;
+ if (strcmp (troff, "troff") == 0)
+ tvers = TROFF;
+ else if (strcmp (troff, "xroff") == 0)
+ tvers = XROFF;
+ else if (strcmp (troff, "pstroff") == 0)
+ tvers = PSTROFF;
+ }
+ else if (strcmp ("-me", *argv) == 0)
+ {
+ macros = *argv;
+ mvers = meMacros;
+ }
+ else if (strcmp ("-mm", *argv) == 0)
+ {
+ macros = *argv;
+ mvers = mmMacros;
+ }
+ else if (strcmp ("-ms", *argv) == 0)
+ {
+ macros = *argv;
+ mvers = msMacros;
+ }
+ else
+ {
+ fprintf (stderr, "Unknown option: %s\n", *argv);
+ fprintf (stderr, "%s\n", usage);
+ exit (1);
+ }
+ --argc;
+ ++argv;
+ }
+ SelectFormatterMaps (troff);
+ if (macros != NULL)
+ SelectMacPackMaps (macros);
+
+ /* not clever; only allows stdin or one named file to be read */
+
+ if (argc > 0)
+ {
+ if (freopen (argv[0], "r", stdin) == NULL)
+ {
+ fprintf (stderr, "Can't open \"%s\"\n", argv[0]);
+ exit (1);
+ }
+ }
+
+
+/*
+ Install writer callbacks into reader and initialize state
+ (sets up pointers into internal state 0, and equates initial
+ written state to internal state).
+*/
+
+ RTFSetClassCallback (rtfText, Text);
+ RTFSetClassCallback (rtfGroup, Group);
+ RTFSetClassCallback (rtfControl, Control);
+ RTFSetClassCallback (rtfUnknown, Unknown);
+
+ InitState ();
+
+ /*
+ If macro package needs to be told special characters
+ might be used, do so.
+ */
+ if (mvers == meMacros)
+ fprintf (f, ".sc\n");
+ else if (mvers == msMacros)
+ fprintf (f, ".AM\n");
+
+ /*
+ Process the input stream. Make sure the first intoken is
+ a "{" so a state push will occur before anything else
+ (need to preserve state 0 intact for section, paragraph,
+ character default restoration).
+ */
+
+ (void) RTFGetToken ();
+ if (!RTFCheckCM (rtfGroup, rtfBeginGroup))
+ {
+ fprintf (stderr, "malformed rtf file - ");
+ fprintf (stderr, "does not begin with \"{\"\n");
+ exit (1);
+ }
+ RTFRouteToken (); /* send "{" through router */
+ RTFRead (); /* read everything else */
+ Flush ();
+
+ /* some diagnostic stuff */
+ CheckFinalState ();
+
+ if (haveTables)
+ fprintf (stderr, "Output contains tables (run through tbl)\n");
+
+ exit (0);
+}
+
+
+/*
+ Token echo function to implement -e
+*/
+
+static void TokenEcho ()
+{
+ fprintf (f, "%d\t%d\t%d\t%d\t\"%s\"\n",
+ rtfClass, rtfMajor, rtfMinor, rtfParam, rtfTextBuf);
+}
+
+
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ Token class handlers
+*/
+
+/*
+ Echo any unknown tokens. This helps know where translator
+ needs to be extended.
+*/
+
+static void Unknown ()
+{
+ fprintf (stderr, "Unknown symbol %s\n", rtfTextBuf);
+}
+
+
+/*
+ Group operator. Push or pop internal state level.
+
+ Before a pop, check whether the destination needs any shutdown.
+*/
+
+static void Group ()
+{
+ switch (rtfMajor)
+ {
+ case rtfBeginGroup: /* push */
+ PushIState ();
+ break;
+ case rtfEndGroup: /* pop */
+ /* do end-of-destination procecssing, then pop state */
+ if (is->destination != rtfNoDestination)
+ EndDestination ();
+ PopIState ();
+ break;
+ }
+}
+
+
+/*
+ Have a text char, write it out. Perform special char mapping
+ for chars > 127, do escapes for backslashes.
+
+ For normal characters, perform to-upper processing.
+*/
+
+static void Text ()
+{
+char buf[2], *p;
+
+ if (rtfMajor > 127) /* non-ASCII, map to troff equiv. */
+ p = CharMapping (rtfMajor);
+ else if (rtfMajor == '\\') /* escape; escape it */
+ p = "\\e";
+ else /* regular unmapped, unescaped char */
+ {
+ if (ics->charStyle & (styleAllCaps | styleSmallCaps))
+ {
+ /*
+ OK to use islower()/toupper() because char
+ is known to be <= 127
+ */
+ if (islower (rtfMajor))
+ rtfMajor = toupper (rtfMajor);
+ }
+ buf[0] = rtfMajor;
+ buf[1] = '\0';
+ p = buf;
+ }
+ PutString (p);
+}
+
+/*
+ The char sets, special chars and destinations do not involve
+ a state change; most other control things do.
+*/
+
+static void Control ()
+{
+ switch (rtfMajor)
+ {
+ case rtfCharSet:
+ CharSet ();
+ break;
+ case rtfSpecialChar:
+ SpecialChar ();
+ break;
+ case rtfDestination:
+ BeginDestination ();
+ break;
+ case rtfDocAttr:
+ DocAttr ();
+ break;
+ case rtfSectAttr:
+ SectAttr ();
+ break;
+ case rtfParAttr:
+ ParAttr ();
+ break;
+ case rtfCharAttr:
+ CharAttr ();
+ break;
+ case rtfTblAttr:
+ TblAttr ();
+ break;
+ }
+}
+
+
+static void CharSet ()
+{
+ SelectCharSetMaps (rtfMinor);
+}
+
+/*
+ The hyphen and dash control things are treated as though they
+ were rtfText here.
+
+ An extra level of indirection is added to the page number register.
+*/
+
+static void SpecialChar ()
+{
+char buf[rtfBufSiz];
+
+ switch (rtfMinor)
+ {
+ case rtfCurHeadPage:
+ PutString ("\\\\n%"); /* reference page number register */
+ break;
+ case rtfCurHeadDate:
+ /* unimplemented */
+ break;
+ case rtfCurHeadTime:
+ /* unimplemented */
+ break;
+ case rtfNoBrkSpace:
+ PutString ("\\ ");
+ break;
+ case rtfNoReqHyphen:
+ PutString ("\\%");
+ break;
+ case rtfNoBrkHyphen:
+ PutString ("\\-");
+ break;
+ case rtfSect:
+ Sect ();
+ break;
+ case rtfRow: /* end of cell, and of row/table */
+ EndCell ();
+ EndTbl ();
+ break;
+ case rtfLine:
+ Par ();
+ break;
+ case rtfPar:
+ Par ();
+ break;
+ case rtfCell:
+ EndCell (); /* end current cell */
+ BeginCell (); /* begin next cell */
+ break;
+ case rtfTab:
+ PutString ("\t");
+ break;
+ case rtfPage:
+ Par ();
+ fprintf (f, ".bp\n");
+ break;
+ }
+}
+
+
+/*
+ Begin/End destination don't try to do anything except dump
+ out comments delimiting the destination. Something "real"
+ should be done, but at least the comment is better than nothing.
+
+ The switch explicitly lists those destinations for which something
+ intelligent should be done. (But nothing is, yet.) Everything
+ else falls under the default case and is simply skipped anonymously.
+
+ When a destination is skipped, the "}" is fed back into the router
+ so the group state gets popped by Group().
+*/
+
+static void BeginDestination ()
+{
+ Destination (1);
+}
+
+
+static void EndDestination ()
+{
+ Destination (0);
+}
+
+
+static void Destination (startDest)
+int startDest;
+{
+char *dp = NULL; /* destination name */
+char *mp = NULL; /* macro name */
+char *rp = NULL; /* register name */
+char *sp = NULL; /* skipped destination name */
+int reset = 0; /* need reset to defaults? */
+
+ /* if beginning destination, set dest type */
+ if (startDest)
+ is->destination = rtfMinor;
+ /* switch on destination type */
+ switch (is->destination)
+ {
+ case rtfFootnote:
+ /*
+ Don't skip, but don't start diversion: effect is to
+ leave footnote text in main document body. Incorrect,
+ but better than losing it. Eventually, footnotes
+ should be caught in diversions.
+ */
+ dp = "footnote";
+ break;
+ case rtfHeader:
+ dp = "header";
+ mp = mHeaderAll;
+ rp = rHeaderAll;
+ ++reset;
+ break;
+ case rtfHeaderLeft:
+ dp = "left header";
+ mp = mHeaderLeft;
+ rp = rHeaderLeft;
+ ++reset;
+ break;
+ case rtfHeaderRight:
+ dp = "right header";
+ mp = mHeaderRight;
+ rp = rHeaderRight;
+ ++reset;
+ break;
+ case rtfHeaderFirst:
+ dp = "first page header";
+ mp = mHeaderFirst;
+ rp = rHeaderFirst;
+ ++reset;
+ break;
+ case rtfFooter:
+ dp = "footer";
+ mp = mFooterAll;
+ rp = rFooterAll;
+ ++reset;
+ break;
+ case rtfFooterLeft:
+ dp = "left footer";
+ mp = mFooterLeft;
+ rp = rFooterLeft;
+ ++reset;
+ break;
+ case rtfFooterRight:
+ dp = "right footer";
+ mp = mFooterRight;
+ rp = rFooterRight;
+ ++reset;
+ break;
+ case rtfFooterFirst:
+ dp = "first page footer";
+ mp = mFooterFirst;
+ rp = rFooterFirst;
+ ++reset;
+ break;
+ case rtfFNSep:
+ sp = "footnote separator";
+ break;
+ case rtfFNContSep:
+ sp = "continued footnote separator";
+ break;
+ case rtfFNContNotice:
+ sp = "continued footnote notice";
+ break;
+ case rtfField: /* don't ignore, but don't capture */
+ dp = "field";
+ break;
+ case rtfFieldInst: /* ignore */
+ sp = "field instruction";
+ break;
+ case rtfFieldResult: /* don't ignore, but don't capture */
+ dp = "field result";
+ break;
+ default:
+ sp = rtfTextBuf;
+ break;
+ }
+
+ if (dp != NULL && startDest)
+ Comment ("begin %s", dp);
+ if (mp != NULL) /* begin a capture macro */
+ {
+ Flush ();
+ if (startDest)
+ {
+ FlushInitialState (); /* make sure this is out */
+ FlushSectState (); /* flush trap positions */
+ if (rp != NULL) /* set a register */
+ fprintf (f, ".nr %s 1\n", rp);
+ BeginDiversion (mp);
+ if (reset)
+ {
+ /* reset paragraph, char defaults */
+ /* (fake a \pard and \plain) */
+ RTFSetToken (rtfControl, rtfParAttr,
+ rtfParDef, -1, "\\pard");
+ RTFRouteToken ();
+ RTFSetToken (rtfControl, rtfCharAttr,
+ rtfPlain, -1, "\\plain");
+ RTFRouteToken ();
+ }
+ }
+ else
+ {
+ EndDiversion ();
+ }
+ }
+ if (sp != NULL) /* skip a group */
+ {
+ if (startDest)
+ {
+ Comment ("SKIPPING %s group", sp);
+ RTFSkipGroup ();
+ RTFRouteToken (); /* feed "}" back into router */
+ }
+ else
+ Comment ("end skipped group");
+ }
+ if (dp != NULL && startDest == 0)
+ Comment ("end %s", dp);
+}
+
+
+static void DocAttr ()
+{
+double inch = (double) rtfParam / (double) rtfTpi;
+
+ switch (rtfMinor)
+ {
+ case rtfPaperWidth:
+ ids->pageWidth = inch;
+ break;
+ case rtfPaperHeight:
+ ids->pageHeight = inch;
+ break;
+ case rtfLeftMargin:
+ ids->leftMargin = inch;
+ break;
+ case rtfRightMargin:
+ ids->rightMargin = inch;
+ break;
+ case rtfTopMargin:
+ ids->topMargin = inch;
+ /* pre-emptive strike */
+ if (iss->headerPos >= ids->topMargin)
+ iss->headerPos = ids->topMargin / 2;
+ break;
+ case rtfBottomMargin:
+ ids->bottomMargin = inch;
+ if (iss->footerPos >= ids->bottomMargin)
+ iss->footerPos = ids->bottomMargin / 2;
+ break;
+ case rtfDefTab:
+ ids->tabWidth = inch;
+ break;
+ case rtfLandscape:
+ ids->landscape = 1;
+ break;
+ }
+ ++docStateChanged;
+}
+
+
+static void SectAttr ()
+{
+double inch = (double) rtfParam / (double) rtfTpi;
+
+ switch (rtfMinor)
+ {
+ case rtfSectDef:
+ RestoreSectDefaults ();
+ break;
+ case rtfNoBreak:
+ case rtfColBreak:
+ case rtfPageBreak:
+ case rtfEvenBreak:
+ case rtfOddBreak:
+ iss->breakType = rtfMinor;
+ break;
+ case rtfPageStarts:
+ iss->pageStart = rtfParam;
+ break;
+ case rtfPageCont:
+ iss->pageRestart = 0;
+ break;
+ case rtfPageRestart:
+ iss->pageRestart = 1;
+ break;
+ case rtfPageDecimal:
+ Flush ();
+ fprintf (f, ".af %% 1\n");
+ break;
+ case rtfPageURoman:
+ Flush ();
+ fprintf (f, ".af %% I\n");
+ break;
+ case rtfPageLRoman:
+ Flush ();
+ fprintf (f, ".af %% i\n");
+ break;
+ case rtfPageULetter:
+ Flush ();
+ fprintf (f, ".af %% A\n");
+ break;
+ case rtfPageLLetter:
+ Flush ();
+ fprintf (f, ".af %% a\n");
+ break;
+ case rtfPageNumLeft:
+ break;
+ case rtfPageNumTop:
+ break;
+ case rtfHeaderY:
+ iss->headerPos = inch;
+ if (iss->headerPos >= ids->topMargin)
+ iss->headerPos = ids->topMargin / 2;
+ break;
+ case rtfFooterY:
+ iss->footerPos = inch;
+ if (iss->footerPos >= ids->bottomMargin)
+ iss->footerPos = ids->bottomMargin / 2;
+ break;
+ case rtfLineModulus:
+ break;
+ case rtfLineDist:
+ break;
+ case rtfLineStarts:
+ break;
+ case rtfLineRestart:
+ break;
+ case rtfLineRestartPg:
+ break;
+ case rtfLineCont:
+ break;
+ case rtfTopVAlign:
+ break;
+ case rtfBottomVAlign:
+ break;
+ case rtfCenterVAlign:
+ break;
+ case rtfJustVAlign:
+ break;
+ case rtfColumns:
+ break;
+ case rtfColumnSpace:
+ break;
+ case rtfColumnLine:
+ break;
+ case rtfENoteHere:
+ break;
+ case rtfTitleSpecial:
+ iss->titleSpecial = 1;
+ break;
+ }
+ ++sectStateChanged;
+}
+
+
+/*
+ Paragraph defaults are restored by using the state 0 values,
+ they applying the "Normal" style (style 0).
+
+ For the rtfStyleNum, the tab flag is reset before expanding the
+ style so any inherited tabs will be overridden by tabs in the
+ style, and reset after expansion so any tabs in the paragraph
+ itself will override inherited or style tabs.
+
+ The "unimplemented" cases below are those which are currently
+ ignored, but for which something might be done someday, i.e.,
+ they're reminders.
+*/
+
+static void ParAttr ()
+{
+double inch = (double) rtfParam / (double) rtfTpi;
+
+ switch (rtfMinor)
+ {
+ case rtfParDef:
+ RestoreParDefaults ();
+ break;
+ case rtfStyleNum:
+ ips->tabFlag = 0;
+ RTFExpandStyle (rtfParam);
+ ips->tabFlag = 0;
+ break;
+ case rtfQuadLeft:
+ case rtfQuadRight:
+ case rtfQuadJust:
+ case rtfQuadCenter:
+ ips->justification = rtfMinor;
+ break;
+ case rtfFirstIndent:
+ ips->firstIndent = inch;
+ break;
+ case rtfLeftIndent:
+ ips->leftIndent = inch;
+ break;
+ case rtfRightIndent:
+ ips->rightIndent = inch;
+ break;
+ case rtfSpaceBefore:
+ ips->spaceBefore = inch;
+ break;
+ case rtfSpaceAfter:
+ ips->spaceAfter = inch;
+ break;
+ case rtfSpaceBetween:
+ ips->spaceBetween = inch;
+ break;
+ case rtfInTable:
+ haveTables = 1;
+ /*
+ If first cell of row, set temp indent to left edge
+ of table. (Actually, this is done incorrectly; tables
+ are always centered.)
+ Subsequent cells are begun when \cell is seen.
+ */
+ if (its->tableHeader == 0) /* first cell; need */
+ { /* table prolog */
+ BeginTbl ();
+ BeginCell ();
+ }
+ break;
+ case rtfNoLineNum:
+ /* unimplemented */
+ break;
+ case rtfTabPos:
+ SetNextTabPos (inch);
+ break;
+ case rtfTabRight:
+ case rtfTabCenter:
+ case rtfTabDecimal:
+ SetNextTabType (rtfMinor);
+ break;
+ case rtfTabBar:
+ /* unimplemented */
+ break;
+ case rtfBorderTop:
+ ips->borderFlags |= borderTop;
+ break;
+ case rtfBorderBottom:
+ ips->borderFlags |= borderBottom;
+ break;
+ case rtfBorderLeft:
+ /* unimplemented */
+ break;
+ case rtfBorderRight:
+ /* unimplemented */
+ break;
+ case rtfBorderBar:
+ /* unimplemented */
+ break;
+ case rtfBorderBox:
+ /* unimplemented */
+ break;
+ case rtfBorderBetween:
+ /* unimplemented */
+ break;
+ case rtfBorderSingle:
+ case rtfBorderThick:
+ case rtfBorderShadow:
+ case rtfBorderDouble:
+ case rtfBorderDot:
+ case rtfBorderHair:
+ ips->borderType = rtfMinor;
+ break;
+ case rtfBorderSpace:
+ /* unimplemented */
+ break;
+ case rtfLeaderDot:
+ case rtfLeaderHyphen:
+ case rtfLeaderUnder:
+ case rtfLeaderThick:
+ SetTabChar (rtfMinor);
+ break;
+ }
+ ++parStateChanged;
+}
+
+
+/*
+ Several of the attributes can be turned off with param value
+ of zero (e.g., \b vs. \b0), but since the value of rtfParam
+ is 0 if no param is given, test the text of the token directly.
+ to find out if there's a zero at the end of it.
+
+ \plain is like \pard but for characters, i.e, it restores all
+ character defaults.
+*/
+
+static void CharAttr ()
+{
+int turnOn = (rtfTextBuf[rtfTextLen-1] != '0');
+
+ switch (rtfMinor)
+ {
+ case rtfPlain:
+ RestoreCharDefaults ();
+ break;
+ case rtfBold:
+ if (turnOn)
+ ics->charStyle |= styleBold;
+ else
+ ics->charStyle &= ~styleBold;
+ break;
+ case rtfItalic:
+ if (turnOn)
+ ics->charStyle |= styleItalic;
+ else
+ ics->charStyle &= ~styleItalic;
+ break;
+ case rtfStrikeThru:
+ if (allowStrikeThru)
+ {
+ if (turnOn)
+ ics->charStyle |= styleStrikeThru;
+ else
+ ics->charStyle &= ~styleStrikeThru;
+ }
+ break;
+ case rtfOutline:
+ if (turnOn)
+ ics->charStyle |= styleOutline;
+ else
+ ics->charStyle &= ~styleOutline;
+ break;
+ case rtfShadow:
+ if (turnOn)
+ ics->charStyle |= styleShadow;
+ else
+ ics->charStyle &= ~styleShadow;
+ break;
+ case rtfSmallCaps:
+ if (turnOn)
+ ics->charStyle |= styleSmallCaps;
+ else
+ ics->charStyle &= ~styleSmallCaps;
+ break;
+ case rtfAllCaps:
+ if (turnOn)
+ ics->charStyle |= styleAllCaps;
+ else
+ ics->charStyle &= ~styleAllCaps;
+ break;
+ case rtfInvisible:
+ if (turnOn)
+ ics->charStyle |= styleInvisible;
+ else
+ ics->charStyle &= ~styleInvisible;
+ break;
+ case rtfFontNum:
+ /* unimplemented */
+ break;
+ case rtfFontSize:
+ /* sizes are in half-points, convert to whole points */
+ ics->fontSize = (int) (rtfParam / 2);
+ if (ics->fontSize <= 0)
+ ++ics->fontSize; /* don't play with fire */
+ break;
+ case rtfExpand:
+ /* unimplemented */
+ break;
+ case rtfUnderline:
+ if (allowUnderline)
+ {
+ if (turnOn)
+ ics->charStyle |= styleUnderline;
+ else
+ ics->charStyle &= ~styleUnderline;
+ }
+ break;
+ case rtfWUnderline:
+ if (allowUnderline)
+ {
+ if (turnOn)
+ ics->charStyle |= styleWUnderline;
+ else
+ ics->charStyle &= ~styleWUnderline;
+ }
+ break;
+ case rtfDUnderline:
+ /* unimplemented */
+ break;
+ case rtfDbUnderline:
+ /* unimplemented */
+ break;
+ case rtfNoUnderline:
+ ics->charStyle &= ~styleUnderline;
+ ics->charStyle &= ~styleWUnderline;
+ break;
+ case rtfSuperScript:
+ /* superscripts are in half-points, convert to points */
+ ics->superScript = rtfParam / 2;
+ break;
+ case rtfSubScript:
+ /* subscripts are in half-points, convert to points */
+ ics->subScript = rtfParam / 2;
+ break;
+ case rtfRevised:
+ /* unimplemented */
+ break;
+ case rtfForeColor:
+ /* unimplemented */
+ break;
+ case rtfBackColor:
+ /* unimplemented */
+ break;
+ }
+ ++charStateChanged;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ Tab handling routines
+*/
+
+void InitTabSet ()
+{
+int i;
+
+ ips->nTabs = 0;
+ /*
+ Set all tabs to be left-justified; that will then be used if
+ no other tab type is specified. This is done because the
+ position is specified *after* the type.
+ */
+ for (i = 0; i < maxTab; i++)
+ ips->tabType[i] = rtfTabLeft;
+}
+
+
+static void SetNextTabPos (pos)
+double pos;
+{
+ if (ips->tabFlag != 0 && ips->nTabs >= maxTab)
+ fprintf (stderr, "maximum tabstop count (%d) exceeded\n",
+ maxTab);
+ else
+ {
+ /* if no tab info has been set for this state, reinit them */
+ if (ips->tabFlag == 0)
+ {
+ InitTabSet ();
+ ips->tabFlag = 1;
+ }
+ ips->tab[ips->nTabs++] = pos;
+ }
+}
+
+
+/*
+ Tab types are specified *before* the position to which they apply
+ is given, so set the next available slot in anticipation of the
+ position's being specified next.
+*/
+
+static void SetNextTabType (type)
+int type;
+{
+ if (ips->tabFlag != 0 && ips->nTabs >= maxTab)
+ fprintf (stderr, "maximum tabstop count (%d) exceeded\n",
+ maxTab);
+ else
+ {
+ /* if no tab info has been set for this state, reinit them */
+ if (ips->tabFlag == 0)
+ {
+ InitTabSet ();
+ ips->tabFlag = 1;
+ }
+ ips->tabType[ips->nTabs] = type;
+ }
+}
+
+
+static void SetTabChar (leader)
+int leader;
+{
+ if (ips->tabFlag != 0 && ips->nTabs >= maxTab)
+ fprintf (stderr, "maximum tabstop count (%d) exceeded\n",
+ maxTab);
+ else
+ {
+ /* if no tab info has been set for this state, reinit them */
+ if (ips->tabFlag == 0)
+ {
+ InitTabSet ();
+ ips->tabFlag = 1;
+ }
+ ips->tabChar = rtfMinor;
+ }
+}
diff --git a/support/RTF-1_06a1/rtf2troff.h b/support/RTF-1_06a1/rtf2troff.h
new file mode 100644
index 0000000000..7ed6b1e1bf
--- /dev/null
+++ b/support/RTF-1_06a1/rtf2troff.h
@@ -0,0 +1,289 @@
+/*
+ rtf2troff.h - rtf2troff defines, structures, externs
+*/
+
+/* troff versions understood */
+
+# define TROFF 0 /* generic troff */
+# define XROFF 1 /* Image Network xroff */
+# define PSTROFF 2 /* ditroff + public domain tpscript backend */
+
+/* macro packages understood */
+
+# define noMacros 0
+# define meMacros 1
+# define mmMacros 2
+# define msMacros 3
+
+
+/*
+ macro/register names
+*/
+
+# define mHeader "He"
+# define mHeaderAll "Ha"
+# define mHeaderFirst "Hf"
+# define mHeaderLeft "Hl"
+# define mHeaderRight "Hr"
+# define mFooter "Fo"
+# define mFooterAll "Fa"
+# define mFooterFirst "Ff"
+# define mFooterLeft "Fl"
+# define mFooterRight "Fr"
+
+/* normally Hp > Tm > Bm > Fp */
+
+# define rTitlePageSpecial "Tp"
+# define rTopMargin "Tm"
+# define rHeaderPos "Hp"
+# define rBottomMargin "Bm" /* from *top* of page! */
+# define rFooterPos "Fp" /* from *top* of page! */
+# define rHeaderAll "Ha"
+# define rHeaderFirst "Hf"
+# define rHeaderLeft "Hl"
+# define rHeaderRight "Hr"
+# define rFooterAll "Fa"
+# define rFooterFirst "Ff"
+# define rFooterLeft "Fl"
+# define rFooterRight "Fr"
+
+
+
+/*
+ rtfTabLeft is used to indicate the default tab type (left tab).
+ RTF assumes that if some other type is not specified, a tab is
+ a left tab and never indicates that explicitly. It's given a
+ number here so the writer can refer to it by a constant known
+ to be different from the other tab types. (All "real" token
+ numbers are non-negative.)
+
+ rtfLeaderMotion is used to indicate default tab char (motion only),
+ which likewise is undefined in RTF.
+
+ rtfNoDestination is used to indicate that a state has had no
+ destination specified yet.
+
+ rtfNoBorderType indicates that a paragraph has no borders.
+*/
+
+# define rtfTabLeft (-1)
+# define rtfLeaderMotion (-1)
+# define rtfNoDestination (-1)
+# define rtfNoBorderType (-1)
+
+
+# define styleBold 0x0001
+# define styleItalic 0x0002
+# define styleStrikeThru 0x0004
+# define styleOutline 0x0008
+# define styleShadow 0x0010
+# define styleSmallCaps 0x0020
+# define styleAllCaps 0x0040
+# define styleInvisible 0x0080
+# define styleUnderline 0x0100
+# define styleWUnderline 0x0200
+
+# define StyleFontBits(s) (s & (styleBold | styleItalic))
+
+/*
+ Values for operations that map border positions onto bits
+ in flag word.
+*/
+
+# define borderTop 0x0001
+# define borderBottom 0x0002
+# define borderLeft 0x0004
+# define borderRight 0x0008
+
+/*
+ Values for operations that map border positions to array indices.
+ Must be zero-based and sequential.
+*/
+
+# define topIndex 0
+# define leftIndex 1
+# define bottomIndex 2
+# define rightIndex 3
+
+
+# define lineBreakLen 60 /* break lines after 60 columns */
+
+
+# define maxIStack 10 /* internal state stack depth */
+# define maxWStack 3 /* written state stack depth */
+# define maxTab 20
+# define maxCell 20
+
+
+typedef struct State State;
+typedef struct DocState DocState;
+typedef struct SectState SectState;
+typedef struct ParState ParState;
+typedef struct CharState CharState;
+
+typedef struct TblState TblState; /* this is separate */
+
+
+/* document properties */
+
+struct DocState
+{
+ int landscape; /* non-zero if landscape */
+ double pageWidth; /* paper width */
+ double pageHeight; /* paper height */
+ double leftMargin; /* left margin */
+ double rightMargin; /* right margin */
+ double topMargin; /* top margin */
+ double bottomMargin; /* bottom margin */
+ double tabWidth; /* default tab width */
+};
+
+
+/* section properties */
+
+struct SectState
+{
+ int breakType; /* section break type */
+ int pageStart; /* section starting page number */
+ int pageRestart; /* restart page numbering each sect. */
+ double headerPos; /* from top of page */
+ double footerPos; /* from bottom of page */
+ int titleSpecial; /* first page special */
+};
+
+
+/* paragraph properties */
+
+struct ParState
+{
+ double firstIndent; /* first indent */
+ double leftIndent; /* left indent */
+ double rightIndent; /* right indent */
+ double spaceBefore; /* space before lines */
+ double spaceAfter; /* space after lines */
+ double spaceBetween; /* space between lines */
+ int tabFlag; /* any tabs set yet? (0 = no) */
+ int nTabs; /* number of tabs (0 = defaults) */
+ double tab[maxTab]; /* tab positions */
+ int tabType[maxTab]; /* tab types */
+ int tabChar; /* tab (leader) character */
+ int justification; /* justification */
+ int borderType; /* type of border */
+ int borderFlags; /* where to draw borders */
+};
+
+
+/* character properties */
+
+struct CharState
+{
+ int fontSize; /* font (point) size */
+ u_long charStyle; /* character style */
+ double superScript; /* superscript */
+ double subScript; /* subscript */
+};
+
+struct State
+{
+ int destination; /* state destination */
+ DocState docState;
+ SectState sectState;
+ ParState parState;
+ CharState charState;
+};
+
+
+/* table properties */
+
+struct TblState
+{
+ int tableHeader; /* non-zero if table header written */
+ int nCells; /* number of cells */
+ int curCell; /* current cell (0-based) */
+ double cellPos[maxCell]; /* cell positions (right edge) */
+ double tableLeft; /* table left edge position */
+ double cellGap; /* horiz. gap between cells */
+ int border[maxCell][4]; /* cell borders */
+};
+
+
+extern int tvers; /* troff version */
+extern int mvers; /* macro package version */
+
+extern TblState *its;
+extern int inTable;
+
+extern FILE *f;
+
+
+extern State *is; /* current internal state */
+extern DocState *ids; /* internal document state */
+extern SectState *iss; /* internal section state */
+extern ParState *ips; /* internal paragraph state */
+extern CharState *ics; /* internal character state */
+
+extern State *ws; /* written state */
+extern DocState *wds; /* written document state */
+extern SectState *wss; /* written section state */
+extern ParState *wps; /* written paragraph state */
+extern CharState *wcs; /* written character state */
+
+extern int docStateChanged; /* document properties have changed */
+extern int sectStateChanged; /* section properties have changed */
+extern int parStateChanged; /* paragraph properties have changed */
+extern int charStateChanged; /* character properties have changed */
+
+# define stateChanged \
+ (docStateChanged||sectStateChanged||parStateChanged||charStateChanged)
+
+
+extern int indirectionLevel;
+
+
+extern void InitState ();
+extern void CheckFinalState ();
+extern void PushIState ();
+extern void PopIState ();
+extern void PushWState ();
+extern void PopWState ();
+extern void BeginDiversion ();
+extern void EndDiversion ();
+extern void RestoreSectDefaults ();
+extern void RestoreParDefaults ();
+extern void RestoreCharDefaults ();
+
+
+extern void InitTabSet ();
+
+
+extern int MapBorderLocation ();
+
+
+extern void SelectFormatterMaps ();
+extern void SelectMacPackMaps ();
+extern void SelectCharSetMaps ();
+extern char *CharMapping ();
+
+
+extern void TblAttr ();
+extern void BeginTbl ();
+extern void EndTbl ();
+extern void BeginCell ();
+extern void EndCell ();
+
+
+extern void FlushState ();
+extern void FlushInitialState ();
+extern void FlushSectState ();
+extern void Flush ();
+extern void SaveTblFPV ();
+extern void FlushTblFPV ();
+
+extern double EnWidth ();
+
+extern void ResetPar ();
+extern void ResetParLine ();
+extern void Sect ();
+extern void Par ();
+extern void PutString ();
+extern void Comment ();
diff --git a/support/RTF-1_06a1/rtf2troff.ms b/support/RTF-1_06a1/rtf2troff.ms
new file mode 100644
index 0000000000..8f75fb2f1e
--- /dev/null
+++ b/support/RTF-1_06a1/rtf2troff.ms
@@ -0,0 +1,649 @@
+.\"
+.\" troff -ms % | lpr
+.\"
+.\" revision date - change whenever this file is edited
+.ds RD 5 April 1991
+.nr PO 1.2i \" page offset 1.2 inches
+.nr PD .7v \" inter-paragraph distance
+.\"
+.EH 'RTF-to-troff Translation'- % -''
+.OH ''- % -'RTF-to-troff Translation'
+.OF 'Revision date:\0\0\*(RD''Printed:\0\0\n(dy \*(MO 19\n(yr'
+.EF 'Revision date:\0\0\*(RD''Printed:\0\0\n(dy \*(MO 19\n(yr'
+.\"
+.\" subscript strings
+.ds < \s-2\v'.4m'
+.ds > \v'-.4m'\s+2
+.\"
+.\" I - italic font (taken from -ms and changed)
+.de I
+.nr PQ \\n(.f
+.if t \&\\$3\\f2\\$1\\fP\&\\$2
+.if n .if \\n(.$=1 \&\\$1
+.if n .if \\n(.$>1 \&\\$1\c
+.if n .if \\n(.$>1 \&\\$2
+..
+.TL
+rtf2troff
+.sp .5v
+An RTF to troff Translator
+.AU
+Paul DuBois
+dubois@primate.wisc.edu
+.AI
+Wisconsin Regional Primate Research Center
+Revision date:\0\0\*(RD
+.NH
+Introduction
+.LP
+.I rtf2troff
+is a document translator that takes an input file in RTF format
+and writes output suitable for processing by
+.I troff .
+It has a number of features, including:
+.IP \(bu
+Production of output that, when run through
+.I troff ,
+on rare occasions possesses a mild resemblance to the original document.
+.IP \(bu
+Voluminous, inefficient and largely incomprehensible source code (available for free and overpriced at that).
+.IP \(bu
+Often-incomprehensible output, especially for tables.
+.IP \(bu
+Complete lack of support for formulas.
+.IP \(bu
+Support for underlining and strikethrough
+that generates prize-winning amounts of output.
+Besides its incredible bulk, this has the additional security feature
+of being impossible to make sense of for editing.
+The reckless user is, however, given the option of disabling this valuable
+form of protection.
+.IP \(bu
+Inability to write
+.I nroff -specific
+output, or output specific to the
+.I \-me ,
+.I \-mm
+or
+.I \-ms
+macro packages.
+.IP \(bu
+Blissful ignorance of the fact that there are any fonts other than the
+default, except for purposes of boldface and italics.
+.IP \(bu
+Ability to completely lose any unrecognized input, or, for variety, core dump.
+.IP \(bu
+Merges text of footnotes right into the main body of the document.
+You didn't really want 'em at the bottom of the page anyway, did you?
+.LP
+Perhaps over time this list will shrink and this section can be removed.
+But don't hold your breath.
+.LP
+The intended audience of this document is not those who might use
+.I rtf2troff
+for daily work, but programmers who want to know why it's written the way
+it is.
+As such, it discusses aspects of the implementation.
+The source code should be consulted for further reference.
+Actually, I suspect you're reading this because you've already looked
+at the source and couldn't make any sense of it!
+.NH
+Random Implementation Notes
+.LP
+In the output produced by
+.I rtf2troff ,
+a distinction is made between
+.I content
+(or document) text and
+.I formatting
+(or control)
+text.
+Content text consists of the characters that are actually supposed
+to appear in the finished document.
+Formatting text affects how those characters appear.
+Formatting text may be inline with content text (e.g., ``\efR'', ``\es+3'')
+or on a line by itself (e.g., ``.ft R'', ``.ps +3'').
+.NH 2
+State Maintenance Issues
+.LP
+It is possible to write out control language whenever any changes are
+made to document, section, paragraph or character formatting
+properties, but that
+would result in more output than is necessary.
+Instead,
+.I rtf2troff
+maintains notions of two kinds of state:
+an
+.I internal
+state, which is the current state of formatting properties as indicated
+by control words encountered in the RTF input stream,
+and
+.I written
+state, which tracks the state corresponding to the
+.I troff
+control language that has been written to the output (i.e., the state
+that
+.I troff
+will be in).
+.LP
+Changes to formatting properties are simply accumulated in the
+internal state without writing any output.
+When content text is to be written out, a check is made for any
+discrepancy between the accumulated changes in the internal state, and the
+written state.
+If there are any differences, control language is generated to bring
+the written state into sync with the internal state, before writing
+the content text.
+This guarantees that the correct formatting properties will apply to
+the text, and minimizes the amount of control language generated.
+.LP
+Control language to set up the initial state is flushed before anything
+else comes out.
+It's flushed when any of the following are about to be written:
+(i) any content text for the main body of the document
+(ii) anything at all for headers or footers;
+(iii) the beginning of a table.
+The initial state is written using absolute values.
+State changes are generally written using relative changes to the
+current state values.
+Use of relative values allows manual changes to be made to the initial
+part of the output and have the rest of the document be affected.
+For instance, you can change the initial line indent, and the rest
+of the document will follow the change.
+.LP
+RTF files may contain groups.
+Normally, a group inherits the state of the group containing it, and
+changes made within the group are discarded when the group ends.
+To mimic this, a stack of internal states is maintained by
+.I rtf2troff .
+When a group begins, a new internal state is pushed on the stack,
+with the same values as the previous state.
+This action does not cause any change to the state values, but the
+occurrence of document, section,
+paragraph and character formatting control symbols does.
+When a group ends, the current state is popped off the stack, and the
+previous state becomes the current state.
+The may well change the current state values, if changes were made
+within the group; when the next content text is written, control
+language to undo those changes is generated.
+.LP
+Internal state 0 is special.
+It contains all the RTF default values and is the base state in which the
+writer starts.
+Moreover, it is never
+changed because the first token that should be found in an RTF document
+is ``{'', which
+causes a new state (state 1) to be pushed on the stack immediately.
+Thus the contents of state 0 can be used to restore section, paragraph
+and character formatting defaults.
+.LP
+\fBSection Defaults\*-\fRThe section properties of state 0
+are set to the RTF defaults
+and are used to restore the section state when ``\esectd'' occurs.
+.LP
+\fBParagraph Defaults\*-\fRThe paragraph properties of state 0
+are set to the RTF defaults
+and are used to restore the paragraph state when ``\epard'' occurs.
+The ``Normal'' style is then applied,
+since the real defaults include not only the static initial values,
+but also the formatting produced by that style.
+.LP
+\fBCharacter Defaults\*-\fRThe character properties of state 0
+are set to the RTF defaults
+and are used to restore the character state when ``\eplain'' occurs.
+.LP
+Some groups, such as headers and footers, do
+.I not
+inherit the
+formatting properties of the enclosing group, presumably because the
+output that results from those groups is not contiguous with that of
+the preceding or following groups\*-they generate output that appears
+possibly far away.
+To force non-inheritance of the enclosing group's formatting
+properties,
+the effects of the ``\epard'' and ``\eplain'' tokens are
+applied at the beginning of this kind of group.
+The specification says that ``\esectd'' should also be applied, but I
+don't believe it.
+Why should the section break style, title page special value, etc. be
+reset just because you're collecting a header?
+.LP
+A related problem for such groups is that any changes made to the
+written state while processing them must
+not be allowed to affect the formatting of text following the
+group.
+In other words, the state that
+.I troff
+ends up in when the group ends needs to be rewound to the state it was
+in when the group began.
+To allow changes to the written state to be forgotten properly at the
+end of the group, two things must happen.
+.I troff
+must be told to revert to the pre-group written state, and
+.I rtf2troff
+must revert its own notion of written state.
+To allow
+.I troff
+to revert its state, such groups are processed using environment
+switches within diversions, to collect the group output in a separate
+environment and to allow the environment to be restored.
+To revert the
+.I rtf2troff
+written state, a copy of the state is saved before and restored after
+processing the group.
+.LP
+.I rtf2troff
+currently needs only one level of diversion, so only a single
+state copy is needed.
+However, the implementation uses a stack in case a more general mechanism is
+needed in the future.
+.NH 2
+Output Line Length Control
+.LP
+RTF paragraphs can contain very long strings of text.
+To make
+.I rtf2troff
+output more readable and editable, long paragraphs are broken into multiple
+lines.
+All output is written for fill mode, so these lines will be joined back
+together by
+.I troff .
+However, for this to work, lines must be broken carefully.
+The best ``natural break'' is when there is a single space between
+words.
+Several implications follow from this observation.
+.IP (i)
+Must not break to a new line when the next character to be written is
+whitespace, or
+.I troff
+will not join the lines back together (whitespace at the beginning of
+an input line forces a break).
+.IP (ii)
+Must not break in the middle of a word, or there will be extra whitespace
+in the middle of it when lines are joined.
+.IP (iii)
+Must not lose whitespace at end of broken lines (\fItroff\fR tosses
+whitespace at ends of lines), so only break when there is a single
+space between words.
+.IP (iv)
+Must not put out an extra newline at the end of the paragraph, if the output
+line was just broken after the last character written.
+.LP
+To complicate matters, it is also desirable that the following be true:
+If underlining or stikeout is enabled, the ugly sequences to do them
+should be forced onto separate lines for each character, no matter what,
+to make the output more editable.
+Since this may violate the conditions above (e.g., if only the middle
+of a word is underlined), use of ``\ec'' may be necessary.
+However, ``\ec'' should only be written when absolutely necessary,
+to avoid cluttering up the output.
+.LP
+Three variables are used to keep track of output written to the current
+paragraph.
+.I inPara
+is true if any characters have been written out to
+the current paragraph.
+.I oLen
+is the number of characters written to the current output line of the
+paragraph.
+It is zero if the current line is empty.
+.I breakOK
+is non-zero if it's OK to break a line when the next content character
+is written (if the next character isn't a space).
+.LP
+When a character is about to be written for a paragraph, if
+.I inPara
+is zero, it is assumed that a paragraph is just beginning, otherwise that
+part but not all of a paragraph has been written out.
+This assumption is used when writing both content and formatting text.
+If a content character is about to be written and
+.I inPara
+is zero, beginning-of-paragraph processing takes place:
+space before paragraphs is written out; if the paragraph
+has a top border, a line is drawn; control language is generated
+to set the temporary indent (the RTF ``first line indent'').
+.I inPara
+is also checked when writing formatting text that must be on a line by itself:
+if
+.I inPara
+is not zero, content text has been written which
+must be ``flushed'' by writing a newline.
+.NH 2
+Underlining/Strikethrough
+.LP
+.I rtf2troff
+can do continuous or word underlining.
+If a document conversion is simply for printing purposes,
+it makes sense to leave underlining conversion on.
+If you want to edit the converted file, you may want to turn underlining
+conversion off (with the
+.B \-u
+option),
+because it may be difficult to edit the portions of text
+that are underlined.
+Another reason to turn underlining off is that some printers seem to
+take a long time to print documents containing a lot of underlining.
+.LP
+These remarks apply to strikeout text as well.
+.NH 2
+Page Orientation
+.LP
+Some versions of Word (e.g., WfM) don't seem to write out the
+``\elandscape'' control word properly, so when
+.I rtf2troff
+writes out the initial state-setting control language, it checks to see
+whether the page height is less than the width.
+If so, it prints a message and assumes landscape is on.
+.NH 2
+Tab Handling
+.LP
+The defaults are every .5 inch, left justified, motion
+only (no leader character).
+There are
+.I maxTab
+tabs (\fImaxTab\fR \(eq 20, which might be enough).
+When the state is pushed, the new state inherits the previous state's tab
+settings, but if any tabs are set explicitly in the new state, they override
+inherited tabs.
+A flag is used to know when the first tab is being set in the new state.
+When that happens, a new tab set is started instead of
+adding the tab to the end of the existing set.
+.LP
+Tabs may have position and justification.
+For a given tab, the position is the
+.I last
+attribute specified.
+Thus, when a justification indicator is encountered in the input
+stream, it's entered into the
+.I next
+tab slot, but the tab count is not incremented.
+When the position is specified,
+the count is incremented and any justification previously specified
+automatically becomes part of the new tab stop.
+.LP
+In RTF, tabs may also be associated with a leader character, but
+.I rtf2troff
+only maintains a single tab character.
+Thus, if multiple tab leader characters are specified for a paragraph,
+only the last one is used, and it applies to all the tabs.
+This is certainly unsatisfactory, but that's the way it is.
+.LP
+Bar tabs are ignored.
+Decimal tabs are treated as right-justified tabs.
+.NH 2
+Tables
+.LP
+.I rtf2troff
+includes some table support, but tables are hard to do well, so you'll
+easily find examples which confuse it and convert poorly.
+At least
+it was hard for
+.I me
+to figure out how to do them well, but then, I don't understand
+.I tbl .
+Does anyone?
+.LP
+Tables are written out under the assumption that you have the
+.I tbl
+program available.
+Each row of a table is written out between .TS/.TE pairs.
+Cell contents are written out using
+.I tbl 's
+``T{''...``T}'' construct.
+.LP
+One problem with writing tables using the
+T{/T} mechanism is that
+.I tbl
+tries to keep font, point size and vertical spacing changes within one
+cell from affecting the next.
+Since RTF tables may well expect changes to these three parameters to
+carry over to following cells,
+.I tbl 's
+invisibly resetting these introduces a problem.
+The solution to this is straightforward, but results in output that's
+even uglier than usual:
+force out the current font, point size and vertical spacing at the
+beginning of each cell.
+It's also necessary to do this after the ``.TE'' since that seems
+to mess with point size and vertical spacing.
+.LP
+One optimization that ought to be possible (says he) to minimize the
+amount of output generated is to compare the current values to the
+values in force at the beginning of the table and only write them out
+if they're different.
+Unfortunately, for reasons I don't understand, this doesn't always
+work.
+Thus brute force prevails.
+.LP
+Another problem arises in connection with column widths.
+.I tbl
+assumes a default column separation of 3 ens, in the current point
+size.
+.I rtf2troff
+knows the width that a cell should be and can write the table
+specification as such.
+Unfortunately, the column separation is added to that width, it's not
+a part of it, so the table ends up wider than it should be.
+A separation of zero can be used, which will make the table the right
+width, but the text is too jammed together.
+If there are borders, the text hits the borders.
+.LP
+Specifying a 1-en separation spaces the text away from the cell
+borders, but then the table is again too wide.
+This could be handled if there were some easy way of subtracting 1 en
+from the column width, but there isn't.
+Cell widths are absolute values, whereas ens depend on the current
+point size.
+You can't specify a column width in the table heading, e.g., as
+``l1w(1.5i-1n)'', either.
+It
+.I almost
+always works, but some tables botch terribly.
+The ``solution'' adopted in
+.I rtf2troff
+is to try to guess how big an en is in the current point size and
+subtract it from the column width before writing the table header.
+This works pretty well if you can get accurate width data for your
+version of
+.I troff .
+.LP
+Cell borders are handled to a small extent.
+One problem is that each row of an RTF table is written as a separate
+.I tbl
+table, and the .TS/.TE macros can result in a little space before and after
+the table if you use a macro package such as
+.B \-me .
+This means that ugly gaps between rows may result.
+.LP
+Tabs within cells are ignored, i.e., mishandled.
+.LP
+Merged cells are botched.
+.LP
+In general,
+the table-writing code tends to do fairly well with simple tables and
+less well with more complex ones.
+The problem with the output generated for tables is that it is very
+``busy'' and if it's incorrect, it's not always evident how to correct
+it, should you wish to do so manually.
+.LP
+Some newer Xerox 4045 printers have problems with complex tables generated
+by
+.I xroff .
+This is not specific to output generated by
+.I rtf2troff ,
+so if tables appear to be botched, it might not be
+.I rtf2troff 's
+fault.
+.NH 2
+Special Character Translation
+.LP
+Special characters (those in the range 128..255)
+do not have a direct ASCII representation
+and are usually written for
+.I troff
+as a special escape sequence.
+For instance, the plus-or-minus symbol ``\(+-'' can be written out
+as ``\e(+-''.
+.I rtf2troff
+uses lookup tables to map special characters values onto these escape
+sequences.
+.LP
+The association between character values and escape sequences is subject
+to quite a bit of variation, due to three factors:
+.IP \(bu
+There are four possible RTF character sets, and they can use different values
+to represent a special character.
+For instance, the divide symbol ``\(di'' is character value 247 in the ANSI
+character set and 214 on the Macintosh.
+Thus, different lookup tables are needed for different character sets.
+Ugh.
+.IP \(bu
+Different versions of
+.I troff
+vary in the set of escape sequences they support.
+Thus, different lookup tables may be needed for whatever version(s) of
+.I troff
+are locally available.
+For instance,
+.I eroff
+may understand different sequences than
+.I xroff .
+Ugh ugh.
+.IP \(bu
+Some macro packages like
+.I \-me
+and
+.I \-ms
+provide their own escape sequences for special characters.
+If
+.I rtf2troff
+is told to write macro-package-specific output, special character mapping
+should be tailored to that package.
+Currently,
+.I rtf2troff
+doesn't know much about macro packages, but it may someday, so this factor
+needs to be kept in mind.
+Ugh ugh ugh.
+.LP
+Due to these factors, a scheme is used
+to allow character mapping to be done, and to allow site-specific
+modifications to be made to accommodate local conventions.
+This scheme is complicated and incomprehensible, but it does have the
+virtue that it works.
+.LP
+For each
+.I troff
+variant supported, there is a set of character mappings, one mapping
+for each of the four RTF character sets.
+These are the ``default'' mappings.
+There are also three other sets of four mappings, one set for each of the
+.I \-me ,
+.I \-mm ,
+and
+.I \-ms
+macro packages.
+The set for each package has a mapping for each character set.
+These are ``override'' mappings, and should have entries only for those
+special characters for which the macro package provides special escape
+sequences.
+When a special character is mapped, the override table is consulted first.
+If an entry for the character is found, it's used.
+Otherwise the default mapping is used.
+If nothing is found there, either, ``<<UNKNOWN>>'' is returned, which
+should be sufficiently ugly to call your attention to it so you know
+some editing needs to be done.
+.LP
+The maps are selected from the command line with the
+.B \-t
+and
+.B \-me|\-mm|\-ms
+options.
+For instance, if your site supports
+.I xroff
+and
+.I pstroff ,
+you can select tables for one or the other with
+.LP
+.DS
+rtf2troff -t xroff
+rtf2troff -t pstroff
+.DE
+.LP
+It might be more convenient simply to create shell scripts, e.g.,
+.I rtf2xroff ,
+which would contain
+.LP
+.DS
+#!/bin/sh
+exec rtf2troff -t xroff "$@"
+.DE
+.LP
+Internally, character mappings are selected using three functions.
+They must be called in the order described.
+If a
+.I troff
+name is given (with the
+.B \-t
+argument),
+.I SelectFormatterMaps()
+is called.
+This selects the proper entry from the mapping table and selects
+the set of default maps.
+Then, if a macro package argument is given, it should be passed
+to
+.I SelectMacPackMaps()
+so that the proper override tables are used.
+During RTF file parsing, when the character set symbol is found,
+pass its minor number to
+.I SelectCharSetMaps()
+to select the charset-specific maps from the default and override maps.
+You should be confused enough by the preceding that you will not be
+surprised when I adjure you to consult the source code for more information.
+.LP
+To modify
+.I rtf2troff
+for local variations, you must
+make sure the mapping table in
+.I trf-charmap.c
+has an entry for each of your
+.I troff
+versions.
+You may have to contruct new mappings yourself.
+.LP
+If you do make such modifications, please let me know about them.
+.NH 2
+Error messages
+.LP
+Tokens not recognized by the reader are echoed.
+.LP
+``Uh-oh! RTF group nesting exceeded maximum level,'':
+the maximum stack depth needs to be increased.
+.LP
+``unbalanced brace level'':
+the RTF file is malformed; some ``{'' is not matched by a ``}''.
+.LP
+``unrestored environment'':
+indicates a bug in
+.I rtf2troff .
+.LP
+``unrestored indirection'':
+indicates a bug in
+.I rtf2troff .
+.LP
+If you get a message ``Trap Loop Death detected'', it means the header
+and footer overlap.
+This is legal in RTF, but
+.I troff
+doesn't like it and can end up in an infinite loop because the header
+triggers the footer trap, which triggers the header trap, which...
+.LP
+Most other messages come from inside the reader, e.g., if the stylesheet
+or font table readers get confused.
+.NH 2
+Registers and Macros
+.LP
+A number of register and macro names are used by
+.I rtf2troff .
+If these conflict with those used by any preprocessors you might use,
+you can change them by editing
+.I rtf.h .
diff --git a/support/RTF-1_06a1/rtfdiag.c b/support/RTF-1_06a1/rtfdiag.c
new file mode 100644
index 0000000000..ccc6df9d35
--- /dev/null
+++ b/support/RTF-1_06a1/rtfdiag.c
@@ -0,0 +1,121 @@
+/*
+ rtfdiag - read rtf input, write diagnostic stuff. Useful for
+ testing reader to see if it's finding and classifying
+ tokens properly, reading destinations, reprocessing
+ styles, etc.
+
+ Options:
+
+ -e echo tokens as they are read
+
+ 03 Feb 91 Paul DuBois dubois@primate.wisc.edu
+
+ 03 Feb 91 V1.0. Created.
+ 27 Feb 91 V1.01. Updated for distribution 1.05.
+*/
+
+# include <stdio.h>
+# include "rtf.h"
+
+
+static char *usage = "rtfdiag [-e] [file]";
+
+static void TokenEcho ();
+static void PrintTables ();
+
+int main (argc, argv)
+int argc;
+char **argv;
+{
+ RTFInit ();
+
+ --argc;
+ ++argv;
+
+ while (argc > 1 && **argv == '-')
+ {
+ while (*++*argv != '\0')
+ {
+ switch (**argv)
+ {
+ case 'e':
+ RTFSetReadHook (TokenEcho);
+ break;
+ default:
+ fprintf (stderr, "Unknown option: -%c\n",
+ **argv);
+ fprintf (stderr, "%s\n", usage);
+ exit (1);
+ }
+ }
+ --argc;
+ ++argv;
+ }
+
+ /* not clever; only allows stdin or one named file to be read */
+
+ if (argc > 0)
+ {
+ if (freopen (argv[0], "r", stdin) == NULL)
+ {
+ fprintf (stderr, "Can't open \"%s\"\n", argv[0]);
+ exit (1);
+ }
+ }
+
+ /* process the input stream */
+
+ RTFRead ();
+
+ PrintTables ();
+
+ exit (0);
+}
+
+static void TokenEcho ()
+{
+ printf ("%d\t%d\t%d\t%d\t\"%s\"\n",
+ rtfClass, rtfMajor, rtfMinor, rtfParam, rtfTextBuf);
+}
+
+
+static void PrintTables ()
+{
+RTFColor *cp;
+RTFFont *fp;
+RTFStyle *sp;
+RTFStyleElt *sep;
+int count;
+
+ printf ("Font table:\n");
+ count = 0;
+ for (fp = RTFGetFont (-1); fp != NULL; fp = fp->rtfNextFont)
+ {
+ ++count;
+ printf ("%2d:\t%s\t%d\n", fp->rtfFNum, fp->rtfFName,
+ fp->rtfFFamily);
+ }
+ printf ("Font table entries:\t%d\n\n", count);
+
+ printf ("Color table:\n\tred\tgreen\tblue\n");
+ count = 0;
+ for (cp = RTFGetColor (-1); cp != NULL; cp = cp->rtfNextColor)
+ {
+ ++count;
+ printf ("%2d:\t%d\t%d\t%d\n", cp->rtfCNum, cp->rtfCRed,
+ cp->rtfCGreen, cp->rtfCBlue);
+ }
+ printf ("Color table entries:\t%d\n\n", count);
+
+ printf ("Stylesheet:\n");
+ count = 0;
+ for (sp = RTFGetStyle (-1); sp != NULL; sp = sp->rtfNextStyle)
+ {
+ ++count;
+ printf ("%2d:\t%s\t%d\t%d\n", sp->rtfSNum, sp->rtfSName,
+ sp->rtfSBasedOn, sp->rtfSNextPar);
+ for (sep = sp->rtfSSEList; sep != NULL; sep = sep->rtfNextSE)
+ printf ("\t%s\n", sep->rtfSEText);
+ }
+ printf ("Style table entries:\t%d\n\n", count);
+}
diff --git a/support/RTF-1_06a1/rtfindent.c b/support/RTF-1_06a1/rtfindent.c
new file mode 100644
index 0000000000..e04d2dee69
--- /dev/null
+++ b/support/RTF-1_06a1/rtfindent.c
@@ -0,0 +1,109 @@
+/*
+ rtfindent - indent RTF file
+
+ Useful for revealing nesting structure of RTF documents.
+ Also makes them somewhat more readable.
+
+ The output is legal RTF but will not format exactly as the input.
+ The extra newlines that are introduced might not make a difference,
+ but the extra spaces used to effect indenting levels would.
+
+ 28 Jan 91 Paul DuBois dubois@primate.wisc.edu
+
+ 28 Jan 90 V1.0. Created.
+ 28 Feb 91 V1.01. Updated for distribution 1.05.
+*/
+
+# include <stdio.h>
+
+
+int indLevel = 0;
+int indAmt = 2;
+int c;
+int nChars = 0;
+int escNext = 0;
+
+
+int main (argc, argv)
+int argc;
+char **argv;
+{
+ /* not clever; only allows stdin or one named file to be read */
+
+ if (argc > 1)
+ {
+ if (freopen (argv[1], "r", stdin) == NULL)
+ {
+ fprintf (stderr, "Can't open \"%s\"\n", argv[1]);
+ exit (1);
+ }
+ }
+
+ while ((c = getchar ()) != EOF)
+ {
+ if (escNext)
+ {
+ escNext = 0;
+ Put (c);
+ continue;
+ }
+ if (c == '\\') /* this would be wrong for a general reader */
+ {
+ escNext = 1;
+ Put (c);
+ continue;
+ }
+ if (c == '{')
+ {
+ Flush ();
+ Put (c);
+ Flush ();
+ ++indLevel;
+ }
+ else if (c == '}')
+ {
+ Flush ();
+ --indLevel;
+ Put (c);
+ Flush ();
+ }
+ else if (c == '\r')
+ {
+ Put ('\n');
+ Flush ();
+ }
+ else
+ Put (c);
+ }
+ Flush ();
+}
+
+
+Flush ()
+{
+ if (nChars > 0)
+ {
+ Put ('\n');
+ nChars = 0;
+ }
+}
+
+
+Put (c)
+int c;
+{
+int i, j;
+ if (nChars == 0) /* beginning of line, dump out indent */
+ {
+ for (i = 0; i < indLevel; i++)
+ {
+ for (j = 0; j < indAmt; j++)
+ {
+ putchar (' ');
+ ++nChars;
+ }
+ }
+ }
+ putchar (c);
+ ++nChars;
+}
diff --git a/support/RTF-1_06a1/rtfskel.c b/support/RTF-1_06a1/rtfskel.c
new file mode 100644
index 0000000000..dec038f123
--- /dev/null
+++ b/support/RTF-1_06a1/rtfskel.c
@@ -0,0 +1,801 @@
+/*
+ rtfskel - skeleton RTF translator
+
+ This provides placeholders for (almost) all the tokens listed in
+ rtf.h. You can plug in your code as you like to handle particular
+ tokens, or rip out code for tokens you want to ignore.
+
+ The built-in destination readers are left enabled, as is the
+ default of style expansion ON.
+
+ 07 Feb 91 Paul DuBois dubois@primate.wisc.edu
+
+ 07 Feb 91 V1.0. Created.
+ 26 Feb 91 V1.01. Updated for distribution 1.05.
+*/
+
+# include <stdio.h>
+# include "rtf.h"
+
+
+static void UnknownClass ();
+static void GroupClass ();
+static void TextClass ();
+static void ControlClass ();
+
+static void Destination ();
+static void CharSet ();
+static void SpecialChar ();
+static void DocAttr ();
+static void SectAttr ();
+static void TblAttr ();
+static void ParAttr ();
+static void CharAttr ();
+static void PictAttr ();
+static void FieldAttr ();
+static void TOCAttr ();
+static void PosAttr ();
+
+
+int main (argc, argv)
+int argc;
+char **argv;
+{
+ RTFInit ();
+
+ --argc;
+ ++argv;
+
+ /* not clever; only allows stdin or one named file to be read */
+
+ if (argc > 0)
+ {
+ if (freopen (argv[0], "r", stdin) == NULL)
+ {
+ fprintf (stderr, "Can't open \"%s\"\n", argv[0]);
+ exit (1);
+ }
+ }
+
+ /* install class callbacks */
+
+ RTFSetClassCallback (rtfUnknown, UnknownClass);
+ RTFSetClassCallback (rtfGroup, GroupClass);
+ RTFSetClassCallback (rtfText, TextClass);
+ RTFSetClassCallback (rtfControl, ControlClass);
+
+ /* process the input stream */
+
+ RTFRead ();
+
+ exit (0);
+}
+
+
+/*
+ Token class callbacks
+*/
+
+
+static void UnknownClass ()
+{
+ /* use this to print warnings about unknown tokens */
+}
+
+
+static void GroupClass ()
+{
+ switch (rtfMajor)
+ {
+ case rtfBeginGroup:
+ /* push state */
+ break;
+ case rtfEndGroup:
+ /* pop state */
+ break;
+ }
+}
+
+static void TextClass ()
+{
+ /* rtfMajor contains character value */
+}
+
+
+/*
+ Process control symbol.
+*/
+
+static void ControlClass ()
+{
+ switch (rtfMajor)
+ {
+ case rtfVersion:
+ break;
+ case rtfDefFont:
+ /*
+ rtfParam contains the default font number. Beware
+ that there is no guarantee that this font will actually
+ be listed in the font table!
+ */
+ break;
+ case rtfCharSet:
+ CharSet ();
+ break;
+ case rtfDestination:
+ Destination ();
+ break;
+ case rtfFontFamily:
+ /* only occurs within font table - can ignore */
+ break;
+ case rtfColorName:
+ /* only occurs within color table - can ignore */
+ break;
+ case rtfSpecialChar:
+ SpecialChar ();
+ break;
+ case rtfStyleAttr:
+ /* only occurs within stylesheet - can ignore */
+ break;
+ case rtfDocAttr:
+ DocAttr ();
+ break;
+ case rtfSectAttr:
+ SectAttr ();
+ break;
+ case rtfTblAttr:
+ TblAttr ();
+ break;
+ case rtfParAttr:
+ ParAttr ();
+ break;
+ case rtfCharAttr:
+ CharAttr ();
+ break;
+ case rtfPictAttr:
+ PictAttr ();
+ break;
+ case rtfFieldAttr:
+ FieldAttr ();
+ break;
+ case rtfTOCAttr:
+ TOCAttr ();
+ break;
+ case rtfPosAttr:
+ PosAttr ();
+ break;
+ }
+}
+
+
+/*
+ Control class major number handlers. Each one switches on
+ the minor numbers that occur within the major number.
+*/
+
+
+static void CharSet ()
+{
+ switch (rtfMinor)
+ {
+ case rtfAnsiCharSet:
+ break;
+ case rtfMacCharSet:
+ break;
+ case rtfPcCharSet:
+ break;
+ case rtfPcaCharSet:
+ break;
+ }
+}
+
+
+static void Destination ()
+{
+ switch (rtfMinor)
+ {
+ case rtfPict:
+ break;
+ case rtfFootnote:
+ break;
+ case rtfHeader:
+ break;
+ case rtfHeaderLeft:
+ break;
+ case rtfHeaderRight:
+ break;
+ case rtfHeaderFirst:
+ break;
+ case rtfFooter:
+ break;
+ case rtfFooterLeft:
+ break;
+ case rtfFooterRight:
+ break;
+ case rtfFooterFirst:
+ break;
+ case rtfFNSep:
+ break;
+ case rtfFNContSep:
+ break;
+ case rtfFNContNotice:
+ break;
+ case rtfInfo:
+ break;
+ case rtfStyleSheet:
+ /* will never occur because of default destination reader */
+ break;
+ case rtfFontTbl:
+ /* will never occur because of default destination reader */
+ break;
+ case rtfColorTbl:
+ /* will never occur because of default destination reader */
+ break;
+ case rtfField:
+ break;
+ case rtfFieldInst:
+ break;
+ case rtfFieldResult:
+ break;
+ case rtfIndex:
+ break;
+ case rtfIndexBold:
+ break;
+ case rtfIndexItalic:
+ break;
+ case rtfIndexText:
+ break;
+ case rtfIndexRange:
+ break;
+ case rtfTOC:
+ break;
+ case rtfBookmarkStart:
+ break;
+ case rtfBookmarkEnd:
+ break;
+ case rtfITitle:
+ break;
+ case rtfISubject:
+ break;
+ case rtfIAuthor:
+ break;
+ case rtfIOperator:
+ break;
+ case rtfIKeywords:
+ break;
+ case rtfIComment:
+ break;
+ case rtfIVersion:
+ break;
+ case rtfIDoccomm:
+ break;
+ }
+}
+
+
+static void SpecialChar ()
+{
+ switch (rtfMinor)
+ {
+ case rtfCurHeadPage:
+ break;
+ case rtfCurFNote:
+ break;
+ case rtfCurHeadPict:
+ break;
+ case rtfCurHeadDate:
+ break;
+ case rtfCurHeadTime:
+ break;
+ case rtfFormula:
+ break;
+ case rtfNoBrkSpace:
+ break;
+ case rtfNoReqHyphen:
+ break;
+ case rtfNoBrkHyphen:
+ break;
+ case rtfPage:
+ break;
+ case rtfLine:
+ break;
+ case rtfPar:
+ break;
+ case rtfSect:
+ break;
+ case rtfTab:
+ break;
+ case rtfCell:
+ break;
+ case rtfRow:
+ break;
+ case rtfCurAnnot:
+ break;
+ case rtfAnnotation:
+ break;
+ case rtfAnnotID:
+ break;
+ case rtfCurAnnotRef:
+ break;
+ case rtfFNoteSep:
+ break;
+ case rtfFNoteCont:
+ break;
+ case rtfColumn:
+ break;
+ case rtfOptDest:
+ break;
+ case rtfIIntVersion:
+ break;
+ case rtfICreateTime:
+ break;
+ case rtfIRevisionTime:
+ break;
+ case rtfIPrintTime:
+ break;
+ case rtfIBackupTime:
+ break;
+ case rtfIEditTime:
+ break;
+ case rtfIYear:
+ break;
+ case rtfIMonth:
+ break;
+ case rtfIDay:
+ break;
+ case rtfIHour:
+ break;
+ case rtfIMinute:
+ break;
+ case rtfINPages:
+ break;
+ case rtfINWords:
+ break;
+ case rtfINChars:
+ break;
+ case rtfIIntID:
+ break;
+ }
+}
+
+
+static void DocAttr ()
+{
+ switch (rtfMinor)
+ {
+ case rtfPaperWidth:
+ break;
+ case rtfPaperHeight:
+ break;
+ case rtfLeftMargin:
+ break;
+ case rtfRightMargin:
+ break;
+ case rtfTopMargin:
+ break;
+ case rtfBottomMargin:
+ break;
+ case rtfFacingPage:
+ break;
+ case rtfGutterWid:
+ break;
+ case rtfDefTab:
+ break;
+ case rtfWidowCtrl:
+ break;
+ case rtfHyphHotZone:
+ break;
+ case rtfFNoteEndSect:
+ break;
+ case rtfFNoteEndDoc:
+ break;
+ case rtfFNoteText:
+ break;
+ case rtfFNoteBottom:
+ break;
+ case rtfFNoteStart:
+ break;
+ case rtfFNoteRestart:
+ break;
+ case rtfPageStart:
+ break;
+ case rtfLineStart:
+ break;
+ case rtfLandscape:
+ break;
+ case rtfFracWidth:
+ break;
+ case rtfNextFile:
+ break;
+ case rtfTemplate:
+ break;
+ case rtfMakeBackup:
+ break;
+ case rtfRTFDefault:
+ break;
+ case rtfRevisions:
+ break;
+ case rtfMirrorMargin:
+ break;
+ case rtfRevDisplay:
+ break;
+ case rtfRevBar:
+ break;
+ }
+}
+
+
+static void SectAttr ()
+{
+ switch (rtfMinor)
+ {
+ case rtfSectDef:
+ break;
+ case rtfNoBreak:
+ break;
+ case rtfColBreak:
+ break;
+ case rtfPageBreak:
+ break;
+ case rtfEvenBreak:
+ break;
+ case rtfOddBreak:
+ break;
+ case rtfPageStarts:
+ break;
+ case rtfPageCont:
+ break;
+ case rtfPageRestart:
+ break;
+ case rtfPageDecimal:
+ break;
+ case rtfPageURoman:
+ break;
+ case rtfPageLRoman:
+ break;
+ case rtfPageULetter:
+ break;
+ case rtfPageLLetter:
+ break;
+ case rtfPageNumLeft:
+ break;
+ case rtfPageNumTop:
+ break;
+ case rtfHeaderY:
+ break;
+ case rtfFooterY:
+ break;
+ case rtfLineModulus:
+ break;
+ case rtfLineDist:
+ break;
+ case rtfLineStarts:
+ break;
+ case rtfLineRestart:
+ break;
+ case rtfLineRestartPg:
+ break;
+ case rtfLineCont:
+ break;
+ case rtfTopVAlign:
+ break;
+ case rtfBottomVAlign:
+ break;
+ case rtfCenterVAlign:
+ break;
+ case rtfJustVAlign:
+ break;
+ case rtfColumns:
+ break;
+ case rtfColumnSpace:
+ break;
+ case rtfColumnLine:
+ break;
+ case rtfENoteHere:
+ break;
+ case rtfTitleSpecial:
+ break;
+ }
+}
+
+
+static void TblAttr ()
+{
+ switch (rtfMinor)
+ {
+ case rtfCellBordBottom:
+ break;
+ case rtfCellBordTop:
+ break;
+ case rtfCellBordLeft:
+ break;
+ case rtfCellBordRight:
+ break;
+ case rtfRowDef:
+ break;
+ case rtfRowLeft:
+ break;
+ case rtfRowRight:
+ break;
+ case rtfRowCenter:
+ break;
+ case rtfRowGapH:
+ break;
+ case rtfRowHt:
+ break;
+ case rtfRowLeftEdge:
+ break;
+ case rtfCellPos:
+ break;
+ case rtfMergeRngFirst:
+ break;
+ case rtfMergePrevious:
+ break;
+ }
+}
+
+
+static void ParAttr ()
+{
+ switch (rtfMinor)
+ {
+ case rtfParDef:
+ break;
+ case rtfStyleNum:
+ break;
+ case rtfQuadLeft:
+ break;
+ case rtfQuadRight:
+ break;
+ case rtfQuadJust:
+ break;
+ case rtfQuadCenter:
+ break;
+ case rtfFirstIndent:
+ break;
+ case rtfLeftIndent:
+ break;
+ case rtfRightIndent:
+ break;
+ case rtfSpaceBefore:
+ break;
+ case rtfSpaceAfter:
+ break;
+ case rtfSpaceBetween:
+ break;
+ case rtfInTable:
+ break;
+ case rtfKeep:
+ break;
+ case rtfKeepNext:
+ break;
+ case rtfSideBySide:
+ break;
+ case rtfPBBefore:
+ break;
+ case rtfNoLineNum:
+ break;
+ case rtfTabPos:
+ break;
+ case rtfTabRight:
+ break;
+ case rtfTabCenter:
+ break;
+ case rtfTabDecimal:
+ break;
+ case rtfTabBar:
+ break;
+ case rtfBorderTop:
+ break;
+ case rtfBorderBottom:
+ break;
+ case rtfBorderLeft:
+ break;
+ case rtfBorderRight:
+ break;
+ case rtfBorderBar:
+ break;
+ case rtfBorderBox:
+ break;
+ case rtfBorderBetween:
+ break;
+ case rtfBorderSingle:
+ break;
+ case rtfBorderThick:
+ break;
+ case rtfBorderShadow:
+ break;
+ case rtfBorderDouble:
+ break;
+ case rtfBorderDot:
+ break;
+ case rtfBorderHair:
+ break;
+ case rtfBorderSpace:
+ break;
+ case rtfLeaderDot:
+ break;
+ case rtfLeaderHyphen:
+ break;
+ case rtfLeaderUnder:
+ break;
+ case rtfLeaderThick:
+ break;
+ }
+}
+
+
+/*
+ Several of the attributes can be turned off with param value
+ of zero (e.g., \b vs. \b0), but since the value of rtfParam
+ is 0 if no param is given, test the text of the token directly.
+*/
+
+static void CharAttr ()
+{
+int turnOn = (rtfTextBuf[rtfTextLen-1] != '0');
+
+ switch (rtfMinor)
+ {
+ case rtfPlain:
+ break;
+ case rtfBold:
+ break;
+ case rtfItalic:
+ break;
+ case rtfStrikeThru:
+ break;
+ case rtfOutline:
+ break;
+ case rtfShadow:
+ break;
+ case rtfSmallCaps:
+ break;
+ case rtfAllCaps:
+ break;
+ case rtfInvisible:
+ break;
+ case rtfFontNum:
+ break;
+ case rtfFontSize:
+ break;
+ case rtfExpand:
+ break;
+ case rtfUnderline:
+ break;
+ case rtfWUnderline:
+ break;
+ case rtfDUnderline:
+ break;
+ case rtfDbUnderline:
+ break;
+ case rtfSuperScript:
+ break;
+ case rtfNoUnderline:
+ break;
+ case rtfSubScript:
+ break;
+ case rtfRevised:
+ break;
+ case rtfForeColor:
+ break;
+ case rtfBackColor:
+ break;
+ }
+}
+
+
+static void PictAttr ()
+{
+ switch (rtfMinor)
+ {
+ case rtfMacQD:
+ break;
+ case rtfWinMetafile:
+ break;
+ case rtfWinBitmap:
+ break;
+ case rtfPicWid:
+ break;
+ case rtfPicHt:
+ break;
+ case rtfPicGoalWid:
+ break;
+ case rtfPicGoalHt:
+ break;
+ case rtfPicScaleX:
+ break;
+ case rtfPicScaleY:
+ break;
+ case rtfPicScaled:
+ break;
+ case rtfPicCropTop:
+ break;
+ case rtfPicCropBottom:
+ break;
+ case rtfPicCropLeft:
+ break;
+ case rtfPicCropRight:
+ break;
+ case rtfPixelBits:
+ break;
+ case rtfBitmapPlanes:
+ break;
+ case rtfBitmapWid:
+ break;
+ case rtfPicBinary:
+ break;
+ }
+}
+
+
+static void FieldAttr ()
+{
+ switch (rtfMinor)
+ {
+ case rtfFieldDirty:
+ break;
+ case rtfFieldEdited:
+ break;
+ case rtfFieldLocked:
+ break;
+ case rtfFieldPrivate:
+ break;
+ }
+}
+
+
+static void TOCAttr ()
+{
+ switch (rtfMinor)
+ {
+ case rtfTOCType:
+ break;
+ case rtfTOCLevel:
+ break;
+ }
+}
+
+
+static void PosAttr ()
+{
+ switch (rtfMinor)
+ {
+ case rtfPosX:
+ break;
+ case rtfPosXCenter:
+ break;
+ case rtfPosXInside:
+ break;
+ case rtfPosXLeft:
+ break;
+ case rtfPosXOutSide:
+ break;
+ case rtfPosXRight:
+ break;
+ case rtfPosY:
+ break;
+ case rtfPosYInline:
+ break;
+ case rtfPosYTop:
+ break;
+ case rtfPosYCenter:
+ break;
+ case rtfPosYBottom:
+ break;
+ case rtfAbsWid:
+ break;
+ case rtfTextDist:
+ break;
+ case rtfRPosMargV:
+ break;
+ case rtfRPosPageV:
+ break;
+ case rtfRPosMargH:
+ break;
+ case rtfRPosPageH:
+ break;
+ case rtfRPosColH:
+ break;
+ }
+}
diff --git a/support/RTF-1_06a1/rtfwc.c b/support/RTF-1_06a1/rtfwc.c
new file mode 100644
index 0000000000..30d58e1cfe
--- /dev/null
+++ b/support/RTF-1_06a1/rtfwc.c
@@ -0,0 +1,131 @@
+/*
+ rtfwc - read rtf input, write word count (actually, char, word
+ and paragraph counts).
+
+ This installs callbacks for the ascii and control token classes.
+ The control class is necessary so that special characters such as
+ \par, \tab, \sect, etc. can be counted.
+
+ Counts paragraphs instead of lines, since the concept of "line"
+ is relatively meaningless.
+
+ It's problematic how to count text in headers and footers, and
+ what to do about tables.
+
+ 04 Feb 91 Paul DuBois dubois@primate.wisc.edu
+
+ 04 Feb 91 V1.0. Created.
+ 27 Feb 91 V1.01. Updated for distribution 1.05.
+ 16 Mar 91 V1.02. Updated for distribution 1.06. Multiple files
+ allowed.
+*/
+
+# include <stdio.h>
+# include "rtf.h"
+
+
+static long chars, tchars = 0;
+static long words, twords = 0;
+static long paras, tparas = 0;
+static long wchars = 0; /* chars in current word */
+
+static void Count ();
+static void Text ();
+static void Control ();
+
+int main (argc, argv)
+int argc;
+char **argv;
+{
+int i;
+
+ --argc;
+ ++argv;
+
+ if (argc == 0)
+ {
+ Count ();
+ printf ("\n");
+ }
+ else
+ {
+ for (i = 0; i < argc; i++)
+ {
+ if (freopen (argv[i], "r", stdin) == NULL)
+ {
+ fprintf (stderr, "Can't open \"%s\"\n",
+ argv[i]);
+ exit (1);
+ }
+ Count ();
+ printf ("\t%s\n", argv[i]);
+ }
+ if (argc > 1) /* multiple files, print totals */
+ printf ("%ld chars\t%ld words\t%ld paragraphs\ttotal\n",
+ tchars, twords, tparas);
+ }
+
+ exit (0);
+}
+
+
+static void Count ()
+{
+ chars = words = paras = wchars = 0;
+
+ RTFInit ();
+
+ /* install counting hooks and process the input stream */
+
+ RTFSetClassCallback (rtfText, Text);
+ RTFSetClassCallback (rtfControl, Control);
+ RTFRead ();
+ printf ("%ld chars\t%ld words\t%ld paragraphs", chars, words, paras);
+ tchars += chars;
+ twords += words;
+ tparas += paras;
+}
+
+static void Text ()
+{
+ ++chars;
+ if (rtfMajor != ' ')
+ ++wchars;
+ else if (wchars > 0)
+ ++words;
+}
+
+
+static void Control ()
+{
+ if (rtfMajor != rtfSpecialChar)
+ return;
+ switch (rtfMinor)
+ {
+ case rtfPage:
+ case rtfSect:
+ case rtfLine:
+ case rtfPar:
+ ++paras;
+ ++chars;
+ if (wchars > 0)
+ {
+ ++words;
+ wchars = 0;
+ }
+ break;
+ case rtfNoBrkSpace:
+ case rtfTab:
+ ++chars;
+ if (wchars > 0)
+ {
+ ++words;
+ wchars = 0;
+ }
+ break;
+ case rtfNoBrkHyphen:
+ ++chars;
+ ++wchars;
+ break;
+ }
+}
diff --git a/support/RTF-1_06a1/trf-charmap.c b/support/RTF-1_06a1/trf-charmap.c
new file mode 100644
index 0000000000..b6dc0f898e
--- /dev/null
+++ b/support/RTF-1_06a1/trf-charmap.c
@@ -0,0 +1,364 @@
+/*
+ trf-charmap.c - Unnecessarily complex routines for mapping special
+ characters in the non-ASCII range (128..255) onto troff equivalents.
+
+ This file may require modification for local troff versions.
+
+ Tries to handle the four different character sets allowed in the
+ RTF specification (ANSI, Macintosh, PC and PCA). That part in itself
+ is easy, but the complexity stems from trying to allow for local
+ variations in troff versions (not all troff's understand the same
+ set of special characters) and for particular macro packages (-me,
+ -me, -ms). The last one is silly at this point since no other part
+ of rtf2troff knows anything about writing macro-package-specific
+ output. Maybe someday.
+
+ SelectFormatterMaps () - selects character maps specific to the given
+ formatter, e.g., xroff, pstroff, eroff.
+ SelectMacPackMaps () - select override maps for the given macro
+ package.
+ SelectCharSetMaps () - select maps for particular character set.
+ CharMapping () - return troff equivalent for a special character.
+*/
+
+# include <stdio.h>
+# include <sys/types.h>
+# include "rtf.h"
+# include "rtf2troff.h"
+
+
+/*
+ Structure for mapping character values >= 128 to troff strings
+ for different character sets.
+
+ The reason char value/string pairs are used instead of a 128-entry
+ table is that while the latter would be faster, it's much easier
+ to build an incomplete table with the former, and the entries don't
+ need to be in any particular order.
+*/
+
+typedef struct CharMap CharMap;
+
+struct CharMap
+{
+ int charVal;
+ char *charStr;
+};
+
+
+/*
+ Structure for associating default and override maps with
+ particular versions of troff.
+*/
+
+# define ansiMap 0
+# define macMap 1
+# define pcMap 2
+# define pcaMap 3
+# define mapTypes 4
+
+typedef struct CharMapTable CharMapTable;
+
+struct CharMapTable
+{
+ char *formatter;
+ CharMap *defCharMap[mapTypes];
+ CharMap *meCharMap[mapTypes];
+ CharMap *mmCharMap[mapTypes];
+ CharMap *msCharMap[mapTypes];
+};
+
+
+/*
+ ANSI char map is taken from Windows 3.0 and Word for
+ Windows 1.1 manuals. Note that these conflict, so there
+ are some guesses.
+ PC char map is taken from Windows 3.0 manual.
+*/
+
+static CharMap ansiCharMap [] =
+{
+ 0x91, "`", /* left curly single quote */
+ 0x92, "'", /* right curly single quote */
+ 0x93, "``", /* left curly double quote */
+ 0x94, "''", /* right curly double quote */
+ 0x95, "o", /* ?? */
+ 0xa2, "\\(ct", /* cent */
+ 0xa6, "|", /* vert. bar */
+ 0xa7, "\\(sc", /* section */
+ 0xa9, "\\(co", /* copyright */
+ 0xab, "<<", /* alternate quote */
+ 0xac, "\\(no", /* not */
+ 0xad, "\\(hy", /* short dash */
+ 0xae, "\\(rg", /* registered */
+ 0xaf, "\\(em", /* long dash */
+ 0xb0, "\\(de", /* degree */
+ 0xb1, "\\(+-", /* plus or minus */
+ 0xb4, "\\(aa", /* acute accent */
+ 0xb5, "\\(*m", /* micro (use greek mu) */
+ 0xbb, ">>", /* alternate end-quote*/
+ 0xbc, "\\(14", /* one-fourth */
+ 0xbd, "\\(12", /* one-half */
+ 0xbe, "\\(34", /* three-fourths */
+ 0xc6, "AE", /* joined A-E */
+ 0xd7, "\\(mu", /* math multiply */
+ 0xdf, "\\(*b", /* German B? (fake with greek beta) */
+ 0xe6, "ae", /* joined a-e */
+ 0xf7, "\\(di", /* divide */
+ 0, NULL
+};
+
+
+static CharMap macCharMap [] =
+{
+ 0xa0, "\\(dg", /* dagger */
+ 0xa1, "\\(de", /* degree */
+ 0xa2, "\\(ct", /* cent */
+ 0xa4, "\\(sc", /* section */
+ 0xa5, "\\(bu", /* bullet */
+ 0xa7, "\\(*b", /* German B? (fake with greek beta) */
+ 0xa8, "\\(rg", /* registered */
+ 0xa9, "\\(co", /* copyright */
+ 0xaa, "(TM)", /* trademark */
+ 0xab, "\\(aa", /* acute accent */
+ 0xad, "\\(!=", /* not equal */
+ 0xae, "AE", /* joined A-E */
+ 0xb0, "\\(if", /* infinity */
+ 0xb1, "\\(+-", /* plus or minus */
+ 0xb2, "\\(<=", /* less than or equal */
+ 0xb3, "\\(>=", /* greater than or equal */
+ 0xb5, "\\(*m", /* micro (use greek mu) */
+ 0xb6, "\\(*d", /* delta */
+ 0xb7, "\\(*S", /* summation (Sigma) */
+ 0xb8, "\\(*P", /* Pi */
+ 0xb9, "\\(*p", /* pi */
+ 0xba, "\\(is", /* integral sign */
+ 0xbd, "\\(*W", /* ohm-sign (greek Omega) */
+ 0xbe, "ae", /* joined a-e */
+ 0xc2, "\\(no", /* not */
+ 0xc3, "\\(sr", /* square root */
+ 0xc5, "\\(ap", /* approximately */
+ 0xc6, "\\(*D", /* Delta */
+ 0xc7, "<<", /* alternate quote */
+ 0xc8, ">>", /* alternate end-quote*/
+ 0xc9, "...", /* ellipsis */
+ 0xca, "\\ ", /* unbreakable space */
+ 0xd0, "\\(hy", /* short dash */
+ 0xd1, "\\(em", /* long dash */
+ 0xd2, "``", /* left curly double quote */
+ 0xd3, "''", /* right curly double quote */
+ 0xd4, "`", /* left curly single quote */
+ 0xd5, "'", /* right curly single quote */
+ 0xd6, "\\(di", /* divide */
+ 0, NULL
+};
+
+
+static CharMap pcCharMap [] =
+{
+ 0x91, "ae", /* joined a-e */
+ 0x9b, "\\(ct", /* cent */
+ 0xa9, "\\(em", /* long dash */
+ 0xaa, "\\(no", /* not */
+ 0xab, "\\(12", /* one-half */
+ 0xac, "\\(14", /* one-fourth */
+ 0xae, "<<", /* alternate quote */
+ 0xaf, ">>", /* alternate end-quote*/
+ 0xf1, "\\(+-", /* plus or minus */
+ 0xf8, "\\(de", /* degree */
+ 0, NULL
+};
+
+
+static CharMap pcaCharMap [] =
+{
+ 0, NULL
+};
+
+
+/*
+ These -me maps are just here for example
+*/
+
+
+static CharMap meAnsiCharMap [] =
+{
+ 0, NULL
+};
+
+
+static CharMap meMacCharMap [] =
+{
+ 0, NULL
+};
+
+
+static CharMap mePcCharMap [] =
+{
+ 0, NULL
+};
+
+
+static CharMap mePcaCharMap [] =
+{
+ 0, NULL
+};
+
+
+static CharMapTable charMapTable [] =
+{
+ {
+ "troff",
+ { ansiCharMap, macCharMap, pcCharMap, pcaCharMap }, /* defaults */
+ { NULL, NULL, NULL, NULL }, /* -me overrides */
+ { NULL, NULL, NULL, NULL }, /* -mm overrides */
+ { NULL, NULL, NULL, NULL } /* -ms overrides */
+ },
+ {
+ "xroff",
+ { ansiCharMap, macCharMap, pcCharMap, pcaCharMap }, /* defaults */
+ { NULL, NULL, NULL, NULL }, /* -me overrides */
+ { NULL, NULL, NULL, NULL }, /* -mm overrides */
+ { NULL, NULL, NULL, NULL } /* -ms overrides */
+ },
+ {
+ "pstroff",
+ { ansiCharMap, macCharMap, pcCharMap, pcaCharMap }, /* defaults */
+ { NULL, NULL, NULL, NULL }, /* -me overrides */
+ { NULL, NULL, NULL, NULL }, /* -mm overrides */
+ { NULL, NULL, NULL, NULL } /* -ms overrides */
+ },
+ {
+ /*
+ This should be the last entry. Do not change it.
+ Put new entries before this one.
+ */
+ NULL
+ }
+};
+
+
+/*
+ curCharMaps points to current entry in character map table.
+ macroMaps points to current set of override maps (default NULL
+ until SelectMacPackMaps() is called). defaultMap points to the
+ default map within curCharMaps (default is the ANSI map).
+ overrideMap points to the map within the macro package override
+ maps (default is the ANSI map after SelectMacPackMaps() is called).
+*/
+
+static CharMapTable *curCharMaps = &charMapTable[0];
+static CharMap **macroMaps = NULL;
+static CharMap *defaultMap = ansiCharMap;
+static CharMap *overrideMap = NULL;
+
+
+void SelectFormatterMaps (name)
+char *name;
+{
+CharMapTable *cmtp;
+
+ for (cmtp = charMapTable; cmtp->formatter != NULL; cmtp++)
+ {
+ if (strcmp (name, cmtp->formatter) == 0)
+ {
+ curCharMaps = cmtp;
+ macroMaps = NULL;
+ defaultMap = curCharMaps->defCharMap[ansiMap];
+ overrideMap = NULL;
+ return;
+ }
+ }
+ fprintf (stderr, "Unknown formatter: %s\n", name);
+ exit (1);
+}
+
+
+void SelectMacPackMaps (name)
+char *name;
+{
+ if (strcmp (name, "-me") == 0)
+ macroMaps = curCharMaps->meCharMap;
+ else if (strcmp (name, "-mm") == 0)
+ macroMaps = curCharMaps->mmCharMap;
+ else if (strcmp (name, "-ms") == 0)
+ macroMaps = curCharMaps->msCharMap;
+ else
+ {
+ fprintf (stderr, "Unknown macro package: %s\n", name);
+ exit (1);
+ }
+ if (macroMaps != NULL)
+ overrideMap = macroMaps[ansiMap];
+}
+
+
+/*
+ mapSet should be an rtfCharSet minor number
+*/
+
+void SelectCharSetMaps (mapSet)
+int mapSet;
+{
+int mapIndex;
+
+ switch (mapSet)
+ {
+ case rtfAnsiCharSet:
+ mapIndex = ansiMap;
+ break;
+ case rtfMacCharSet:
+ mapIndex = macMap;
+ break;
+ case rtfPcCharSet:
+ mapIndex = pcMap;
+ break;
+ case rtfPcaCharSet:
+ mapIndex = pcaMap;
+ break;
+ default:
+ fprintf (stderr, "Unknown charset: %d\n", mapSet);
+ exit (1);
+ }
+ defaultMap = curCharMaps->defCharMap[mapIndex];
+ if (macroMaps != NULL)
+ overrideMap = macroMaps[mapIndex];
+}
+
+
+/*
+ Figure out what string a special (non-ASCII) character should map
+ to. (Determine troff equivalent using "normal" characters.)
+*/
+
+static char *_CharMapping (c, map)
+int c;
+CharMap *map;
+{
+CharMap *cmp;
+char *p = NULL;
+
+ for (cmp = map; cmp->charStr != NULL; cmp++)
+ {
+ if (c == cmp->charVal)
+ {
+ p = cmp->charStr;
+ break;
+ }
+ }
+ return (p);
+}
+
+
+char *CharMapping (c)
+int c;
+{
+CharMap *cmp;
+char *p = NULL;
+
+ if (overrideMap != NULL)
+ p = _CharMapping (c, overrideMap);
+ if (p == NULL && defaultMap != NULL)
+ p = _CharMapping (c, defaultMap);
+ return (p != NULL ? p : "<<UNKNOWN>>");
+}
diff --git a/support/RTF-1_06a1/trf-flush.c b/support/RTF-1_06a1/trf-flush.c
new file mode 100644
index 0000000000..238f58689b
--- /dev/null
+++ b/support/RTF-1_06a1/trf-flush.c
@@ -0,0 +1,1157 @@
+/*
+ trf-flush.c - state and content text flushing
+
+ Eventually, all output will end up being flushed through one
+ or two low-level routines, which will allow better trapping
+ on conditions such as initial state needing to be dumped,
+ diversions needing to be started, trap positions needing to
+ be flushed, etc. Maybe in 1.06a2.
+*/
+
+# include <stdio.h>
+# include <sys/types.h>
+# ifdef VARARGS
+# include <varargs.h>
+# endif /* VARARGS */
+# include "rtf.h"
+# include "rtf2troff.h"
+
+
+static int initialStateFlushed = 0;
+
+static int useInLine = 0; /* non-zero for inline char state changes */
+static char inLineChgs[rtfBufSiz] = "";
+
+/*
+ Whether any content text chars have been written to current
+ paragraph.
+*/
+
+static int inPara = 0;
+static int oLen = 0;
+static int breakOK = 0;
+
+
+static void FlushDocState ();
+static void FlushParState ();
+static void FlushCharState ();
+static void FlushSACharState ();
+static void Continuation ();
+static void CalcInLineChanges ();
+static void _PutS ();
+static char *ApplyIndirection ();
+
+static void DrawLine ();
+static char *TabTypeStr ();
+static char *JustTypeStr ();
+static void CheckVMargins ();
+static double LineLen ();
+
+
+/*
+ Flush any discrepancies between state as written and current
+ internal state to bring the former in sync with the latter.
+
+ Virtually all formatting text is written by this operation.
+
+ It's assumed here, perhaps unfortunately, that things needing
+ a Flush() first won't occur in the middle of output line
+ collection.
+*/
+
+void FlushState ()
+{
+ /* flush */
+ FlushInitialState ();
+ if (docStateChanged)
+ FlushDocState ();
+ /* header/footer depend on some doc properties */
+ if (docStateChanged || sectStateChanged)
+ FlushSectState ();
+ /* para line length depends on some doc properties; ditto tabs */
+ if (docStateChanged || parStateChanged)
+ FlushParState ();
+ if (charStateChanged)
+ FlushCharState ();
+
+ /* sync */
+ if (docStateChanged)
+ bcopy ((char *) ids, (char *) wds, (int) sizeof (DocState));
+ if (sectStateChanged)
+ bcopy ((char *) iss, (char *) wss, (int) sizeof (SectState));
+ if (parStateChanged)
+ bcopy ((char *) ips, (char *) wps, (int) sizeof (ParState));
+ if (charStateChanged)
+ bcopy ((char *) ics, (char *) wcs, (int) sizeof (CharState));
+
+ docStateChanged = 0;
+ sectStateChanged = 0;
+ parStateChanged = 0;
+ charStateChanged = 0;
+}
+
+
+/*
+ This is called at the beginning of output to write out absolute
+ initial values for some important state stuff. The other
+ state-writers usually write values relative to the last written
+ values, so this is needed to write absolute values that the
+ relative values can be relative *to*.
+
+ Problem: it's important to avoid tripping the first pseudo-page
+ transition, or the header for the first page will be lost. This
+ occurs when non-diverted text processing occurs or when a number
+ of different requests (e.g., .in) occur. Header/footer text
+ processingn occurs in diversions, so that's not a problem. To
+ avoid tripping the trap with requests, use things like 'in instead
+ of .in. Losing a break isn't a problem since there's no content
+ text to write yet.
+
+ The page length is written early and header/footer traps are
+ planted. These traps stay intact. At most, the footer trap
+ position might be moved.
+
+ Tp is non-zero if a section's title page is special.
+
+ Macros Ha, Hf, Hl and Hr are defined if/when all-page, first-page,
+ left-page and right-page headers are given, and the number registers
+ of the same name, which initially have value zero, are set to 1.
+ Similarly for footers. The register Tm defines the top margins.
+ The registers Hp and Fp define the header and footer positions.
+
+ HE, FO need are written to exit if there are trap loops and
+ to not space too much if vertical margins are weird.
+*/
+
+void FlushInitialState ()
+{
+ if (initialStateFlushed)
+ return;
+
+ Comment ("begin initial layout setup, change as desired");
+
+ /* check whether it appears landscape *should have* been selected */
+ if (ids->pageHeight < ids->pageWidth && !ids->landscape)
+ {
+ fprintf (stderr, "Turning landscape on\n");
+ ids->landscape = 1;
+ }
+
+ if (ids->landscape)
+ {
+ if (tvers == XROFF)
+ fprintf (f, ".dc landscape\n");
+ /* reverse page height and width? */
+ }
+ fprintf (f, ".pl %gi\n", ids->pageHeight);
+ if (tvers == XROFF)
+ {
+ double pLen;
+
+ /* have to tell printer the page length in 300dpi units */
+ /* if not default 11in (this is orientation dependent) */
+ if (ids->landscape)
+ pLen = ids->pageWidth;
+ else
+ pLen = ids->pageHeight;
+ if (pLen != 11.0)
+ fprintf (f, ".dc length %d\n", (int) (pLen * 300));
+ }
+
+ /* abandon hope, all ye who who enter here to try to read this... */
+
+ fprintf (f, ".ad %s\n", JustTypeStr (ips->justification));
+ fprintf (f, ".po %gi\n", ids->leftMargin);
+ fprintf (f, "'in %gi\n", ips->leftIndent); /* ' to avoid break */
+ fprintf (f, ".ll %gi\n", LineLen (ids, ips));
+ fprintf (f, ".ps %d\n", ics->fontSize);
+ Comment ("%gi = %gp", ips->spaceBetween, ips->spaceBetween * 72);
+ fprintf (f, ".vs %gi\n", ips->spaceBetween);
+ fprintf (f, ".ft R\n");
+
+ /* plant traps */
+
+ Comment ("plant header trap");
+ fprintf (f, ".nr %s %d\n", rTitlePageSpecial, iss->titleSpecial);
+ fprintf (f, ".nr %s %gi\n", rTopMargin, ids->topMargin);
+ fprintf (f, ".nr %s %gi\n", rHeaderPos, iss->headerPos);
+ fprintf (f, ".nr %s 0\n", rHeaderAll);
+ fprintf (f, ".nr %s 0\n", rHeaderFirst);
+ fprintf (f, ".nr %s 0\n", rHeaderLeft);
+ fprintf (f, ".nr %s 0\n", rHeaderRight);
+ fprintf (f, ".de %s\n", mHeader);
+ fprintf (f, ".if \\\\n(%s>=\\\\n(Bm \\{\\\n",
+ rTopMargin, rBottomMargin);
+ fprintf (f, ".\ttm Trap Loop Death detected...\n");
+ fprintf (f, ".\tex\n");
+ fprintf (f, ".\\}\n");
+ fprintf (f, ".rs\n");
+ fprintf (f, ".if \\\\n(%s<\\\\n(%s 'sp |\\\\n(%su\n",
+ rHeaderPos, rTopMargin, rHeaderPos);
+ fprintf (f, ".ev 1\n");
+ /*fprintf (f, ".nf\n"); /* correct? */
+ /* ugly stuff to select correct header text macro */
+ fprintf (f, ".ie (\\\\n%%=1&\\\\n(%s>0&\\\\n(%s>0) .%s\n",
+ rHeaderFirst, rTitlePageSpecial, mHeaderFirst);
+ fprintf (f, ".el \\{\\\n");
+ fprintf (f, ". ie \\\\n(%s>0 \\{\\\n", rHeaderLeft);
+ fprintf (f, ". ie o .%s\n", mHeaderRight);
+ fprintf (f, ". el .%s\n", mHeaderLeft);
+ fprintf (f, ". \\}\n");
+ fprintf (f, ". el .if \\\\n(%s>0 .%s\n", rHeaderAll, mHeaderAll);
+ fprintf (f, ".\\}\n");
+ /* end ugly stuff */
+ fprintf (f, ".ev\n");
+ fprintf (f, "'sp |\\\\n(%su\n", rTopMargin);
+ fprintf (f, ".ns\n");
+ fprintf (f, "..\n");
+ fprintf (f, ".wh 0i %s\n", mHeader);
+
+ Comment ("plant footer trap");
+ fprintf (f, ".nr %s %gi\n",
+ rBottomMargin, ids->pageHeight - ids->bottomMargin);
+ fprintf (f, ".nr %s %gi\n",
+ rFooterPos, ids->pageHeight - iss->footerPos);
+ fprintf (f, ".nr %s 0\n", rFooterAll);
+ fprintf (f, ".nr %s 0\n", rFooterFirst);
+ fprintf (f, ".nr %s 0\n", rFooterLeft);
+ fprintf (f, ".nr %s 0\n", rFooterRight);
+ fprintf (f, ".de %s\n", mFooter);
+ fprintf (f, ".if \\\\n(%s>\\\\n(%s 'sp |\\\\n(%su\n",
+ rFooterPos, rBottomMargin, rFooterPos);
+ fprintf (f, ".ev 1\n");
+ /*fprintf (f, ".nf\n"); /* correct? */
+ /* ugly stuff to select correct footer text macro */
+ fprintf (f, ".ie (\\\\n%%=1&\\\\n(%s>0&\\\\n(%s>0) .%s\n",
+ rFooterFirst, rTitlePageSpecial, mFooterFirst);
+ fprintf (f, ".el \\{\\\n");
+ fprintf (f, ". ie \\\\n(%s>0 \\{\\\n", rFooterLeft);
+ fprintf (f, ". ie o .%s\n", mFooterRight);
+ fprintf (f, ". el .%s\n", mFooterLeft);
+ fprintf (f, ". \\}\n");
+ fprintf (f, ". el .if \\\\n(%s>0 .%s\n", rFooterAll, mFooterAll);
+ fprintf (f, ".\\}\n");
+ /* end ugly stuff */
+ fprintf (f, ".ev\n");
+ fprintf (f, "'bp\n");
+ fprintf (f, "..\n");
+ fprintf (f, ".wh %gi %s\n", -ids->bottomMargin, mFooter);
+
+ Comment ("end initial layout setup");
+
+ /* manually sync everything that was just flushed */
+ wds->bottomMargin = ids->bottomMargin;
+ wds->bottomMargin = ids->bottomMargin;
+ wds->landscape = ids->landscape;
+ wds->leftMargin = ids->leftMargin;
+ wds->leftMargin = ids->leftMargin;
+ wds->pageHeight = ids->pageHeight;
+ wds->pageWidth = ids->pageWidth;
+ wds->rightMargin = ids->rightMargin;
+ wds->topMargin = ids->topMargin;
+ wss->footerPos = iss->footerPos;
+ wss->headerPos = iss->headerPos;
+ wss->titleSpecial = iss->titleSpecial;
+ wps->justification = ips->justification;
+ wps->leftIndent = ips->leftIndent;
+ wps->rightIndent = ips->rightIndent;
+ wps->spaceBetween = ips->spaceBetween;
+ wcs->fontSize = ics->fontSize;
+
+ ++initialStateFlushed;
+}
+
+
+/*
+ Note that right margin is document property in RTF, but has the
+ effect of changing line length, which is handled under paragraph
+ property changes. Ditto for change of default tab width.
+*/
+
+static void FlushDocState ()
+{
+ CheckVMargins ();
+ if (ids->landscape != wds->landscape)
+ {
+ /* note: once on, can't turn off */
+ if (ids->landscape) /* it's now on */
+ {
+ Flush ();
+ if (tvers == XROFF)
+ fprintf (f, ".dc landscape\n");
+ }
+ }
+ if (ids->pageHeight != wds->pageHeight)
+ {
+ Flush ();
+ fprintf (f, ".pl %gi\n", ids->pageHeight);
+ if (tvers == XROFF)
+ {
+ double pLen;
+
+ /* have to tell printer the page length in 300dpi units */
+ /* if not default 11in (this is orientation dependent) */
+
+ if (ids->landscape)
+ pLen = ids->pageWidth;
+ else
+ pLen = ids->pageHeight;
+ if (pLen != 11.0)
+ fprintf (f, ".dc length %d\n",
+ (int) (pLen * 300));
+ }
+ }
+ if (ids->leftMargin != wds->leftMargin)
+ {
+ Flush ();
+ fprintf (f, ".po %gi\n", ids->leftMargin);
+ }
+}
+
+
+/*
+ If the top margin or the header or footer positions have
+ changed, redefine the registers giving their sizes. If the
+ bottom margin has changed, move the trap to the right spot.
+ (Document and section state interact here.)
+
+ This is also called when a macro is about to be diverted, so that
+ the trap position isn't set within a different environment.
+ (Is that necessary?)
+
+ The really ugly thing here is to try and catch cases where the
+ header position is set below the top margin, and especially where the
+ footer position *above* the bottom margin. The latter can result
+ in loops where the footer trap is invoked in a loop.
+*/
+
+void FlushSectState ()
+{
+ if (iss->titleSpecial != wss->titleSpecial)
+ {
+ Flush ();
+ fprintf (f, ".nr %s %d\n",
+ rTitlePageSpecial, iss->titleSpecial);
+ }
+ if (ids->topMargin != wds->topMargin)
+ {
+ Flush ();
+ fprintf (f, ".nr %s %gi\n", rTopMargin, ids->topMargin);
+ }
+ if (iss->headerPos != wss->headerPos)
+ {
+ Flush ();
+ fprintf (f, ".nr %s %gi\n", rHeaderPos, iss->headerPos);
+ }
+ if (ids->bottomMargin != wds->bottomMargin)
+ {
+ Flush ();
+ fprintf (f, ".ch %s %gi\n", mHeader, -ids->bottomMargin);
+ }
+ if (iss->footerPos != wss->footerPos)
+ {
+ Flush ();
+ fprintf (f, ".nr %s %gi\n",
+ rFooterPos, ids->pageHeight - iss->footerPos);
+ }
+}
+
+
+static void FlushParState ()
+{
+int tabdiff;
+int i;
+
+ if (ips->justification != wps->justification)
+ {
+ Flush ();
+ fprintf (f, ".ad %s\n", JustTypeStr (ips->justification));
+ }
+ if (ips->leftIndent != wps->leftIndent)
+ {
+ Flush ();
+ fprintf (f, ".in %+gi\n", ips->leftIndent - wps->leftIndent);
+ }
+ /*
+ troff doesn't set right indent, rather it sets
+ line length (function of page width - po - rm - ri)
+ */
+ if (ids->pageWidth != wds->pageWidth
+ || ids->leftMargin != wds->leftMargin
+ || ids->rightMargin != wds->rightMargin
+ || ips->rightIndent != wps->rightIndent)
+ {
+ Flush ();
+ fprintf (f, ".ll %gi\n", LineLen (ids, ips));
+ }
+ if (ips->spaceBetween != wps->spaceBetween)
+ {
+ Flush ();
+ fprintf (f, ".vs %gi\n", ips->spaceBetween);
+ }
+
+ /*
+ Determine if tabs have changed, which they will if there
+ are a different number of tab stops than previously, or any
+ of the current ones are different than those last written
+ out. Change of default width is a change, too.
+ */
+
+ tabdiff = 0;
+ if (ids->tabWidth != wds->tabWidth)
+ tabdiff = 1;
+ else if (ips->nTabs != wps->nTabs)
+ tabdiff = 1;
+ else
+ {
+ for (i = 0; i < ips->nTabs; i++)
+ {
+ if (ips->tab[i] != wps->tab[i]
+ || ips->tabType[i] != wps->tabType[i])
+ {
+ tabdiff = 1;
+ break;
+ }
+ }
+ }
+ if (tabdiff)
+ {
+ Flush ();
+ if (ips->nTabs == 0) /* use defaults */
+ {
+ fprintf (f, ".ta %gi", ids->tabWidth);
+ for (i = 1; i < maxTab; i++)
+ fprintf (f, " +%gi", ids->tabWidth);
+ }
+ else
+ {
+ fprintf (f, ".ta %gi%s", ips->tab[0],
+ TabTypeStr (ips->tabType[0]));
+ for (i = 1; i < ips->nTabs; i++)
+ {
+ fprintf (f, " +%gi%s",
+ ips->tab[i] - ips->tab[i-1],
+ TabTypeStr (ips->tabType[i]));
+ }
+ }
+ fprintf (f, "\n");
+ }
+ if (ips->tabChar != wps->tabChar)
+ {
+ Flush ();
+ switch (ips->tabChar)
+ {
+ case rtfLeaderMotion:
+ fprintf (f, ".tc\n");
+ break;
+ case rtfLeaderDot:
+ fprintf (f, ".tc .\n");
+ break;
+ case rtfLeaderHyphen:
+ fprintf (f, ".tc -\n");
+ break;
+ case rtfLeaderUnder:
+ case rtfLeaderThick:
+ fprintf (f, ".tc _\n");
+ break;
+ }
+ }
+}
+
+
+/*
+ Flush character state. Actually, if useInLine is true, this
+ just calculates the string of inline commands that should be
+ generated, and those are later flushed in PutString ().
+*/
+
+static void FlushCharState ()
+{
+ if (useInLine)
+ CalcInLineChanges ();
+ else
+ FlushSACharState ();
+}
+
+
+/*
+ Flush character state, using standalone requests.
+ If in a paragraph, generates a \c to cause stuff on current line
+ to be joined to next so extraneous space won't end up in the
+ output.
+*/
+static void FlushSACharState ()
+{
+u_long csFontBits, wsFontBits;
+int idiff;
+double ddiff;
+
+ if (ics->fontSize != wcs->fontSize) /* write font size */
+ {
+ Continuation ();
+ idiff = ics->fontSize - wcs->fontSize;
+ fprintf (f, ".ps %+d\n", idiff);
+ }
+ /*
+ Note: super/subscripts don't always have intended effect
+ in non-inline mode. Output may need hand fixing.
+ */
+ if (ics->superScript != wcs->superScript)
+ {
+ Continuation ();
+ ddiff = wcs->superScript - ics->superScript;
+ fprintf (f, "'sp %gp\n", ddiff);
+ }
+ if (ics->subScript != wcs->subScript)
+ {
+ Continuation ();
+ ddiff = ics->subScript - wcs->subScript;
+ fprintf (f, "'sp %gp\n", ddiff);
+ }
+ if (ics->charStyle != wcs->charStyle) /* write R, I, B */
+ {
+ /*
+ Since troff implements plain, bold and italic by
+ changing fonts, figure out whether the font needs
+ to be changed. This doesn't understand simultaneous
+ bold+italic (boo-hoo), and treats it as italic.
+ */
+ csFontBits = StyleFontBits (ics->charStyle);
+ wsFontBits = StyleFontBits (wcs->charStyle);
+ if (csFontBits != wsFontBits)
+ {
+ Continuation ();
+ if (csFontBits == 0) /* neither bold or italic */
+ fprintf (f, ".ft R\n");
+ else if (csFontBits & styleItalic)
+ fprintf (f, ".ft I\n");
+ else if (csFontBits & styleBold)
+ fprintf (f, ".ft B\n");
+ }
+
+ /* if smallcaps now on and wasn't before, turn on */
+ if ((ics->charStyle & styleSmallCaps)
+ && !(wcs->charStyle & styleSmallCaps))
+ {
+ Continuation ();
+ fprintf (f, ".ps -1\n");
+ }
+ /* if smallcaps now off and wasn't before, turn off */
+ if (!(ics->charStyle & styleSmallCaps)
+ && (wcs->charStyle & styleSmallCaps))
+ {
+ Continuation ();
+ fprintf (f, ".ps +1\n");
+ }
+ }
+}
+
+
+static void Continuation ()
+{
+ if (oLen > 0)
+ {
+ if (breakOK)
+ fprintf (f, "\n");
+ else
+ fprintf (f, "\\c\n"); /* need ApplyIndirection() ? */
+ ResetParLine ();
+ }
+}
+
+
+/*
+ Generate a string of inline-changes, which need to be flushed with
+ indirection applied.
+*/
+
+static void CalcInLineChanges ()
+{
+char *picp = inLineChgs;
+int csFontBits, wsFontBits;
+int idiff;
+double ddiff;
+char c;
+
+ *picp = '\0';
+ if (ics->fontSize != wcs->fontSize) /* write font size */
+ {
+ idiff = ics->fontSize - wcs->fontSize;
+ c = '+';
+ if (idiff < 0)
+ {
+ c = '-';
+ idiff *= -1;
+ }
+ while (idiff > 9)
+ {
+ sprintf (picp, "\\s%c9", c);
+ picp += strlen (picp);
+ idiff -= 9;
+ }
+ sprintf (picp, "\\s%c%d", c, idiff);
+ picp += strlen (picp);
+ }
+ if (ics->superScript != wcs->superScript)
+ {
+ ddiff = wcs->superScript - ics->superScript;
+ sprintf (picp, "\\v'%gp'", ddiff);
+ picp += strlen (picp);
+ }
+ if (ics->subScript != wcs->subScript)
+ {
+ ddiff = ics->subScript - wcs->subScript;
+ sprintf (picp, "\\v'%gp'", ddiff);
+ picp += strlen (picp);
+ }
+ if (ics->charStyle != wcs->charStyle) /* write R, I, B */
+ {
+ /*
+ Since troff implements plain, bold and italic by
+ changing fonts, figure out whether the font needs
+ to be changed. This doesn't understand simultaneous
+ bold+italic (boo-hoo), and treats it as italic.
+ */
+ csFontBits = ics->charStyle & (styleBold | styleItalic);
+ wsFontBits = wcs->charStyle & (styleBold | styleItalic);
+ if (csFontBits != wsFontBits)
+ {
+ if (csFontBits == 0) /* neither bold or italic */
+ sprintf (picp, "\\fR");
+ else if (csFontBits & styleItalic)
+ sprintf (picp, "\\fI");
+ else if (csFontBits & styleBold)
+ sprintf (picp, "\\fB");
+ /* this is a NOP if no "if" was triggered above */
+ picp += strlen (picp);
+ }
+
+ /* if smallcaps now on and wasn't before, turn on */
+ if ((ics->charStyle & styleSmallCaps)
+ && !(wcs->charStyle & styleSmallCaps))
+ {
+ sprintf (picp, "\\s-1");
+ picp += strlen (picp);
+ }
+ /* if smallcaps now off and wasn't before, turn off */
+ if (!(ics->charStyle & styleSmallCaps)
+ && (wcs->charStyle & styleSmallCaps))
+ {
+ sprintf (picp, "\\s+1");
+ picp += strlen (picp);
+ }
+ }
+}
+
+
+/*
+ Save font, point size and vertical spacing. Called at beginning
+ of table to get an idea of the values for the parameters that tbl
+ will use at the beginning of each cell. FlushTblFPV() is called
+ after each cell is begin, to undo this if the previous cell ends
+ with some different values, so those values will carry through.
+*/
+
+
+static double vs;
+static int ps;
+static u_long font;
+
+
+void SaveTblFPV ()
+{
+ FlushState (); /* make sure internal state same as written */
+ vs = ips->spaceBetween;
+ ps = ics->fontSize;
+ font = StyleFontBits (ics->charStyle);
+}
+
+
+void FlushTblFPV ()
+{
+u_long curFont;
+
+ if (1 || ips->spaceBetween != vs) /* tbl will have set it to vs, */
+ { /* so set it back */
+ fprintf (f, ".vs %gi\n", ips->spaceBetween);
+ wps->spaceBetween = ips->spaceBetween;
+ }
+ if (1 || ics->fontSize != ps) /* tbl will have... */
+ {
+ fprintf (f, ".ps %d\n", ics->fontSize);
+ wcs->fontSize = ics->fontSize;
+ }
+ curFont = StyleFontBits (ics->charStyle);
+ if (1 || curFont != font) /* tbl will have... */
+ {
+ if (curFont == 0)
+ fprintf (f, ".ft R\n");
+ else if (curFont & styleItalic)
+ fprintf (f, ".ft I\n");
+ else if (curFont & styleBold)
+ fprintf (f, ".ft B\n");
+ /* now the hard part */
+ wcs->charStyle &= ~StyleFontBits (wcs->charStyle);
+ wcs->charStyle |= curFont;
+ }
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+
+void ResetPar ()
+{
+ inPara = 0;
+ ResetParLine ();
+}
+
+
+void ResetParLine ()
+{
+ oLen = 0;
+ breakOK = 0;
+}
+
+
+/*
+ Unconditional flush -- force output line and prevent next line
+ from being joined to it. Also handle any bottom border and
+ "extra space after paragraph" if any is needed.
+*/
+
+void Par ()
+{
+ FlushInitialState ();
+ if (inPara)
+ fprintf (f, "\n.br\n");
+ else
+ fprintf (f, ".sp\n");
+ ResetPar ();
+ if (ips->borderType != rtfNoBorderType
+ && (ips->borderFlags & borderBottom) != 0)
+ {
+ /* draw bottom border */
+ DrawLine (ips->borderType);
+ }
+
+ if (ips->spaceAfter != 0.0)
+ fprintf (f, ".sp %gi\n", ips->spaceAfter);
+
+}
+
+
+void Sect ()
+{
+char *p = NULL;
+char buf[20];
+
+ Par (); /* finish current paragraph */
+ switch (iss->breakType)
+ {
+ case rtfNoBreak:
+ break; /* nothing to do */
+ case rtfColBreak:
+ /* this is untested! */
+ sprintf (buf, ".sp |\\n(%s\n", rBottomMargin);
+ p = buf;
+ break;
+ case rtfPageBreak:
+ p = ".bp";
+ break;
+ case rtfEvenBreak:
+ p = ".if e .bp";
+ break;
+ case rtfOddBreak:
+ p = ".if o .bp";
+ break;
+ }
+ if (p != NULL)
+ {
+ FlushInitialState ();
+ fprintf (f, "%s\n", p);
+ }
+}
+
+/*
+ Document content text writing routines. These should not be
+ used to write out formatting text.
+
+ Flush() force out any collected content text, if any
+ PutString() write out a string of characters
+ PutFunnyChar() map char > 127 onto troff equivalent
+*/
+
+
+void Flush ()
+{
+ if (inPara)
+ {
+ _PutS ("\n");
+ ResetPar ();
+ }
+}
+
+
+/*
+ Dump out a piece of content text. Argument should be a string just
+ as you would write it normally, assuming no levels of indirection.
+
+ Does state flushing, beginning-of-paragraph processing, flushes
+ pending inline changes, and writes out the string (account for levels
+ of indirection).
+
+ Handles underlining if continuous underlining on, or word underlining
+ is on and string isn't " " or "\ ".
+
+ Does *not* do:
+ special char mapping (do before calling)
+ to-caps mapping (ditto)
+
+*/
+
+void PutString (s)
+char *s;
+{
+int doUnderlining = 0;
+int doStrikeThru = 0;
+char *p;
+
+ if (ics->charStyle & styleInvisible)
+ return;
+
+ if (stateChanged)
+ {
+ useInLine = 1;
+ FlushState (); /* clears stateChanged */
+ useInLine = 0;
+ }
+
+ /*
+ It's OK to hang onto inline changes until after this if-block
+ since only paragraph properties are used here; inlines only
+ affect character properties.
+ */
+
+ if (inPara == 0) /* just beginning a paragraph */
+ {
+ if (ips->spaceBefore != 0.0)
+ fprintf (f, ".sp %gi\n", ips->spaceBefore);
+ if (ips->borderType != rtfNoBorderType
+ && (ips->borderFlags & borderTop) != 0)
+ {
+ /* draw top border */
+ DrawLine (ips->borderType);
+ }
+ if (ips->firstIndent != 0.0)
+ fprintf (f, ".ti %gi\n", ips->firstIndent);
+ }
+
+ if (inLineChgs[0] != '\0')
+ {
+ _PutS (ApplyIndirection (inLineChgs));
+ inLineChgs[0] = '\0';
+ }
+
+ /* Break up long output lines. */
+ if (oLen > lineBreakLen && breakOK && s[0] != ' ')
+ _PutS ("\n"); /* (<-- turns breakOK off) */
+
+ /*
+ See if this is a natural breakpoint (single space not
+ at beginning of line). If so, remember it for following
+ characters, so long lines can be broken. If this is
+ a breakpoint, but the previous character was too, then
+ we're seeing multiple whitespace characters, and it's really
+ not a breakpoint, since breaking the line would then result
+ in loss of whitespace when troff joins lines back together
+ (it tosses trailing whitespace; this is only safe when that
+ consists of a single space).
+ */
+
+ if (oLen > 0 && s[0] == ' ' && s[1] == '\0')
+ {
+ if (breakOK)
+ breakOK = 0; /* multiple whitespace; not OK */
+ else
+ breakOK = 1;
+ }
+
+ if (ics->charStyle & styleUnderline)
+ ++doUnderlining;
+ if (ics->charStyle & styleStrikeThru)
+ ++doStrikeThru;
+ else if (ics->charStyle & styleWUnderline)
+ {
+ if (strcmp (s, " ") != 0 && strcmp (s, "\\ ") != 0)
+ ++doUnderlining;
+ }
+ if (doUnderlining || doStrikeThru)
+ {
+ if (oLen > 0) /* force onto own line if necessary */
+ {
+ p = ApplyIndirection ("\\c\n");
+ _PutS (p);
+ }
+ /* mark horizontal position */
+ p = ApplyIndirection ("\\kx");
+ _PutS (p);
+ }
+ p = ApplyIndirection (s);
+ _PutS (p);
+ if (doUnderlining)
+ {
+ /* return to marked position, draw underline */
+ p = ApplyIndirection ("\\l'|\\nxu\\(ul'");
+ _PutS (p);
+ }
+ if (doStrikeThru)
+ {
+ /* return to marked position, draw strikethrough */
+ p = ApplyIndirection ("\\v'-.2v'\\l'|\\nxu-'\\v'.2v'");
+ _PutS (p);
+ }
+
+ inPara = 1;
+}
+
+
+/*
+ Write something to current paragraph, keeping track of last char
+ and number of characters written to current line. Need oLen and
+ breakOK to know when to break output line for readability.
+
+ When a newline is written, oLen is reset.
+
+ When a non-space is written, breakOK is turned off, which handles
+ cases where PutString() saw a single space and thought a natural
+ break was in order, but that space ends up coming out in the middle
+ of control language, such as for underlining.
+*/
+
+static void _PutS (s)
+char *s;
+{
+char c;
+
+ while ((c = *s++) != '\0')
+ {
+ fputc (c, f);
+ if (c == '\n')
+ ResetParLine ();
+ else
+ ++oLen;
+ if (c != ' ')
+ breakOK = 0;
+ }
+}
+
+
+/*
+ Process a string to apply indirection.
+ Level Action
+ 0 \ -> \
+ 1 \ -> \\
+ 2 \ -> \\\\
+
+ Note: returns pointer into static buffer.
+*/
+
+static char *ApplyIndirection (s)
+char *s;
+{
+static char buf[100];
+static char *p, c;
+static int slashCount, i;
+
+ slashCount = 1; /* figure out how many \'s */
+ for (i = 0; i < indirectionLevel; i++) /* one \ maps to */
+ slashCount += slashCount;
+ p = buf;
+ while ((c = *s++) != '\0')
+ {
+ if (c != '\\')
+ *p++ = c;
+ else for (i = 0; i < slashCount; i++)
+ *p++ = '\\';
+ }
+ *p = '\0';
+ return (buf);
+}
+
+
+/*
+ Draw horizontal line. Sets vertical size not to space down very
+ much, then restores. Sets point size big for thick lines, then
+ restores.
+
+ Probably should take current boldface setting into account.
+*/
+
+static void DrawLine (type)
+int type;
+{
+int ps;
+double vs;
+char buf[100], c;
+
+ switch (type)
+ {
+ default:
+ case rtfBorderHair:
+ case rtfBorderSingle:
+ ps = 10;
+ vs = .1;
+ c = '_';
+ break;
+ case rtfBorderThick:
+ case rtfBorderShadow:
+ ps = 36;
+ vs = .3;
+ c = '_';
+ break;
+ case rtfBorderDouble:
+ ps = 5;
+ vs = .3;
+ c = '=';
+ break;
+ case rtfBorderDot:
+ ps = 10;
+ vs = .1;
+ c = '.';
+ break;
+ }
+ Flush ();
+ if (ps != wcs->fontSize) /* change point size if necessary */
+ fprintf (f, ".ps %d\n", ps);
+ fprintf (f, ".vs %gi\n", vs);
+ sprintf (buf, "\\l'%gi\\&%c'", LineLen (ids, ips), c);
+ fprintf (f, "%s\n", ApplyIndirection (buf));
+ fprintf (f, ".br\n");
+ fprintf (f, ".vs\n"); /* restore */
+ if (ps != wcs->fontSize) /* restore if was changed */
+ fprintf (f, ".ps\n");
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ Miscellaneous stuff
+*/
+
+
+static char *TabTypeStr (type)
+int type;
+{
+char *p = ""; /* assume left justified (default) */
+
+ switch (type)
+ {
+ case rtfTabDecimal: /* <- act like right tab, oh, well... */
+ case rtfTabRight: p = "R"; break;
+ case rtfTabCenter: p = "C"; break;
+ }
+ return (p);
+}
+
+
+static char *JustTypeStr (type)
+int type;
+{
+char *p = "l"; /* default if unrecognized */
+
+ switch (type)
+ {
+ default: /* <- if unrecognized */
+ case rtfQuadLeft:
+ p = "l";
+ break;
+ case rtfQuadRight:
+ p = "r";
+ break;
+ case rtfQuadCenter:
+ p = "c";
+ break;
+ case rtfQuadJust:
+ p = "b";
+ break;
+ }
+ return (p);
+}
+
+
+/*
+ Check vertical margins. Constraints:
+
+ Top margin should not extend to or below bottom margin
+ Top margin should be below header margin
+ Bottom margin MUST be above top margin (or Trap Loop Death will occur)
+*/
+
+static void CheckVMargins ()
+{
+ if (ids->topMargin + ids->bottomMargin >= ids->pageHeight)
+ {
+ fprintf (stderr, "Top margin is below bottom margin. Yow!\n");
+ exit (1);
+ }
+}
+
+
+static double LineLen (docState, parState)
+DocState *docState;
+ParState *parState;
+{
+ return (docState->pageWidth
+ - (docState->leftMargin + docState->rightMargin)
+ - parState->rightIndent);
+}
+
+
+/*
+ Comment - dump a comment to the output. The .\" and \n at
+ beginning and end are supplied automatically.
+*/
+
+
+# ifdef VARARGS
+
+/*
+ This version is for systems that have varargs.
+*/
+
+void
+Comment (va_alist)
+va_dcl
+{
+va_list args;
+char *fmt;
+
+ Flush ();
+ fprintf (f, ".\\\" ");
+ va_start (args);
+ fmt = va_arg (args, char *);
+ vfprintf (f, fmt, args);
+ va_end (args);
+ fprintf (f, "\n");
+}
+
+# else /* !VARARGS */
+
+/*
+ This version is for systems that don't have varargs.
+*/
+
+void
+Comment (fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
+char *fmt;
+char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8, *a9;
+{
+ Flush ();
+ fprintf (f, ".\\\" ");
+ fprintf (f, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+ fprintf (f, "\n");
+}
+
+# endif /* VARARGS */
diff --git a/support/RTF-1_06a1/trf-nwid.c b/support/RTF-1_06a1/trf-nwid.c
new file mode 100644
index 0000000000..0f71c1efb2
--- /dev/null
+++ b/support/RTF-1_06a1/trf-nwid.c
@@ -0,0 +1,91 @@
+/*
+ trf-nwid.c - routine to try to figure out the width of an en
+ in the current point size. This is used by the table writing
+ code in an attempt to get cells the right width.
+
+ If you're trying to figure out widths for another version of
+ troff, run nwidth.trf through it and look at the result.
+*/
+
+# include <stdio.h>
+# include <sys/types.h>
+# include "rtf.h"
+# include "rtf2troff.h"
+
+typedef struct EnVal EnVal;
+
+struct EnVal
+{
+ int size;
+ double width;
+};
+
+# define uXroff 300.0 /* xroff dpi */
+
+EnVal enXroff [] =
+{
+ 3, 9./uXroff, /* xroff uses 4 */
+ 4, 9./uXroff,
+ 5, 11./uXroff,
+ 6, 13./uXroff,
+ 7, 16./uXroff,
+ 8, 18./uXroff,
+ 9, 20./uXroff,
+ 10, 22./uXroff,
+ 11, 25./uXroff,
+ 12, 27./uXroff,
+ 13, 29./uXroff,
+ 14, 31./uXroff,
+ 15, 34./uXroff,
+ 16, 36./uXroff,
+ 17, 36./uXroff, /* xroff uses 16 */
+ 18, 40./uXroff,
+ 19, 40./uXroff, /* xroff uses 18 */
+ 20, 45./uXroff,
+ 22, 45./uXroff, /* xroff uses 20 */
+ 24, 54./uXroff,
+ 26, 54./uXroff, /* xroff uses 24
+ 28, 63./uXroff,
+ 30, 67./uXroff,
+ 32, 67./uXroff, /* xroff uses 0?!? Use 30 instead */
+ 34, 67./uXroff, /* xroff uses 0?!? Use 30 instead */
+ 36, 81./uXroff,
+ 38, 81./uXroff, /* xroff uses 36 */
+ 40, 81./uXroff, /* xroff uses 36
+ 44, 107./uXroff, /* xroff uses 48 */
+ 48, 107./uXroff,
+ 72, 107./uXroff, /* xroff uses 48 */
+ 0, 50./uXroff /* 0 = end of table; 50 = default size */
+};
+
+
+static double EVTabLookup ();
+
+
+static double EVTabLookup (tab)
+EnVal tab[];
+{
+int ps = ics->fontSize;
+EnVal *p;
+
+ for (p = tab; p->size != 0; p++)
+ {
+ if (p->size >= ps)
+ return (p->width);
+ }
+ return (p->width); /* use last width as default */
+}
+
+
+double EnWidth ()
+{
+ /*
+ Our tpscript uses 720 as resolution base, and character
+ sizes are 5 times the point size.
+ */
+ if (tvers == PSTROFF)
+ return (ics->fontSize * 5. / 720.);
+
+ /* default - covers troff and xroff */
+ return (EVTabLookup (enXroff));
+}
diff --git a/support/RTF-1_06a1/trf-stack.c b/support/RTF-1_06a1/trf-stack.c
new file mode 100644
index 0000000000..2179b0ddd0
--- /dev/null
+++ b/support/RTF-1_06a1/trf-stack.c
@@ -0,0 +1,263 @@
+/*
+ trf-stack.c - internal and written stack operations.
+*/
+
+# include <stdio.h>
+# include <sys/types.h>
+# include "rtf.h"
+# include "rtf2troff.h"
+
+
+static int iTopState = 0; /* current internal state */
+static State iState[maxIStack] = /* internal state stack */
+{
+/*
+ state 0 = initial state.
+*/
+ rtfNoDestination, /* destination */
+ {
+ 0, /* landscape (0 = no) */
+ 12240.0/rtfTpi, /* paper width = 8.5i*/
+ 15840.0/rtfTpi, /* paper height = 11i */
+ 1800.0/rtfTpi, /* left margin = 1.25i */
+ 1800.0/rtfTpi, /* right margin = 1.25i */
+ 1440.0/rtfTpi, /* top margin = 1i */
+ 1440.0/rtfTpi, /* bottom margin = 1i */
+ 720.0/rtfTpi /* tab width = .5i */
+ },
+ {
+ rtfPageBreak, /* section break type */
+ 1, /* starting page number */
+ 0, /* continuous page numbering */
+ 1080.0/rtfTpi, /* header position */
+ 1080.0/rtfTpi, /* footer position */
+ 0 /* title page not special */
+ },
+ {
+ 0, /* first indent */
+ 0, /* left indent */
+ 0, /* right indent */
+ 0, /* space before */
+ 0, /* space after */
+ .2, /* space between: 12p * 1.2 = 14.4p */
+ 0, /* no tabs set yet */
+ 0, /* number of tabs */
+ { 0 }, /* tab positions */
+ { 0 }, /* tab types */
+ rtfLeaderMotion, /* tab character */
+ rtfQuadLeft, /* justification */
+ rtfNoBorderType, /* no border */
+ 0 /* draw border nowhere */
+ },
+ {
+ 12, /* font size */
+ 0, /* char style (plain, DON'T CHANGE) */
+ 0, /* superscript */
+ 0 /* subscript */
+ }
+};
+
+
+static int wTopState = 0; /* current written state */
+static State wState[maxWStack]; /* written state stack */
+
+
+/*
+ Set up pointers into internal state 0, and equate initial written
+ state to internal state (although written state isn't actually
+ written until FlushInitialState()).
+
+ Initialize the tab type array to left tabs, so that any tab
+ positions specified without a type will default to left-justified.
+*/
+
+void InitState ()
+{
+ is = &iState[0];
+ /* initialize state 0 */
+ ids = &is->docState;
+ iss = &is->sectState;
+ ips = &is->parState;
+ ics = &is->charState;
+ ips->tabFlag = 0;
+ InitTabSet ();
+ /* sync written state to internal state */
+ bcopy ((char *) &iState[0], (char *) &wState[0], (int) sizeof (State));
+ ws = &wState[0];
+ wds = &ws->docState;
+ wss = &ws->sectState;
+ wps = &ws->parState;
+ wcs = &ws->charState;
+}
+
+
+void CheckFinalState ()
+{
+ if (iTopState != 0)
+ fprintf (stderr, "Warning: unbalanced brace level\n");
+ if (wTopState != 0)
+ fprintf (stderr, "Warning: unrestored environment\n");
+ if (indirectionLevel > 0)
+ fprintf (stderr, "Warning: unrestored indirection\n");
+}
+
+
+/*
+ Push or pop internal state.
+
+ On push, initial value of new state is same as current state, so
+ no state *change* is involved. Indicate that no destination or
+ tab stops have been specified.
+
+ On pop, revert to previous state. It's just laziness to set the
+ state change variables on a state pop, since some or all of them
+ may well not have changed at all... but it's safest and easiest
+ to do so.
+*/
+
+
+void PushIState ()
+{
+ if (iTopState >= maxIStack - 1)
+ {
+ fprintf (stderr, "Internal state stack limit exceeded");
+ fprintf (stderr, " maximum level (%d)\n", maxIStack);
+ exit (1);
+ }
+ bcopy ((char *) &iState[iTopState],
+ (char *) &iState[iTopState + 1], (int) sizeof (State));
+ is = &iState[++iTopState];
+ is->destination = rtfNoDestination;
+ is->parState.tabFlag = 0; /* no tabs set in state yet */
+ ids = &is->docState;
+ iss = &is->sectState;
+ ips = &is->parState;
+ ics = &is->charState;
+}
+
+
+void PopIState ()
+{
+ if (iTopState < 1)
+ {
+ fprintf (stderr, "Pop error: no internal state to pop");
+ fprintf (stderr, " maximum level (%d)\n", maxIStack);
+ exit (1);
+ }
+ is = &iState[--iTopState];
+ ids = &is->docState;
+ iss = &is->sectState;
+ ips = &is->parState;
+ ics = &is->charState;
+ ++docStateChanged;
+ ++sectStateChanged;
+ ++parStateChanged;
+ ++charStateChanged;
+}
+
+
+void PushWState ()
+{
+ if (wTopState >= maxWStack - 1)
+ {
+ fprintf (stderr, "Written state stack limit exceeded");
+ fprintf (stderr, " maximum level (%d)\n", maxWStack);
+ exit (1);
+ }
+ bcopy ((char *) &wState[wTopState],
+ (char *) &wState[wTopState + 1], (int) sizeof (State));
+ ws = &wState[++wTopState];
+ wds = &ws->docState;
+ wss = &ws->sectState;
+ wps = &ws->parState;
+ wcs = &ws->charState;
+}
+
+
+void PopWState ()
+{
+ if (wTopState < 1)
+ {
+ fprintf (stderr, "Pop error: no written state to pop");
+ fprintf (stderr, " maximum level (%d)\n", maxWStack);
+ exit (1);
+ }
+ ws = &wState[--wTopState];
+ wds = &ws->docState;
+ wss = &ws->sectState;
+ wps = &ws->parState;
+ wcs = &ws->charState;
+ ++docStateChanged;
+ ++sectStateChanged;
+ ++parStateChanged;
+ ++charStateChanged;
+}
+
+
+/*
+ Environment switching routines. When commands are written
+ to switch environments, take snapshot of current written state.
+ When environment switches back, restore to snapshot state to
+ reflect the troff state switch.
+
+ Environment switches are saved only when diversions are collected,
+ not when they are written out.
+*/
+
+
+void BeginDiversion (name)
+char *name;
+{
+ Flush ();
+ fprintf (f, ".rm %s\n.di %s\n", name, name);
+ ++indirectionLevel;
+ fprintf (f, ".ev 1\n");
+ PushWState ();
+}
+
+
+void EndDiversion ()
+{
+ Flush ();
+ fprintf (f, ".br\n");
+ fprintf (f, ".ev\n");
+ PopWState ();
+ fprintf (f, ".di\n");
+ --indirectionLevel;
+}
+
+
+/*
+ Restore section, paragraph or character defaults, using
+ values stored in state 0.
+
+ Paragraph defaults are restored by using the state 0 values,
+ they applying the "Normal" style (style 0). The tab flag is reset
+ before expanding the style so any inherited tabs will be overridden
+ by tabs in the style, and reset after expansion so any tabs in the
+ paragraph itself will override inherited or style tabs.
+*/
+
+
+void RestoreSectDefaults ()
+{
+ bcopy ((char *) &iState[0].sectState, (char *) iss,
+ (int) sizeof (SectState));
+}
+
+
+void RestoreParDefaults ()
+{
+ bcopy ((char *) &iState[0].parState, (char *) ips,
+ (int) sizeof (ParState));
+ ips->tabFlag = 0;
+ RTFExpandStyle (0);
+ ips->tabFlag = 0;
+}
+
+
+void RestoreCharDefaults ()
+{
+ bcopy ((char *) &iState[0].charState, (char *) ics,
+ (int) sizeof (CharState));
+}
diff --git a/support/RTF-1_06a1/trf-table.c b/support/RTF-1_06a1/trf-table.c
new file mode 100644
index 0000000000..1b2164e5e9
--- /dev/null
+++ b/support/RTF-1_06a1/trf-table.c
@@ -0,0 +1,289 @@
+/*
+ trf-table.c - table writing functions
+
+ Ugly ugly ugly.
+*/
+
+# include <stdio.h>
+# include <sys/types.h>
+# include "rtf.h"
+# include "rtf2troff.h"
+
+
+static int CellBorderLocIndex ();
+static int VCellBorderType ();
+static char *VCellBorderStr ();
+static char *HCellBorderStr ();
+
+
+/*
+ Border type tokens *follow* cell border location specifiers.
+*/
+
+void TblAttr ()
+{
+double inch = (double) rtfParam / (double) rtfTpi;
+int i, j, loc;
+
+ switch (rtfMinor)
+ {
+ case rtfCellBordBottom:
+ case rtfCellBordTop:
+ case rtfCellBordLeft:
+ case rtfCellBordRight:
+ if (its->nCells >= maxCell)
+ {
+ fprintf (stderr,
+ "Borders specified for too many cells\n");
+ break;
+ }
+ loc = CellBorderLocIndex (rtfMinor);
+ /*
+ Get border type tokens until non-type token seen,
+ then route non-type token normally.
+ */
+ for (;;)
+ {
+ (void) RTFGetToken ();
+ if (!RTFCheckCM (rtfControl, rtfParAttr)
+ || (rtfMinor != rtfBorderSingle
+ && rtfMinor != rtfBorderThick
+ && rtfMinor != rtfBorderShadow
+ && rtfMinor != rtfBorderDouble
+ && rtfMinor != rtfBorderDot
+ && rtfMinor != rtfBorderHair))
+ break;
+ if (its->nCells < maxCell)
+ its->border[its->nCells][loc] = rtfMinor;
+ }
+ RTFRouteToken (); /* send non-border through router */
+ break;
+ case rtfRowDef:
+ its->tableHeader = 0;
+ its->nCells = 0;
+ its->curCell = 0;
+ for (i = 0; i < maxCell; i++)
+ {
+ its->cellPos[i] = 0;
+ for (j = 0; j < 4; j++)
+ its->border[i][j] = rtfNoBorderType;
+ }
+ its->tableLeft = 0;
+ its->cellGap = 0;
+ break;
+ case rtfRowLeft:
+ break;
+ case rtfRowRight:
+ break;
+ case rtfRowCenter:
+ break;
+ case rtfRowGapH:
+ its->cellGap = inch;
+ break;
+ case rtfRowHt:
+ break;
+ case rtfRowLeftEdge:
+ its->tableLeft = inch;
+ break;
+ case rtfCellPos:
+ if (its->nCells >= maxCell)
+ fprintf (f, "max. table row cell count (%d) exceeded\n",
+ maxCell);
+ else
+ its->cellPos[its->nCells++] = inch;
+ break;
+ case rtfMergeRngFirst:
+ break;
+ case rtfMergePrevious:
+ break;
+ }
+}
+
+
+void BeginTbl ()
+{
+int i, n;
+double cwid;
+char *p;
+
+ Flush ();
+ FlushState ();
+ SaveTblFPV (); /* save current font, ps, vs */
+ fprintf (f, ".TS\n");
+ fprintf (f, "center tab(^);\n");
+ for (i = 0; i < its->nCells; i++)
+ {
+ if ((p = VCellBorderStr (VCellBorderType (i))) != NULL)
+ fprintf (f, "%s ", p);
+ cwid = its->cellPos[i];
+ if (i > 0)
+ cwid -= its->cellPos[i-1];
+ cwid -= EnWidth ();
+ fprintf (f, "l1w(%gi) ", cwid);
+ }
+ if ((p = VCellBorderStr (VCellBorderType (its->nCells))) != NULL)
+ fprintf (f, "%s ", p);
+ fprintf (f, ".\n");
+ ++its->tableHeader;
+
+ /* print top borders */
+ n = 0;
+ for (i = 0; i < its->nCells; i++)
+ {
+ if (its->border[i][topIndex] != rtfNoBorderType)
+ ++n;
+ }
+ if (n > 0)
+ {
+ for (i = 0; i < its->nCells; i++)
+ {
+ if (i > 0)
+ fprintf (f, "^");
+ if ((p = HCellBorderStr (its->border[i][topIndex]))
+ != NULL)
+ fprintf (f, "%s", p);
+ }
+ fprintf (f, "\n");
+ }
+}
+
+
+void EndTbl ()
+{
+int i, n;
+char *p;
+
+ /* print bottom borders */
+ n = 0;
+ for (i = 0; i < its->nCells; i++)
+ {
+ if (its->border[i][bottomIndex] != rtfNoBorderType)
+ ++n;
+ }
+ if (n > 0)
+ {
+ for (i = 0; i < its->nCells; i++)
+ {
+ if (i > 0)
+ fprintf (f, "^");
+ if ((p = HCellBorderStr (its->border[i][bottomIndex]))
+ != NULL)
+ fprintf (f, "%s", p);
+ }
+ fprintf (f, "\n");
+ }
+ fprintf (f, ".TE\n"); /* this undoes ps/vs... */
+ FlushTblFPV (); /* so redo it. ugh. */
+ FlushState ();
+ its->tableHeader = 0;
+ its->curCell = 0;
+}
+
+
+/*
+ BeginCell() called when first \intbl in row is seen and after
+ each \cell; EndCell() called whenever \cell or \row are seen.
+ These do nothing if the cell number is greater than would be
+ expected given the number of cell positions found in the table
+ layout information. (It *is* possible to find information
+ beyond the last cell; Word for Macintosh, at least, seems to put an
+ empty cell at the end of each row.)
+*/
+
+void BeginCell ()
+{
+ /* accept cells 0..nCells-1 */
+ if (its->curCell < its->nCells)
+ {
+ Flush ();
+ fprintf (f, "T{\n");
+ /*FlushState ();*/
+ FlushTblFPV (); /* set up correct font, ps, vs */
+ }
+ inTable = 1;
+}
+
+
+void EndCell ()
+{
+ Flush ();
+ /* accept cells 0..nCells-1 */
+ if (its->curCell < its->nCells)
+ {
+ fprintf (f, "T}");
+ }
+ ++its->curCell;
+ if (its->curCell < its->nCells)
+ fprintf (f, "^"); /* more cells to go */
+ else if (its->curCell == its->nCells)
+ fprintf (f, "\n"); /* no more cells to go */
+ inTable = 0;
+}
+
+
+static int CellBorderLocIndex (loc)
+int loc;
+{
+ switch (loc)
+ {
+ case rtfCellBordLeft: return (leftIndex);
+ case rtfCellBordRight: return (rightIndex);
+ case rtfCellBordTop: return (topIndex);
+ case rtfCellBordBottom: return (bottomIndex);
+ }
+ fprintf (stderr, "CellBorderLocIndex: bad argument (%d)\n", loc);
+ exit (1);
+}
+
+
+/*
+ Determine vertical border for left of cell i. Takes into account
+ right border of i-1 and left border of i, with the latter taking
+ precedence. Two special cases are handled implicitly in code
+ below. When i = 0, return left border of cell 0. When i = nCells,
+ return right border of cell nCells-1.
+*/
+
+static int VCellBorderType (i)
+int i;
+{
+int border = rtfNoBorderType;
+
+ if (i >= 0 && i < its->nCells)
+ border = its->border[i][leftIndex];
+ if (i > 0 && i <= its->nCells && border == rtfNoBorderType)
+ border = its->border[i-1][rightIndex];
+ return (border);
+}
+
+
+static char *VCellBorderStr (type)
+int type;
+{
+ switch (type)
+ {
+ case rtfBorderShadow:
+ case rtfBorderThick:
+ case rtfBorderDot:
+ case rtfBorderHair:
+ case rtfBorderSingle: return ("|");
+ case rtfBorderDouble: return ("||");
+ }
+ return (NULL);
+}
+
+
+static char *HCellBorderStr (type)
+int type;
+{
+ switch (type)
+ {
+ case rtfBorderShadow:
+ case rtfBorderThick:
+ case rtfBorderDot:
+ case rtfBorderHair:
+ case rtfBorderSingle: return ("_");
+ case rtfBorderDouble: return ("=");
+ }
+ return (NULL);
+}