\begindata{text,538268692}
\textdsversion{12}
\template{default}
\define{global
}
\define{footnote

attr:[Flags OverBar Int Set]
attr:[FontSize PreviousFontSize Point -2]}
\define{hidden
menu:[Region~4,Hidden]
attr:[FontFamily AndySans Int 0]
attr:[FontSize PreviousFontSize Point -4]}
\define{reallyhidden
menu:[Region~4,ReallyHidden]
attr:[Flags Hidden Int Set]}
\define{min1
menu:[Font~1,Min1]
attr:[FontSize PreviousFontSize Point -1]}
\define{plus6
menu:[Font~1,Plus6]
attr:[FontSize PreviousFontSize Point 6]}
\define{plus18
menu:[Font~1,Plus18]
attr:[FontSize PreviousFontSize Point 18]}
\define{sans
menu:[Font~1,Sans]
attr:[FontFamily AndySans Int 0]}
\define{symbol
menu:[Font~1,Symbol]
attr:[FontFamily Symbol Int 0]}
\define{symbola
menu:[Font~1,SymbolA]
attr:[FontFamily SymbolA Int 0]}
\define{andy
menu:[Font~1,Andy]
attr:[FontFamily Andy Int 0]}
\define{up2
menu:[Justify~2,Up2]
attr:[Script PreviousScriptMovement Point -2]}
\define{down2
menu:[Justify~2,Down2]
attr:[Script PreviousScriptMovement Point 2]}
\define{para6
menu:[Justify~2,Para6]
attr:[Spacing ConstantSpacing Point 0]
attr:[Spread ConstantSpacing Point 6]}
\define{para12
menu:[Justify~2,Para12]
attr:[Spread ConstantSpacing Point 14]}
\define{para24
menu:[Justify~2,Para24]
attr:[Spread ConstantSpacing Point 24]}
\define{line6
menu:[Justify~2,Line6]
attr:[Spacing ConstantSpacing Point 6]}
\define{line12
menu:[Justify~2,Line12]
attr:[Spacing ConstantSpacing Point 12]}
\define{line24
menu:[Justify~2,Line24]
attr:[Spacing ConstantSpacing Point 24]}
\define{leftinmin36
menu:[Indent~5,LeftInMin36]
attr:[LeftMargin LeftMargin Cm -83231]}
\define{leftinmin12
menu:[Indent~5,LeftInMin12]
attr:[LeftMargin LeftMargin Cm -27744]}
\define{leftindent12
menu:[Indent~5,LeftIndent12]
attr:[LeftMargin LeftMargin Cm 27744]}
\define{leftindent36
menu:[Indent~5,LeftIndent36]
attr:[LeftMargin LeftMargin Cm 83231]}
\define{leftindent72
menu:[Indent~5,LeftIndent72]
attr:[LeftMargin LeftMargin Cm 166461]}
\define{rightinmin36
menu:[Indent~5,RightInMin36]
attr:[RightMargin RightMargin Cm -83231]}
\define{rightinmin12
menu:[Indent~5,RightInMin12]
attr:[RightMargin RightMargin Cm -27744]}
\define{rightindent12
menu:[Indent~5,RightIndent12]
attr:[RightMargin RightMargin Cm 27744]}
\define{rightindent36
menu:[Indent~5,RightIndent36]
attr:[RightMargin RightMargin Cm 83231]}
\define{rightindent72
menu:[Indent~5,RightIndent72]
attr:[RightMargin RightMargin Cm 166461]}
\define{firstinmin72
menu:[Indent~5,FirstInMin72]
attr:[Indent PreviousIndentation Cm -166461]}
\define{firstinmin36
menu:[Indent~5,FirstInMin36]
attr:[Indent PreviousIndentation Cm -83231]}
\define{firstinmin12
menu:[Indent~5,FirstInMin12]
attr:[Indent PreviousIndentation Cm -27744]}
\define{firstindent12
menu:[Indent~5,FirstIndent12]
attr:[Indent PreviousIndentation Cm 27744]}
\define{firstindent36
menu:[Indent~5,FirstIndent36]
attr:[Indent PreviousIndentation Cm 83231]}
-- fromrtf.n

--	Convert a file (or selected section) from RTF format to ATK format.

--

--	Author: WJHansen


marker Version := "1.3"


-- Version 1.3 - 19 February 1991

--	bug fixes, especially to indentation and \\*

--	now deals with an old fonttbl format


-- Version 1.2 - 13 Feb 1991

--		Added features:

--	annotations, fields, index entries, table of contents (partial)

--	all page numbering options

--	paragraph indentation has been corrected


--------------------------------------------

-- HERE'S HOW


-- To convert an entire file give the command

--		nessrun /usr/andrew/lib/ness/fromrtf.n <filename>

--	The output will be in a file having the same prefix and the extension '.d'

--	An existing file with the name generated for the output will be moved to

--	the same name with the extension '.old'


-- To convert a piece of a document:

--	Select the piece, type ESC-ESC, and at the 'Ness:' prompt type

--		fileconvert_convert()


-- To have the conversion as a menu option, add to your ~/.atkinit (or other 
.XYZinit):

--		call ness-load FILENAME

--	where FILENAME is the full pathname of this file


-- To invoke conversion from another Ness program, call the function

--		fromrtf_to_atk(text)

--	The return value will be the converted text.


-- For the second, third, and fourth options your ~/.atkinit (or other 
.XYZinit file)

-- should contain the lines

--		load ness

--		addkey ness-dostmt  \\e\\e  view  


-----------------------------------------

-- Known Problems


--	Styles are fragmented, a long indented section will have separate pieces

--	at each place where the style of an internal piece changes.  

--

--	Table of contents entries in ATK are generated based on styles.  These

--	styles are not currently generated by this program; instead the individual 

--	components of the styles are generated.


--	Hidden text in ATK cannot be viewed readily.  Users can get around this

--	by using lookz to give some other attributes to the style "Hidden".


-----------------------------------------

-- Algorithm


--	The main loop searches for the next \\ \{ \} or newline, 

--		processing each appropriately.

--	CurrText is the unprocessed tail of the original input.

--	The accumulated output is in OutText.

--	Newlines and carriage returns are ignored, everywhere.


--	The format of a control is  

--		backslash, letters, optional-number-optionally-signed, optional-space

--	or

--		backslash, non-letter

--	PeelControl() knows this syntax and strips one control off the input.


--	Our strategy for dealing with styles is to accumulate a style

--	string from style information.	When the style changes or a group

--	ends, the current style string is applied to the text that has just

--	been finished.


--	The style string to be applied to any given piece of text may have a 
sequence

--	of styles, each of which is represented as a byte with that style.

--	The entire sequence is stored as a sequence of such bytes, each followed

--	by a single unstyled blank.  A style defined in the rtf \\stylesheet is 
stored 

--	in variable StyleSheet as the sequence:

--		\\sdd (where dd is an integer), followed by a dash, 

--		the style sequence, and finally a comma.


--	On encountering a style, the plain text collected since the last style

--	is marked with the former style.  Then the new style is applied

--	(added or deleted) to  the style string.

--	At the end of a group, the outer style string is reinstated, popping 

--	its string off StyleStack in ParseGroup.


--	The following rtf controls are processed by this program.

--	A # means the style has a numeric operand

--	A * means the control may have the operand 0 to turn off the style.


-- Major groups that are specially processed

--	\\rtf#  \\fonttbl  \\stylesheet  \\footnote

--	\\footer \\footerl \\footerr  \\header \\headerl \\headerr

--	\\*\\annotation \\*\\atnid    stored as hidden text

--	\\field  -  minimal processing.  

--		convert page to \\chpgn or use \\fldrslt (if not \\fldpriv)

--		ignore \\flddirty \\fldedit \\fldlock \\*\\fldinst

--	\\xe  text goes into document (possibly hidden ala \\v)   \\: -> :

--		ignore \\bxe \\ixe \\rxe \\txe

--	\\tc    ignore \\tcf# and \\tcl#

--	\\info		saved in document with "Hidden" style

--			\\info includes the following:

--		\\title \\subject \\author \\keywords \\comment \\version

--		\\doccomm \\vern# \\creatim \\yr# \\mo# \\dy# \\hr# \\min#  \\id#

--		\\revtim \\printim \\buptim \\edmins# \\nopages# \\nofwords# \\nofchars#

-- Character set is assumed to be ASCII, so the mappings

--	\\ansi \\mac \\pc \\pca \\nextcset

-- are minimal and utilized only for  \\'

-- These maps can be extended by adding appropriate entries.


-- Page numbering and section controls

--	\\page \\pgnstart# \\pgnstarts# \\pgnrestart \\pgncont 

--	\\pgndec \\pgnucrm \\pgnlcrm \\pgnucltr \\pgnlcltr 

--	\\sect \\sectd \\sbknone \\sbkcol \\sbkpage \\sbkeven \\sbkodd


-- Controls that result in modifications to the style string

--	\\pard \\s#

--	\\v 				uses "Hidden" style

--	\\ql \\qr \\qj \\qc

--	\\plain \\b* \\i* \\f \\fs \\ulnone

--	\\ul* \\ulw* \\uld* \\uldb*		all treated as \\ul

--	\\fi# \\li# \\ri#			rounded to nearest 12 points

--	\\up# \\dn# \\sb# \\sa# \\sl#  	rounded to nearest 2 points

-- as installed, the Region,Hidden style is sanserif and four points smaller.

-- To make this text invisible, edit the style to have the Hidden

-- attribute in the "enable" section.  This attribute can be made visible 

-- by clicking the Region,ReallyHidden style name in lookz.

-- Unfortunately, ReallyHidden text still prints as of February, 1991


-- Controls that are replaced with text

--	\\par			newline

--	backslash-newline	newline

--	backslash-return	newline

--	\\row			newline

--	\\cell			tab

--	\\line			carriage return ("soft" newline)

--	\\tab

--	\\~			unpaddable space

--	\\'n			uses the n'th ASCII character (may be mapped)

--	\\-			soft hyphen

--	\\_			non-breaking hyphen

--	\\\\			\\

--	\\\{			\{

--	\\\}			\}

--	\\:			:

--	\\chpgn			page number

--	\\chdate		mo/day/yr, as 1/30/91

--	\\bullet  \\emdash  \\endash  \\lquote  \\rquote  \\ldblquote  \\rdblquote



----------------------------------------

-- Ignored controls

--

--	Groups beginning with these words

--		\\headerf \\footerf \\pict \\colortbl

--		\\*\\bkmkstart \\*\\bkmkend

--	Associated with the ignored groups are these controls

--	which appear only in these groups and are thus never encountered

--		\\red# \\green# \\blue#	\\ftnsep \\ftnspec \\ftncn

--		\\pich# \\picw# \\picscaled \\wmetafile# \\macpict \\bin#

--		\\wbitmap# \\picwGoal# \\pichGoal# \\picscalex# \\picscaley#

--		\\piccropt# \\piccropb# \\piccropl# \\piccropr# 

--		\\wbmbitspixel# \\wbmplanes# \\wbmwidthbytes#

--	Document formatting controls

--		\\paperw# \\paperh# \\margl# \\margr# \\margt# \\margb# \\facingp

--		\\gutter# \\ogutter# \\deftab# \\widowctrl \\deff# \\revbar#

--		\\hyphotz# \\ftncn \\enddoc \\defformat \\revisions \\revprop#

--		\\ftnbj \\ftnsep \\ftnsepc \\endnotes \\ftntj \\ftnstart#

--		\\ftnrestart \\linestart# \\landscape \\margmirror

--		\\fracwidth \\*\\nextfile \\*\\template \\makeback 

--	Section properties:

--		\\pgnx# \\pgny# \\headery# \\footery#

--		\\linemod# \\linex# \\linestarts# \\linerestart \\lineppage

--		\\linecont \\vertalt \\vertalc \\vertalj \\vertal

--		\\cols# \\colsx# \\linebetcol \\endnhere \\titlepg

--	Paragraph styles

--		\\keep \\keepn \\sbys \\noline \\tx# \\tqr \\tb \\tqc \\tqdec 

--		\\brdrt \\brdrb \\brdrl \\brdrr \\box \\brdrs 

--		\\brdrth \\brdrsh \\brdrdb \\brdrdot \\brdrhair \\brsp#

--		\\tldot \\tlhyph \\tlul \\tlth \\pagebb

--	Absolute positioned objects 

--		\\posx# \\posxc \\posxi \\posxl \\posxo \\posxr 

--		\\posy# \\posyil \\posyt \\posyc \\posyb

--		\\absw# \\dxfrtext# \\pvmrg \\pvpg \\phmrg \\phpg \\phcol

--	Tables

--		\\intbl \\clbrdrb \\clbrdrt \\clbrdrr \\clbrdrl

--		 \\trowd \\trql \\trqc \\trqr \\trgaph# \\trrh# \\trleft#

--		\\cellx# \\clmgf \\clmgr

--	Character styles

--		\\strike \\outl \\shad \\scaps \\caps \\expnd# \\cb# \\cf# \\revised

--	Special characters

--		\\chftn \\chftnsep \\chftnsepc \\chtime \\|  \\chatn \\column


------- Lookz to edit the special styles used in this program

--	Do not use lookz to edit styles FirstIndent\italic{xx} and 
FirstInMin\italic{xx}.

-- 
\begindata{lookz, 538247816}
hidden
\enddata{lookz, 538247816}
\view{lookzview,538247816,14,0,0}



---------------------------------------------

--  constants


integer DEFAULTFONTSIZE := 12	-- whatever size is usual


marker Letters := "qwertyuiopasdfghjklzxcvbnm"

		~ "QWERTYUIOPASDFGHJKLZXCVBNM"


marker Hidden := "\hidden{h}idden"  -- first letter has "hidden" style

			-- (this value is temporarily replaced in processing \\xe)


marker PageBreak := 

//


\begindata{bp,538247880}
\enddata{bp,538247880}
\view{bpv,538247880,15,0,0}

\\\\


---------------------------------------------

-- global state


marker CurrText		-- what remains to be parsed


-- results of parseControl()

marker CurrCtl		-- the result of parsing the latest control

marker CurrRand		-- the operand string

integer CurrRandValue	-- the numeric operand


marker StyleSheet		-- constructed from \\stylesheet

marker FontTbl		-- constructed from \\fonttbl group

marker CurrMap		-- set from macmap, ansimap, pcmap, or pcamap


boolean DefinedHeader	-- have we seen \\header...

boolean sectBreakPage := True		-- set False by \\sbknone

boolean restartpgnumpersect := False	-- set true by \\pgnrestart

integer sectFirstPageNum := 1  		-- set by \\pgnstarts

boolean pageNumberSupplied := False	-- kludge

marker currPageNFmt := "1"			-- set by \\pgnxcxx


---------------------------------------------

-- Control Interpretation Table


-- The ControlInterpretationTable gives a translation for every control

--	interpreted by this program.

--	The proper entry for "control" is found by searching for "\\control-"

--	and utilizing subsequent characters up to the comma.  

--	The first character after the dash is the major function indicator

--	and determines, for example, whether preceding text should have the

--	current style applied.


marker ControlInterpretationTable := 


	-- these entries all introduce new styles.  The major function code is "s".

	-- the action for those without $  is to append the style to the current 
style

	-- for those with subcode $, individual actions are taken

	-- The style code letters are not duplicated so when a style is to be deleted

	-- from the current style, its code letter is deleted from the style string.

	   "\\\\ql-s\flushleft{A},\\\\qr-s\flushright{B},\\\\qj-sC,\\\\qc-s\center{D},\
\\\\b-s\bold{E},\\\\i-s\italic{F},"

	~ "\\\\v-s\hidden{G},"	-- between the s and comma is a "G" in style Hidden 

	~ 
"\\\\ul-s\underline{I},\\\\ulw-s\underline{J},\\\\uld-s\underline{K},\\\\uldb-s\
\underline{L},\\\\up-s$R\up2{M}\down2{M},\\\\dn-s$R\down2{N}\up2{N},"

	~ 
"\\\\li-s$P\leftinmin36{h}\leftindent72{h}\leftinmin12{h}\leftindent36{h}\leftindent12{h\
},\\\\ri-s$P\rightinmin36{i}\rightindent72{i}\rightinmin12{i}\rightindent36{i}\
\rightindent12{i},\\\\fi-s$Q\firstinmin72{j}\firstindent36{j}\firstinmin36{j}\
\firstindent12{j}\firstinmin12{j},\\\\sb-s$U\para6{k}\para12{k}\para24{k},\\\\s\
a-s$U\para6{k}\para12{k}\para24{k},\\\\sl-s$U\line6{l}\line12{l}\line24{l},"

	~ "\\\\s-s$S,\\\\fs-s$T,\\\\f-s$f,\\\\ulnone-s$V,"

	~ "\\\\plain-s$W,\\\\pard-s$X,\\\\snext-s$n,\\\\sbasedon-s$b,"


	-- the following are simply replaced with the text following the

	-- major function code, which is "r"

	~ "\\\\par-r\\n,\\\\tab-r\\t,\\\\~-r\formatnote{\\\\ 
},\\\\_-r\formatnote{\\\\-},\\\\--r\formatnote{\\\\%},\\\\:-r:,"

	~ 
"\\\\\\r-r\\n,\\\\line-r\\r,\\\\\{-r\{,\\\\\}-r\},\\\\\\\\-r\\\\,\\\\\\n-r\\n,"\
 	~ 
"\\\\chpgn-r\formatnote{\\\\\\\\n(PN},\\\\chdate-r\formatnote{\\\\\\\\n(mo/\\\\\
\\\\n(dy/\\\\\\\\n(yr},"

	~ 
"\\\\cell-r\\t,\\\\row-r\\n,\\\\bullet-r\symbola{7},\\\\emdash-r\symbola{>},\\\\\
endash-r-,"

	~ 
"\\\\lquote-r`,\\\\rquote-r',\\\\ldblquote-r\\",\\\\rdblquote-r\symbola{2},"


	-- footnotes (code "p") return text to be inserted unstyled

	-- picts are ignored.  annotations are stored as hidden text

	~ "\\\\footnote-pA,\\\\pict-pB,"

	~ "\\\\annotation-pC,\\\\atnid-pD,\\\\annotation-pC,\\\\atnid-pD,"

	~ "\\\\field-pE,\\\\xe-pF,\\\\tc-pG,"


	-- hex chars are mapped.  major function code "m"

	~ "\\\\'-m,"


	-- map font codes to ATK fonts.  major function code "f"

	-- (These should only be seen by parseFonttbl)

	~ 
"\\\\fnil-f,\\\\froman-\andy{f},\\\\fswiss-\sans{f},\\\\fmodern-\typewriter{f},\
"

	~ 
"\\\\fscript-\italic{\underline{f}},\\\\fdecor-\bold{\underline{f}},\\\\ftech-\
\symbol{f},"


	-- page numbering and section controls, func code "qP"

	~ "\\\\pgnstart-qPa,\\\\pgnstarts-qPb,\\\\pgnrestart-qPc,\\\\pgncont-qPd,"

	~ 
"\\\\pgnucrm-qPe,\\\\pgnlcrm-qPf,\\\\pgnucltr-qPg,\\\\pgnlcltr-qPh,\\\\pgndec-q\
Pi,"

	~ "\\\\sect-qPj,\\\\sectd-qPk,\\\\sbknone-qPl,\\\\sbkcol-qPm,"

	~ "\\\\sbkpage-qPm,\\\\sbkeven-qPm,\\\\sbkodd-qPm,\\\\page-qPp,"


	-- these introduce major blocks.  Function code "q"

	~ "\\\\footer-qEfs,\\\\footerl-qEfd,\\\\footerr-qEfd,"

	~ "\\\\header-qEhs,\\\\headerl-qEhd,\\\\headerr-qEhd,"  

	~ "\\\\mac-qCA,\\\\pc-qCB,\\\\ansi-qCC,\\\\nextcset-qCC,\\\\pca-qCD,"

	~ "\\\\rtf-qR,\\\\fonttbl-qF,\\\\stylesheet-qS,\\\\info-qI,"

	~ "\\\\*-q*,"		-- unknown destinations are ignored

	~ "\\\\colortbl-q#,\\\\bkmkstart-q#,\\\\bkmkend-q#,"	-- ignored

	~ "\\\\txe-q#,\\\\rxe-q#,"


---------------------------------------------

-- font controls

\symbola{
}-- Font choices:

--	\\fnil -> default font

--	\\roman -> andy

--	\\fswiss -> andysans

--	\\fmodern-> andytype

--	\\fscript -> default-italic-underline

--	\\fdecor -> default-bold-underline

--	\\ftech -> symbol	(could be symbola, XXX need mapping)


-- The fonts Symbol and SymbolA under ATK are in the PostScript ordering.


-- font Symbol:   (PostScript symbol codes 0x20 ... 0x7F)

--\symbol{	  !"#$%&'()*+,-./}		2x  punctuation

--	\symbol{0123456789:;<=>?}		3x  digits

--	\symbol{@ABCDEFGHIJKLMNO}	4x  upper case

--	\symbol{PQRSTUVWXYZ[\\]^_}	5x  upper case\symbol{

}--	\symbol{`abcdefghijklmno}		6x  lower case\symbol{

}--	\symbol{pqrstuvwxyz\{|\}~?}		7x  lower case


-- font SymbolA:   (PostScript symbol codes 0xA0 ... 0xFF, mapped to 0x20 ... 
0x7F)

--	 \symbola{ !"#$%&'()*+,-./}		2x\symbola{

}--\symbola{	0123456789:;<=>?}		3x

--\symbola{	@ABCDEFGHIJKLMNO}	4x

--\symbola{	PQRSTUVWXYZ[\\]^_}	5x

--\symbola{	`abcdefghijklmno}			6x

--\symbola{	pqrstuvwxyz\{|\}~?}			7x


marker macmap := 
"a1-\symbola{0}a5-\symbola{7}a8-\symbola{b}a9-\symbola{c}aa-\symbola{T}ad-\
\symbola{9}c9-\symbola{<}d"

		~ "1-\symbola{m}d2-\\"d3-\symbola{2}d4-`d5-'"

marker ansimap := "aa-\\"ba-\symbola{2}b7-\symbola{7}e3-\symbola{c}"

marker pcmap := ""

marker pcamap := ""


---------------------------------------------

-- table for \\'#, the hexadecimal character convention (we just use ASCII)


marker hextran :=

	    "\\000\\001\\002\\003\\004\\005\\006\\007\\010\\011\\012\\013\\014\\015\\0\
16\\017"

	~ 
"\\020\\021\\022\\023\\024\\025\\026\\027\\030\\031\\032\\033\\034\\035\\036\\0\
37"

	~ 
"\\040\\041\\042\\043\\044\\045\\046\\047\\050\\051\\052\\053\\054\\055\\056\\0\
57"

	~ 
"\\060\\061\\062\\063\\064\\065\\066\\067\\070\\071\\072\\073\\074\\075\\076\\0\
77"

	~ 
"\\100\\101\\102\\103\\104\\105\\106\\107\\110\\111\\112\\113\\114\\115\\116\\1\
17"

	~ 
"\\120\\121\\122\\123\\124\\125\\126\\127\\130\\131\\132\\133\\134\\135\\136\\1\
37"

	~ 
"\\140\\141\\142\\143\\144\\145\\146\\147\\150\\151\\152\\153\\154\\155\\156\\1\
57"

	~ 
"\\160\\161\\162\\163\\164\\165\\166\\167\\170\\171\\172\\173\\174\\175\\176\\1\
77"

	~ 
"\\200\\201\\202\\203\\204\\205\\206\\207\\210\\211\\212\\213\\214\\215\\216\\2\
17"

	~ 
"\\220\\221\\222\\223\\224\\225\\226\\227\\230\\231\\232\\233\\234\\235\\236\\2\
37"

	~ 
"\\240\\241\\242\\243\\244\\245\\246\\247\\250\\251\\252\\253\\254\\255\\256\\2\
57"

	~ 
"\\260\\261\\262\\263\\264\\265\\266\\267\\270\\271\\272\\273\\274\\275\\276\\2\
77"

	~ 
"\\300\\301\\302\\303\\304\\305\\306\\307\\310\\311\\312\\313\\314\\315\\316\\3\
17"

	~ 
"\\320\\321\\322\\323\\324\\325\\326\\327\\330\\331\\332\\333\\334\\335\\336\\3\
37"

	~ 
"\\340\\341\\342\\343\\344\\345\\346\\347\\350\\351\\352\\353\\354\\355\\356\\3\
57"

	~ 
"\\360\\361\\362\\363\\364\\365\\366\\367\\370\\371\\372\\373\\374\\375\\376\\3\
77"



function printdump(msg, text)

	writefile ("/tmp/a", text)

	printline(msg)

	printline(system("cat /tmp/a"))

end function



---------------------------------------------

-- text manipulation


-- SkipNewlines()

--	advance CurrText beyond any initial newline or carriage return

--	returns resulting first character of CurrText

function SkipNewlines()

	while first(CurrText) = "\\n" or first(CurrText) = "\\r" do

		CurrText := rest(CurrText)

	end while

	return first(CurrText)

end function


-- SkipToUnmatchedRightBrace(after)

--	skip text to next unmatched right brace

--	if 'after' is True CurrText will begin after the brace, 

--		otherwise before

--	deal with \\\{ and \\\} by skipping char after \\

function SkipToUnmatchedRightBrace(boolean after)

	marker brace

	integer cnt := 1

	while cnt > 0 do

		brace := anyof(CurrText, "\{\}\\\\")

		CurrText := extent(finish(brace), CurrText)

		if CurrText = "" then exit function

		elif brace = "\\\\" then CurrText := rest(CurrText)

		elif brace = "\{" then 	 cnt := cnt + 1

		else	cnt := cnt -1	 end if

	end while

	if not after then

		CurrText := extent(previous(CurrText), CurrText)

	end if

end function


-- PeelControl(bs)

--	bs refers to a \\ at the beginning of a control

--	This function parses a control off CurrText

--	and sets CurrText, CurrCtl, CurrRand, CurrRandValue

--	returns major function code in ControlInterpretationTable

function PeelControl(bs)

	integer neg := 1

	marker t

	CurrCtl := extent(bs, span(finish(bs), Letters))

	if CurrCtl = "\\\\" then

		-- must be a control symbol

		CurrCtl := extent(CurrCtl, next(CurrCtl))

		CurrRand := ""

		CurrText := extent(finish(CurrCtl), CurrText)

		if CurrCtl = "\\\\*" then

			t := PeelControl(first(CurrText))

			if t /= "" then return t end if	-- ignore \\*

			CurrCtl := "\\\\*"	-- replace unintelligible control group

		end if

	else

		CurrRand := span(finish(CurrCtl), "+-0123456789")

		if CurrRand /= "" then

			if first(CurrRand) = "-" then neg := -neg end if

			CurrRandValue := neg * parseint(token(CurrRand, "0123456789"))

		else

			CurrRandValue := 0

		end if

		CurrText := extent(finish(CurrRand), CurrText)

		if front(CurrText) = " " then CurrText := rest(CurrText) end if

	end if

	return next(search(ControlInterpretationTable, CurrCtl ~ "-"))

end function


---------------------------------------------

-- font routines


-- ParseOldFonttbl()

--	some \\rtf0 files have a non-group format for fonttbls.  

--	Each font entry is text like:

--		\\f1\\froman Times;

--	the semicolon on the last entry is followed by a \} to match the one before 
\\fonttbl

function ParseOldFonttbl()

	marker c := first(CurrText)

	marker tkey, font

	while c = "\\\\" do

		PeelControl(c)		-- get font code: \\fnn

		if CurrCtl /= "\\\\f" then  -- error: no \\f

			 exit function 

		end if 

		tkey := CurrRand			-- save nn

		c := SkipNewlines()

		if c /= "\\\\" then exit function end if	-- error: no control for font 
family

		font := PeelControl(c)			-- get font family: \\fnil, etc.

		if font /= "f" then  exit function end if	-- error, no font family

		FontTbl ~:= tkey ~ " ,"  

		replace (previous(last(FontTbl)), font)

		c := anyof(CurrText, ";\}\\\\")

		if c /= ";" then exit function end if	-- error no font name

		CurrText := extent(finish(c), CurrText)

		c := SkipNewlines()

	end while

end function


-- ParseFontTbl()

--	parses the \\fonttbl, building table in FontTbl

--	assumes CurrText begins just after \\fonttbl

--	Output is string containing sequence of  "nnf," where nn is font number

--		and f has the appropriate style 

--	We utilize the font family code and ignore the font name.

function ParseFontTbl()

	marker c

	marker tkey, font

	c := SkipNewlines()

	if c /= "\{" then

		return ParseOldFonttbl()

	end if

	while c = "\{" do

		CurrText := rest(CurrText)

		c := SkipNewlines()

		if c /= "\\\\" then exit function end if	-- error: no \\ for \\f

		tkey := PeelControl(c)		-- get font code: \\fnn

		if CurrCtl /= "\\\\f" then  -- error: no \\f

			 exit function 

		end if 

		tkey := CurrRand			-- save nn

		c := SkipNewlines()

		if c /= "\\\\" then exit function end if	-- error: no control for font 
family

		font := PeelControl(c)			-- get font family: \\fnil, etc.

		if font /= "f" then  exit function end if	-- error, no font family

		FontTbl ~:= tkey ~ " ,"  

		replace (previous(last(FontTbl)), font)

		

		SkipToUnmatchedRightBrace(True) -- skip fontname & \}

		c := SkipNewlines()

	end while

end function


-- GenerateFontSize(integer fs)

--	fs is size in half points

--	generate a character having a font size style setting of fs

--	Algorithm: start with size 1 or 2 and advance with Bigger, Plus6, and 
Plus18


function GenerateFontSize(integer fs)

	marker s := copy("T")   -- byte to be styled

	integer currsize := DEFAULTFONTSIZE


	-- convert to points by dividing by two.  

	-- round  extra half point to nearest even number.

	if fs % 4 = 3 then fs := fs + 1 elif fs % 4 = 1 then fs := fs -1 end if

	fs := fs / 2

	if fs %2 = 1 then

		addstyles(s, "\min1{$}");   currsize := currsize - 1

	end if

	while currsize > fs do addstyles(s, "\smaller{$}");  currsize := currsize - 2 
end while

	while currsize+18 <= fs do   addstyles(s, "\plus18{$}");   currsize := 
currsize + 18   end while

	while currsize+6 <= fs do   addstyles(s, "\plus6{$}");   currsize := currsize 
+ 6	end while

	while currsize+2 <= fs do   addstyles(s, "\bigger{$}");   currsize := 
currsize + 2   	end while

	return s

end function


---------------------------------------------

-- style routines


-- RemoveStyles(style sts)

--	remove from style the styles coded by sts

function RemoveStyles(style, sts)

	marker m

	while sts /= "" do

		if first(sts) /= " " then

			m := search(style, first(sts))

			if m /= "" then

				replace(extent(m, next(m)), "")

			end if

		end if

		sts := rest(sts)

	end while

end function


-- adjustindent()

--	addstyles(target, code) enough times to come closer to the desired value

integer function adjustindent(target, integer desired, code, integer val)

	integer times := desired / val

	if times < 0 then return desired end if -- opposite signs

	desired := desired - val * times

	while times > 0 do 

		addstyles(target, code);  times := times - 1

	end while

	return desired

end function


function IndentUnits(style, code, integer first, integer second, 

				integer third, integer fourth, integer fifth)

		-- convert twips to points and round to nearest 12 points

	integer desired := (CurrRandValue + 120) / 20

	marker target

	RemoveStyles(style, code)

	style ~:= code ~ " "

	target := previous(last(style))

	clearstyles(target)

	desired := adjustindent(target, desired, code, first)  code := next(code)

	desired := adjustindent(target, desired, code, second)  code := next(code)

	desired := adjustindent(target, desired, code, third)  code := next(code)

	desired := adjustindent(target, desired, code, fourth)  code := next(code)

	desired := adjustindent(target, desired, code, fifth)  code := next(code)

	return style

end function 


function RoundUnits(style, code, integer base)

	integer twips := base * 20;	-- measurements are in points/20

	if CurrRandValue < 0 then

		code := next(code)

		CurrRandValue := - CurrRandValue

	end if

	RemoveStyles(style, code)

	style ~:= code ~ " "

	CurrRandValue := CurrRandValue - twips*3/2	-- count first one and round

	while CurrRandValue > 0 do

		addstyles(previous(last(style)), code)

		CurrRandValue := CurrRandValue - twips

	end while

	return style

end function 


-- ModifyStyle(code, style)

--	Modify 'style' to have or remove the style of 'code'

--	A CurrRand of 0 turns off the option if already in 'style'.

--	Other numeric rands are ignored.

--	If code is "$", the style is specially handled as coded by next(code):

--		Q	round to 12 points

--		R	round to 2 points

--		U	round to 2 points

--		S	\\s#	search StyleSheet

--		T	\\fs#	set font size

--		f	\\f#	set font

--		V	\\ulnone undoes any underline

--		W	\\plain undoes \\b \\i \\f \\fs \\ul \\ulw \\uld \\uldb \\up \\dn "

--		X	\\pard	sets style string to empty


-- assumption, the styles are represented each with a unique byte


function ModifyStyle(code, style)

	marker m

	code := next(code)

	if CurrRand /= "" and CurrRandValue = 0 then

		-- turn off the style

		if code = "$" then code := next(code) end if

		RemoveStyles(style, code)

	elif code /= "$" then 

		RemoveStyles(style, code)

		style ~:= "  "	-- two blanks

		replace(previous(last(style)), code)

	else

		code := next(code)

		--printline("s$" ~ code)

		if code = "T" then 		-- \\fs

			RemoveStyles(style, "T")

			style ~:= "  "	-- two blanks

			replace(previous(last(style)),

					GenerateFontSize(CurrRandValue))

		elif code = "f" then 		-- \\f

			RemoveStyles(style, "f")

			m := search(FontTbl, CurrRand)

			if m /= "" then

				style ~:= "  "	-- two blanks

				replace(previous(last(style)), next(m))

			end if

		elif code = "S" then 		-- \\s

			-- change style to that found in StyleSheet

			m := search(StyleSheet, "\\\\" ~ CurrRand ~ "-")

			if m /= "" then

				m := finish(m)

				style := copy(extent(m, start(search(m, ","))))

				--printdump("change to style \\\\s" ~ CurrRand, style)

			end if

		elif code = "P" then		-- \\li \\ri   round to 12 points

			style := IndentUnits(style, next(code), -36, 72, -12, 36, 12)

		elif code = "Q" then		-- \\fi   round to 12 points

			style := IndentUnits(style, next(code), -72, 36, -36, 12, -12)

		elif code = "R" then 		-- \\up \\dn round to 2 points

			style := RoundUnits(style, next(code), 2)

		elif code = "U" then 		-- \\sa \\sb \\sl  6, 12, or 24 points, but cancel 
for 0

			code := next(code)

			RemoveStyles(style, code)

			if CurrRandValue /= 0 then

				if CurrRandValue >= 360 then

					-- 18 points or more, use 24

					code := next(next(code))

				elif CurrRandValue >= 180 then

					-- 9 points or more, use 12

					code := next(code)

				else

					-- less than 9 points, use 6

				end if

				style ~:= "  "	-- two blanks

				replace(previous(last(style)), code)

			end if

		elif code = "X" then		-- \\pard

			style := newbase()

		elif code = "W" then		-- \\plain

			RemoveStyles(style, "GHIJKLMNfT")

		elif code = "V" then		-- \\ulnone

			RemoveStyles(style, "IJKL")

		end if

	end if

	return style

end function


-- ParseStyle()

--	parse controls off the front of CurrText

--	call ModifyStyle to append style definitions to style

--	leave CurrText at the beginning of the style name

--	Returns "\\snn<styles>," where nn is stylenum and <styles> is a style 
string

--	for \\sbasedon, call ModifyStyle for each elt of the basis style

--		(order of definition matters)

function ParseStyle()

	marker stynum := "999"

	marker m, code, xcode

	marker style := newbase()

	while first(CurrText) = "\\\\" do

		code := PeelControl(first(CurrText))

		xcode := extent(code, next(next(code)))

		if CurrCtl = "\\\\s" then

			stynum := CurrRand

		elif CurrCtl = "\\\\snext" and stynum = "999" then   	-- \\snext

			-- this is BOGUS,  based on rule that \\snext gives

			--	own number if is the "last"   XXX

			stynum := CurrRand

		elif CurrCtl = "\\\\sbasedon" then  	-- \\sbasedon

			m := search(StyleSheet, "\\\\" ~ CurrRand ~ "-")

			if m /= "" then

				m := copy(extent(next(m), start(search(finish(m), ","))))

				RemoveStyles(m, style) -- remove styles already

							-- specified in 'style'

				style ~:= m

				-- printdump("basedon " ~ CurrRand, style)

			end if

		elif code = "s" then

			style := ModifyStyle(code, style)

		end if

		SkipNewlines()

	end while

	return "\\\\" ~ stynum ~ "-" ~ style ~ ","

end function


-- ParseStyleSheet()

--	parse stylesheet, build StyleSheet value

--	CurrText begins just after \\stylesheet

function ParseStyleSheet()

	marker t

	t := SkipNewlines()

	while t = "\{" do

		CurrText := rest(CurrText)

		SkipNewlines()

		StyleSheet ~:= ParseStyle()

		SkipToUnmatchedRightBrace(True)  -- skip style name & \}

		t := SkipNewlines()

	end while

	-- printdump("stylesheet", StyleSheet)

end function


-- ApplyStyle(tstart, tend, style)

--	Apply style to extent(tstart, base(tend))

--	Return ref to tend

--

function ApplyStyle(tstart, tend, style)

	marker subject 

	subject := extent(tstart, base(tend))

	if subject = "" then 

		-- no text to be styled

		return finish(subject)

	end if

	while style /= "" do 

		addstyles(subject, style)

		style := rest(rest(style))

	end while

	return finish(subject)

end function



---------------------------------------------

-- Headers and Footers


-- 	Every header and footer is included, but only the most recent of each

--	will apply.   Simplex printing is specified for header or footer.

--	Duplex printing is specified for  headerl, headerr, footerl, footerr. 

--	Each tab in the text separates one of the three parts of the title.

--	(Maximum of two tabs).   Styles are ignored.

--Example input:

--	\{\\footerl \\pard\\plain \\s243\\tqc\\tx4320\\tqr\\tx8640 

--	\{\\f14\\fs20 Sun OS 4.0 Installation Procedures\\tab \\chdate 

--	\\tab Page \\chpgn \\par \}\}

-- Example output (all wrapped in FormatNote)

--	.duplex

--	.\\" Footer

--	.ds LB Sun OS 4.0 Installation Procedures

--	.ds CB \\\\n(dy/\\\\n(mo/\\\\n(yr

--	.ds RB \\\\n(PN

--


-- ComputeExtremiter(text, footer)

--	create lines for left, right, and center

--	break text at tabs or newlines, using the non-blank segments

--	3 or more non-blank segs:  use first three as L, C, and R

--	2 segs: L and R

--	1 seg: C

function ComputeExtremiter(text, boolean footer)

	marker tab, segL, segC, segR, where

	integer nsegs := 0

	while text /= ""and nsegs < 3 do

		tab := anyof(text, "\\t\\n")

		segR := extent(text, start(tab))

		if segR /= "" then

			-- grab a seg

			nsegs := nsegs + 1

			if nsegs = 1 then segL := segR

			elif nsegs = 2 then segC := segR end if

		end if

		-- skip tab

		text := extent(finish(tab), text)

	end while

	if nsegs = 1 then 

		segC := segL;   segL := "";   segR := ""

	elif nsegs = 2 then

		segC := ""

	elif nsegs = 0 then

		segC := "";   segL := "";   segR := ""

	end if

	if footer then where := "B " else where := "T " end if

	return (".ds L" ~ where ~ segL ~ "\\n")

		~ (".ds C" ~ where ~ segC ~ "\\n")

		~ (".ds R" ~ where ~ segR ~ "\\n")

end function


--	~ "\\\\footer-qEfs,\\\\footerl-qEfd,\\\\footerr-qEfd,"

--	~ "\\\\header-qEhs,\\\\headerl-qEhd,\\\\headerr-qEhd," 


function ParseExtremiter(code)

	boolean footer 

	marker text := newbase() ~ "\\n"	-- initial newline


	code := next(code) -- f or h

	footer := code = "f"	


	code := next(code) -- to s or d

	if code = "d" then  text ~:= ".duplex\\n" else text ~:= ".simplex\\n" end if

	if footer then text ~:= ".\\\\\\" Footer\\n"

	else text ~:= ".\\\\\\" Header\\n"  end if

	text ~:= ComputeExtremiter(clearstyles(parseGroup("")), footer)

	if not footer then DefinedHeader := True

	elif footer and not DefinedHeader then

		-- undefine the standard header with page number at top

		text ~:= ".ds CT\\n"

	end if


	return addstyles(text, "\formatnote{%}")	-- formatnote

end function


---------------------------------------------

-- Footnotes


marker annotator := ""


function parseEmbeddedObject(code)

	marker m, t, SaveState

	if next(code) = "A" then

		-- \\footnote

		-- m := 
copy("\footnote{\
\begindata{fnote,537826312}
\textdsversion{12}
\enddata{fnote,537826312}
\view{fnotev,537826312,16,0,0}  }")	-- footnote object and two footnote blanks

		--	the above fails because all footnotes get the same object

		m := copy("   ")

		replacewithobject(first(m), new(class("fnote")), "fnotev")

		addstyles(m, 
"\footnote{\
\begindata{fnote,537826568}
\textdsversion{12}
\enddata{fnote,537826568}
\view{fnotev,537826568,17,0,0}}")

		m := replace (previous(last(m)), clearstyles(parseGroup("")))

		if first(m) = "\\n" then replace(first(m), "") end if

		replace(next(m), "")

		return base(m)

	elif next(code) = "C" then  	-- \\annotation.  append (annotator)

		m := parseGroup("") 

		if annotator /= "" then m := m ~ " (" ~ annotator ~ ")" end if

		annotator := ""

		addstyles(m, Hidden)

		return m

	elif next(code) = "D" then	-- \\atnid.  save author

		annotator := parseGroup("")

		return ""

	elif next(code) = "E" then	-- \\field  -  minimal processing.  

		--	convert page to \\chpgn or use \\fldrslt (if not \\fldpriv)

		--	ignore \\flddirty \\fldedit \\fldlock \\*\\fldinst

		m := CurrText

		SkipToUnmatchedRightBrace(False)

		m := extent(m, start(CurrText))  -- the contents of the \\field group

		if search(m, "page")  /= "" then  -- assume it is page number 

			return "\formatnote{\\\\\\\\n(PN}"

		end if

		t := search(m, "\\\\fldrslt")

		if t /= "" then

			-- return contents of \\fldrslt

			SaveState := CurrText

			PeelControl(first(t))		-- sets CurrText

			m := parseGroup("")

			CurrText := SaveState

			return m

		end if

		return ""

	elif next(code) = "F" then	-- xe  text goes into document 

					--(possibly hidden ala \\v)   \\: -> :

					--	ignore \\bxe \\ixe \\rxe \\txe

		SaveState := Hidden

		Hidden := "\indexi{InvisibleIndex}"

		m := parseGroup("")

		if not hasstyles(m, Hidden) then

			addstyles(m, "\index{Index}")

		end if

		Hidden := SaveState

		return m

	elif next(code) = "G" then	-- \\tc

		--	ATK entries for T/C  are based on which style is chosen

		--	to implement this, we would have to choose which style

		--	sequences map to each ATK title style.

		--	For now we just include the text.

		return parseGroup("")

	else

		-- must be a pict, field, index entry, or tc entry

		SkipToUnmatchedRightBrace(False)

		return ""

	end if

end function



---------------------------------------------

-- Control and Block Processing


-- MapHex()

--	Do mapping for \\'xx

--	First check CurrMap, then just generate the hex byte

--

function MapHex()

	marker t

	marker m := next(CurrCtl)

	m := extent(m, next(m)) 	-- the two hex bytes

	CurrText := extent(finish(m), CurrText)

	t := search(CurrMap, m ~ "-")

	if t /= "" then return next(t)

	else return nextn(first(hextran), parseint("0x" ~ m))

	end if

end function


function pageNFmt(fmt, fmtname)

	if currPageNFmt = fmt then return "" end if

	currPageNFmt := fmt

	return ".\\\\\\" format page number as " ~ fmtname ~ "\\n'af PN " ~ fmt

end function


function Pagination(code)

	marker t

	marker troff := newbase()

	--	printline("Pagination code " ~ code)

	if code = "a" then 	-- a-\\pgnstart#

		CurrRandValue := CurrRandValue + 1 -- kludge

		t := textimage(CurrRandValue)

		troff ~:= "\\n.\\\\\\" set page number to " ~ t ~ "\\n'pn " ~ t

		pageNumberSupplied := True

	elif code = "b" then	-- b-\\pgnstarts#

		CurrRandValue := CurrRandValue + 1 -- kludge

		sectFirstPageNum := CurrRandValue

		return ""

	elif code = "c" then	-- c-\\pgnrestart

		-- it is incorrect to output the new page number here,

		--	but it works since pgnrestart is only given 

		-- 	at the beginning of a section

		restartpgnumpersect := True

		t := textimage(sectFirstPageNum)

		troff := pageNFmt("1", "decimal")

			~ ".\\\\\\" reset page number for new section to " ~ t 

			~ "\\n'pn " ~ t

		pageNumberSupplied := True

	elif code = "d" then 	-- \\pgncont

		restartpgnumpersect := False

		return ""

	elif code = "e" then 	-- \\pgnucrm

		troff := pageNFmt("I", "upper case roman")

	elif code = "f" then 	-- \\pgnlcrm

		troff := pageNFmt("i", "lower case roman")

	elif code = "g" then 	-- \\pgnucltr

		troff := pageNFmt("A", "upper case letter")

	elif code = "h" then 	-- \\pgnlcltr

		troff := pageNFmt("a", "lower case letter")

	elif code = "i" then 	-- \\pgndec

		troff := pageNFmt("1", "decimal")

	elif code = "j" then 	-- \\sect: add newline or page break

				--  and perhaps restart page numbers

		if not restartpgnumpersect then

			if sectBreakPage then return copy("\\f")

			else return "" end if

		end if

		t := textimage(sectFirstPageNum)

		troff := "\\n.\\\\\\" set page number for new section to " ~ t ~ "\\n'pn " ~ 
t

		pageNumberSupplied := True

		if sectBreakPage then  troff := "\\f" ~ troff  end if

	elif code = "k" then 	-- \\sectd

		-- reset all section styles (we only have those for pagination)

		sectBreakPage := True

		restartpgnumpersect := False

		sectFirstPageNum := 1

		-- assume we just had a \\sect, so we reformat page numbers

		troff := pageNFmt("1", "decimal")

	elif code = "l" then 	-- \\sbknone

		sectBreakPage := False

		return ""

	elif code = "m" then 	-- \\sbkcol  \\sbkpage  \\sbkeven  \\sbkodd

				--	all set page break before section

		sectBreakPage := True

		return ""

	elif code = "p" then 	-- \\page

		return copy("\\f")	-- signal to do page break before next text

	end if

	if troff = "" or troff = "\\n" then return "" end if

	return addstyles(troff ~ "\\n", "\formatnote{FormatNote}")

end function


-- parseDocumentControl(code)

--	major function code "q"

--	process a group with a block code

--	each function called to handle a group 

--		leaves its trailing \} on the front of CurrText


function parseDocumentControl(code)

	marker m

	--printline("parseDocumentControl " ~ CurrCtl ~ CurrRand)

	code := next(code)

	if code = "*" then		-- \\*	ignorable destination

		SkipToUnmatchedRightBrace(False)

	elif code = "P" then		-- page numbering options

		return Pagination(next(code))

	elif code = "R" then		--\\rtf

		--	fine, accept rtf		XXX probably should check CurrRand

	elif code = "F" then		-- \\fonttbl

		ParseFontTbl()

	elif code = "S" then		-- \\stylesheet

		ParseStyleSheet()

	elif code = "E" then		-- \\header or \\footer

		return ParseExtremiter(code)

	elif code = "I" then		-- \\info  (make it hidden)

		m := CurrText

		SkipToUnmatchedRightBrace(False)

		m := copy(extent(m, start(CurrText)))

		return addstyles(m, Hidden)

	elif code = "C" then		-- \\mac \\pc \\ansi \\pca

		-- map characters

		code := next(code)

		if code = "A" then CurrMap := macmap

		elif code = "B" then CurrMap := pcmap

		elif code = "C" then CurrMap := ansimap

		elif code = "D" then CurrMap := pcamap

		end if

	else		-- skip all others

		SkipToUnmatchedRightBrace(False)

	end if

	return ""

end function


boolean NewPage := False   -- kludge return value from AppendTo


-- AppendTo(target, src, pagewanted, hadtext)

--	specialized version of ~:= to avoid a bug in styles

--	if pagewanted is true and the src is non-empty,

--		set NewPage and generate a page break if hadtext is True

function AppendTo(target, src, boolean pagewanted, boolean hadtext)

	-- printline("Append: " ~ src ~ "  " ~ textimage(pagewanted) ~ "  " ~ 
textimage(hadtext))

	if pagewanted and src /= "" then

		NewPage := True    -- tell parsegroup to turn off pagewanted

			target ~:= " "

		if hadtext then

			replace(last(target), PageBreak)

		elif pageNumberSupplied then

			replace(last(target), 

					".\\\\\\" increment page number for inital page break\\n" 

					~ "\formatnote{'pn \\\\n%+1\\n}")

		end if

		pageNumberSupplied := False

	end if

	target ~:= " "

	replace (last(target), src)

	return base(target)

end function


-- parseGroup(CurrStyle)

--	parses the text in CurrText, using the argument as the base style

--	returns the translated text

--

--	the input is a sequence of operators and blocks

--	where an operator begins with \\ and a block begins with \{

--	spaces and newlines are ignored

--	some blocks are control blocks, others are text blocks,

--		depending on the first operator in the block

--	The AppendTo function is used instead of ~:= to avoid 

--	a bug in ATK styles code.

--	The "\}" which terminates the group is left on the front of CurrText.

--

function parseGroup(CurrStyle)

	marker c, t, func, OutText, TStart, StyleStack

	boolean pagePending := False

	boolean hadText := False

	integer depth := 0

	OutText := newbase()

	TStart := OutText

	StyleStack := ""

	CurrStyle := copy(CurrStyle)

	while CurrText /= ""  do

		c := anyof(CurrText, "\{\}\\n\\r\\\\")

		t := extent(CurrText, start(c))

		if t /= "" then

			OutText := AppendTo(OutText, t, pagePending, hadText)

			hadText := True

		end if

		CurrText := extent(finish(c), CurrText)

		if NewPage then

			PagePending := False

			NewPage := False

		end if

		if c = "\{" then

			-- OutText := AppendTo(OutText, parseGroup(CurrStyle))

			-- CurrText := rest(CurrText)	-- discard "\}"

			-- instead of explicitly recurring, we push

			-- (this avoids copying OutText)

			TStart := ApplyStyle(TStart, OutText, CurrStyle)

			depth := depth + 1

			StyleStack := CurrStyle ~ ";" ~ StyleStack

		elif c = "\}" then

			-- we are finished, at least at this level of nesting

			if depth <= 0 then

				CurrText := extent(c, CurrText) -- keep the "\}"

				exit while

			else 

				TStart := ApplyStyle(TStart, OutText, CurrStyle)

				-- pop

				depth := depth - 1

				c := search(StyleStack, ";")

				CurrStyle := copy(extent(StyleStack, start(c)))

				StyleStack := extent(finish(c), StyleStack)

			end if

		elif c = "\\\\" then

			func := PeelControl(c)

			-- printline(CurrCtl ~ ": " ~ func)

			if func = "s" then

				-- style change

				TStart := ApplyStyle(TStart, OutText, CurrStyle)

				CurrStyle := ModifyStyle(func, CurrStyle)

				-- printline("New style : " ~ CurrStyle)

			elif func = "r" then

				-- replace control with text

				OutText := AppendTo(OutText, extent(next(func), 

						start(search(finish(func), ","))), 

						pagePending, hadText)

			elif func = "p" then

				-- footnote (or pict)

				TStart := ApplyStyle(TStart, OutText, CurrStyle)

				OutText := AppendTo(OutText, 

							parseEmbeddedObject(func),

							pagePending, hadText)

				TStart := finish(OutText)

			elif func = "m" then

				-- \\'xx hex code to map. must unset font

				if search(CurrStyle, "f") /= "" then

					t := copy(CurrStyle)

					RemoveStyles(t, "f")

					TStart := ApplyStyle(TStart, OutText, CurrStyle)

					OutText := AppendTo(OutText, MapHex(), 

							pagePending, hadText)

					TStart := ApplyStyle(TStart, OutText, t)

				else

					OutText := AppendTo(OutText, MapHex(), 

							pagePending, hadText)

				end if

			elif func = "q" then

				-- major block or document format

				TStart := ApplyStyle(TStart, OutText, CurrStyle)

				t := parseDocumentControl(func)

				if first(t) = "\\f" then

					PagePending := True

					-- t := rest(t)  -- fails due to bug in styles

					replace(first(t), "")

				end if

				if first(t) = "\\n" and (last(OutText) = "\\n" 

								or OutText ="") then

					-- t := rest(t)  -- fails due to bug in styles

					replace(first(t), "")

				end if

				OutText := AppendTo(OutText, t, False, hadText)

				TStart := finish(OutText)

			else

				-- ignore other controls

			end if

		else	-- c = "\\n" or c = "\\r" then

			-- skip newline or carriage return

		end if

		if NewPage then

			PagePending := False

			NewPage := False

		end if

	end while

	ApplyStyle(TStart, OutText, CurrStyle)

	return base(OutText)

end function 


---------------------------------------------

-- central conversion routine


-- convert(s)

--	Initialize global variables and parse the input by calling parsegroup.

--	ParseGroup ends leaving CurrText starting with the trailing "\}"

--	Convert continues processing if there is more CurrText and the

--	"\}" is not followed by a zero byte.

--	

function convert(s)

	marker t := newbase()

	-- init globals

	StyleSheet := newbase()

	FontTbl := newbase()

	CurrMap := ansimap

	DefinedHeader := False


	if first(s) = "\{" then s := rest(s) end if

	CurrText := s

	while CurrText /= "" and first(CurrText) /= "\\000" do

		t := AppendTo (t, parseGroup(""), False, True)

		CurrText := rest(CurrText)	-- skip "\}"

	end while

	return base(t)

end function



--------------------------------------------------

-- the following provide the four different methods of invoking conversion


-- this function can be called from other Ness scripts

function fromrtf_to_atk(t)

	return convert(t)

end function


-- this function can be called from the 'Ness:' prompt

function fromrtf_convert()

	marker s := currentselection(defaulttext)

	replace (s, convert(s))

end function


-- add an item to the menu for all "textview" objects

extend "view:textview"

on menu "RTF to ATK"

	marker s := currentselection(defaulttext)

	replace (s, convert(s))

end menu

end extend



-- this main function executes if this file is invoked with nessrun

function main(args)

	marker filename, outname, ext, m, text, outtext

	filename := token(args, Letters ~ "./_0123456789")

	ext := filename

	while ext  /= "" do

		m := anyof (ext, "./")

		if m = "" then exit while

		else ext := extent(next(m), ext)

		end if

	end while

	-- now ext is the extension if preceded by "."

	if ext = "" then

		printline("You must supply a filename as argument.")

		exit function

	elif previous(ext) = "." and ext /= "d" then

		outname := extent(filename, start(ext)) ~ "d"

	else

		outname := filename ~ ".d"

	end if

	text := readfile(filename)

	if text = "" then

		printline("empty input file: " ~ filename)

		exit function

	end if

	m := search(text, "\{\\\\rtf")

	if m = "" then

		printline("Input file does not contain \\"\{\\\\rtf\\"")

		exit function

	end if


	printline("fromrtf(" ~Version ~ "):  " ~ filename ~ " -> " ~ outname)

	outtext := convert(extent(m, text))

	if match(system("if test -f "~outname ~  ";"

			~ "then mv " ~ outname ~ " " ~ outname ~ ".BAK;"

			~ "echo moved;fi"), "moved") /= "" then

		printline("Moved old " ~ outname ~ " to " ~ outname ~ ".BAK")

	end if

	writefile(outname, outtext)

end function



-- 
\begindata{bp,537558784}
\enddata{bp,537558784}
\view{bpv,537558784,19,0,0}

-- Copyright 1992 Carnegie Mellon University and IBM.  All rights reserved.

\smaller{\smaller{-- $Disclaimer: 

-- Permission to use, copy, modify, and distribute this software and its 

-- documentation for any purpose is hereby granted without fee, 

-- provided that the above copyright notice appear in all copies and that 

-- both that copyright notice, this permission notice, and the following 

-- disclaimer appear in supporting documentation, and that the names of 

-- IBM, Carnegie Mellon University, and other copyright holders, not be 

-- used in advertising or publicity pertaining to distribution of the software 

-- without specific, written prior permission.

-- 

-- IBM, CARNEGIE MELLON UNIVERSITY, AND THE OTHER COPYRIGHT HOLDERS 

-- DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 

-- ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT 

-- SHALL IBM, CARNEGIE MELLON UNIVERSITY, OR ANY OTHER COPYRIGHT HOLDER 

-- BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY 

-- DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 

-- WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 

-- ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 

-- OF THIS SOFTWARE.

--  $

}}\enddata{text,538268692}
