From e0c6872cf40896c7be36b11dcc744620f10adf1d Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Mon, 2 Sep 2019 13:46:59 +0900 Subject: Initial commit --- support/RTF-1_06a1/1.05-changes | 132 ++++ support/RTF-1_06a1/1.06-changes | 67 ++ support/RTF-1_06a1/Imakefile | 105 +++ support/RTF-1_06a1/Makefile | 425 ++++++++++++ support/RTF-1_06a1/Notes | 43 ++ support/RTF-1_06a1/Porting | 30 + support/RTF-1_06a1/README | 67 ++ support/RTF-1_06a1/nwidth.trf | 40 ++ support/RTF-1_06a1/reader.c | 1380 ++++++++++++++++++++++++++++++++++++++ support/RTF-1_06a1/rtf-misc.ms | 203 ++++++ support/RTF-1_06a1/rtf.h | 484 +++++++++++++ support/RTF-1_06a1/rtf.ms | 896 +++++++++++++++++++++++++ support/RTF-1_06a1/rtf2null.c | 55 ++ support/RTF-1_06a1/rtf2text.c | 264 ++++++++ support/RTF-1_06a1/rtf2troff.c | 1140 +++++++++++++++++++++++++++++++ support/RTF-1_06a1/rtf2troff.h | 289 ++++++++ support/RTF-1_06a1/rtf2troff.ms | 649 ++++++++++++++++++ support/RTF-1_06a1/rtfdiag.c | 121 ++++ support/RTF-1_06a1/rtfindent.c | 109 +++ support/RTF-1_06a1/rtfskel.c | 801 ++++++++++++++++++++++ support/RTF-1_06a1/rtfwc.c | 131 ++++ support/RTF-1_06a1/trf-charmap.c | 364 ++++++++++ support/RTF-1_06a1/trf-flush.c | 1157 ++++++++++++++++++++++++++++++++ support/RTF-1_06a1/trf-nwid.c | 91 +++ support/RTF-1_06a1/trf-stack.c | 263 ++++++++ support/RTF-1_06a1/trf-table.c | 289 ++++++++ 26 files changed, 9595 insertions(+) create mode 100644 support/RTF-1_06a1/1.05-changes create mode 100644 support/RTF-1_06a1/1.06-changes create mode 100644 support/RTF-1_06a1/Imakefile create mode 100644 support/RTF-1_06a1/Makefile create mode 100644 support/RTF-1_06a1/Notes create mode 100644 support/RTF-1_06a1/Porting create mode 100644 support/RTF-1_06a1/README create mode 100644 support/RTF-1_06a1/nwidth.trf create mode 100644 support/RTF-1_06a1/reader.c create mode 100644 support/RTF-1_06a1/rtf-misc.ms create mode 100644 support/RTF-1_06a1/rtf.h create mode 100644 support/RTF-1_06a1/rtf.ms create mode 100644 support/RTF-1_06a1/rtf2null.c create mode 100644 support/RTF-1_06a1/rtf2text.c create mode 100644 support/RTF-1_06a1/rtf2troff.c create mode 100644 support/RTF-1_06a1/rtf2troff.h create mode 100644 support/RTF-1_06a1/rtf2troff.ms create mode 100644 support/RTF-1_06a1/rtfdiag.c create mode 100644 support/RTF-1_06a1/rtfindent.c create mode 100644 support/RTF-1_06a1/rtfskel.c create mode 100644 support/RTF-1_06a1/rtfwc.c create mode 100644 support/RTF-1_06a1/trf-charmap.c create mode 100644 support/RTF-1_06a1/trf-flush.c create mode 100644 support/RTF-1_06a1/trf-nwid.c create mode 100644 support/RTF-1_06a1/trf-stack.c create mode 100644 support/RTF-1_06a1/trf-table.c (limited to 'support/RTF-1_06a1') 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 . +# +# 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 +# include +# 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 +# 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 +# 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 +# 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 +# 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 +# include +# include +# 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, ``<>'' 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 +# 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 + + +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 +# 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 +# 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 +# include +# 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 : "<>"); +} 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 +# include +# ifdef VARARGS +# include +# 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 +# include +# 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 +# include +# 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 +# include +# 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); +} -- cgit v1.2.3